From 4fc6e7a44533a9c5accba7adca6bcdd20062f305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Tue, 7 Jan 2025 12:06:07 +0100 Subject: [PATCH] WIP --- lib/android.js | 128 +++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 78 deletions(-) diff --git a/lib/android.js b/lib/android.js index 849ee642..6be8c2ea 100644 --- a/lib/android.js +++ b/lib/android.js @@ -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)); @@ -144,8 +145,7 @@ function _getApi () { }; const pending = isArt - ? [{ - module: vmModule.path, + ? { functions: { JNI_GetCreatedJavaVMs: ['JNI_GetCreatedJavaVMs', 'int', ['pointer', 'int', 'pointer']], @@ -312,7 +312,7 @@ function _getApi () { this.isDebuggerActive = () => !!address.readU8(); } }, - optionals: [ + optionals: new Set([ 'artInterpreterToCompiledCodeBridge', '_ZN3art9JavaVMExt12AddGlobalRefEPNS_6ThreadENS_6ObjPtrINS_6mirror6ObjectEEE', '_ZN3art9JavaVMExt12AddGlobalRefEPNS_6ThreadEPNS_6mirror6ObjectE', @@ -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']], @@ -380,77 +379,47 @@ function _getApi () { this.gDvm = address; } } - }]; + }; + + const { + functions = {}, + variables = {}, + optionals = new Set(), + } = 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(', ')); @@ -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)); @@ -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; @@ -571,6 +540,8 @@ function _getApi () { MethodMangler = isArt ? ArtMethodMangler : DalvikMethodMangler; + const t2 = Date.now(); + console.log(`getApi() took ${t2 - t1} ms`); return temporaryApi; } @@ -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); @@ -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') && 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);