Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Jan 7, 2025
1 parent 19a6ca7 commit 4fc6e7a
Showing 1 changed file with 50 additions and 78 deletions.
128 changes: 50 additions & 78 deletions lib/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ function getApi () {
}

function _getApi () {
const t1 = Date.now();
const vmModules = Process.enumerateModules()
.filter(m => /^lib(art|dvm).so$/.test(m.name))
.filter(m => !/\/system\/fake-libs/.test(m.path));
Expand All @@ -144,8 +145,7 @@ function _getApi () {
};

const pending = isArt
? [{
module: vmModule.path,
? {
functions: {
JNI_GetCreatedJavaVMs: ['JNI_GetCreatedJavaVMs', 'int', ['pointer', 'int', 'pointer']],

Expand Down Expand Up @@ -312,7 +312,7 @@ function _getApi () {
this.isDebuggerActive = () => !!address.readU8();
}
},
optionals: [
optionals: new Set([
'artInterpreterToCompiledCodeBridge',
'_ZN3art9JavaVMExt12AddGlobalRefEPNS_6ThreadENS_6ObjPtrINS_6mirror6ObjectEEE',
'_ZN3art9JavaVMExt12AddGlobalRefEPNS_6ThreadEPNS_6mirror6ObjectE',
Expand Down Expand Up @@ -360,10 +360,9 @@ function _getApi () {
'_ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID',
'_ZN3art11interpreter18GetNterpEntryPointEv',
'_ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi'
]
}]
: [{
module: vmModule.path,
])
}
: {
functions: {
_Z20dvmDecodeIndirectRefP6ThreadP8_jobject: ['dvmDecodeIndirectRef', 'pointer', ['pointer', 'pointer']],
_Z15dvmUseJNIBridgeP6MethodPv: ['dvmUseJNIBridge', 'void', ['pointer', 'pointer']],
Expand All @@ -380,77 +379,47 @@ function _getApi () {
this.gDvm = address;
}
}
}];
};

const {
functions = {},
variables = {},
optionals = new Set(),

Check failure on line 387 in lib/android.js

View workflow job for this annotation

GitHub Actions / eslint

Unexpected trailing comma
} = pending;

const missing = [];

pending.forEach(function (api) {
const functions = api.functions || {};
const variables = api.variables || {};
const optionals = new Set(api.optionals || []);

const exportByName = Module
.enumerateExports(api.module)
.reduce(function (result, exp) {
result[exp.name] = exp;
return result;
}, {});

Object.keys(functions)
.forEach(function (name) {
let exp = exportByName[name];
if (exp === undefined && name === '_ZN3art7Monitor17TranslateLocationEPNS_9ArtMethodEjPPKcPi' && Process.arch === 'arm64') {
const procSelfCmdlineString = '00 2f 70 72 6f 63 2f 73 65 6c 66 2f 63 6d 64 6c 69 6e 65';
let procSelfCmdlineAddr = findStringInRodata('libart.so', procSelfCmdlineString);
if (procSelfCmdlineAddr !== null) {
procSelfCmdlineAddr = procSelfCmdlineAddr.add(1);

exp = findPcRelativeReferenceToString('libart.so', '?0 ?? ff ?0 00 ?? ?? 91', 0, procSelfCmdlineAddr,
match => scanBackward(match.first.address.sub(4), 10, insn => {
const mnemonic = insn.mnemonic;
if (mnemonic === 'b' || mnemonic === 'bl') {
const branchAddr = ptr(insn.operands[0].value);
const targetInsn = Instruction.parse(branchAddr);
if (targetInsn.mnemonic === 'stp') {
return {
type: 'function',
name,
address: targetInsn.address
};
}
}
return null;
})
);
}
}
if (exp?.type === 'function') {
const signature = functions[name];
if (typeof signature === 'function') {
signature.call(temporaryApi, exp.address);
} else {
temporaryApi[signature[0]] = new NativeFunction(exp.address, signature[1], signature[2], nativeFunctionOptions);
}
} else {
if (!optionals.has(name)) {
missing.push(name);
}
}
});
for (const [name, signature] of Object.entries(functions)) {
let address = vmModule.findExportByName(name);
if (address === null) {
address = vmModule.findSymbolByName(name);
}
if (address !== null) {
if (typeof signature === 'function') {
signature.call(temporaryApi, address);
} else {
temporaryApi[signature[0]] = new NativeFunction(address, signature[1], signature[2], nativeFunctionOptions);
}
} else {
if (!optionals.has(name)) {
missing.push(name);
}
}
}

Object.keys(variables)
.forEach(function (name) {
const exp = exportByName[name];
if (exp !== undefined && exp.type === 'variable') {
const handler = variables[name];
handler.call(temporaryApi, exp.address);
} else {
if (!optionals.has(name)) {
missing.push(name);
}
}
});
});
for (const [name, handler] of Object.entries(variables)) {
let address = vmModule.findExportByName(name);
if (address === null) {
address = vmModule.findSymbolByName(name);
}
if (address !== null) {
handler.call(temporaryApi, address);
} else {
if (!optionals.has(name)) {
missing.push(name);
}
}
}

if (missing.length > 0) {
throw new Error('Java API only partially available; please file a bug. Missing: ' + missing.join(', '));
Expand Down Expand Up @@ -528,7 +497,7 @@ function _getApi () {
temporaryApi.artNterpEntryPoint = temporaryApi['art::interpreter::GetNterpEntryPoint']();
} else {
if (Process.arch === 'arm64' && getAndroidApiLevel() >= 30) {
const artMethodCopyfrom = Module.findExportByName('libart.so', '_ZN3art9ArtMethod8CopyFromEPS0_NS_11PointerSizeE');
const artMethodCopyfrom = vmModule.getExportByName('_ZN3art9ArtMethod8CopyFromEPS0_NS_11PointerSizeE');
for (let off = 0; off < 0x300; off += 4) {
const disasm = Instruction.parse(artMethodCopyfrom.add(off));
const nextInstr = Instruction.parse(artMethodCopyfrom.add(off).add(0x4));
Expand Down Expand Up @@ -560,7 +529,7 @@ function _getApi () {
});
}

const cxxImports = Module.enumerateImports(vmModule.path)
const cxxImports = vmModule.enumerateImports()
.filter(imp => imp.name.indexOf('_Z') === 0)
.reduce((result, imp) => {
result[imp.name] = imp.address;
Expand All @@ -571,6 +540,8 @@ function _getApi () {

MethodMangler = isArt ? ArtMethodMangler : DalvikMethodMangler;

const t2 = Date.now();
console.log(`getApi() took ${t2 - t1} ms`);
return temporaryApi;
}

Expand All @@ -579,6 +550,7 @@ function tryGetEnvJvmti (vm, runtime) {

vm.perform(() => {
let ensurePluginLoadedAddr = Module.findExportByName('libart.so', '_ZN3art7Runtime18EnsurePluginLoadedEPKcPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE');
console.log('doing that thing');
if (ensurePluginLoadedAddr === null) {
const libopenjdkjvmtiSoString = '6c 69 62 6f 70 65 6e 6a 64 6b 6a 76 6d 74 69 2e 73 6f';
const libopenjdkjvmtiSoAddr = findStringInRodata('libart.so', libopenjdkjvmtiSoString);
Expand Down Expand Up @@ -4040,9 +4012,9 @@ function makeArtThreadStateTransitionImpl (vm, env, callback) {
let exceptionClearImpl = envVtable.add(ENV_VTABLE_OFFSET_EXCEPTION_CLEAR).readPointer();
let nextFuncImpl = envVtable.add(ENV_VTABLE_OFFSET_FATAL_ERROR).readPointer();

const fatalErrorSymbol = Module.enumerateSymbols('libart.so').find(({ name, address }) => name.includes('art3JNI') &&
const fatalErrorSymbol = undefined; /*Module.enumerateSymbols('libart.so').find(({ name, address }) => name.includes('art3JNI') &&

Check failure on line 4015 in lib/android.js

View workflow job for this annotation

GitHub Actions / eslint

Expected exception block, space or tab after '/*' in comment

Check failure on line 4015 in lib/android.js

View workflow job for this annotation

GitHub Actions / eslint

Expected space or tab before '*/' in comment
name.includes('FatalError') &&
address.equals(nextFuncImpl));
address.equals(nextFuncImpl));*/
if (fatalErrorSymbol === undefined && Process.arch === 'arm64') {
const jniFatalErrorCalledString = '4a 4e 49 20 46 61 74 61 6c 45 72 72 6f 72 20 63 61 6c';
const jniFatalErrorCalledAddr = findStringInRodata('libart.so', jniFatalErrorCalledString);
Expand Down

0 comments on commit 4fc6e7a

Please sign in to comment.