From 1edd865dbc70301cd49f04c4bbf79e991be0ec3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20S=C3=B8rb=C3=B8?= Date: Fri, 5 Sep 2025 17:20:47 +0200 Subject: [PATCH 1/6] Allow for Runtime._instrumentation being pointer --- lib/android.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/android.js b/lib/android.js index 161de93..d598bef 100644 --- a/lib/android.js +++ b/lib/android.js @@ -464,6 +464,12 @@ function _getApi () { const instrumentationOffset = runtimeOffset.instrumentation; temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null; + // todo: figure out better detection of https://android.googlesource.com/platform/art/+/17c7ed2de734cf892b005b1d15b3db9855506f14 + const instrumentationIsPointer = apiLevel > 35; + if (instrumentationIsPointer) { + temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer(); + } + temporaryApi.artHeap = artRuntime.add(runtimeOffset.heap).readPointer(); temporaryApi.artThreadList = artRuntime.add(runtimeOffset.threadList).readPointer(); @@ -694,7 +700,12 @@ function _getArtRuntimeSpec (api) { throw new Error('Unable to determine Runtime field offsets'); } - spec.offset.instrumentation = tryDetectInstrumentationOffset(api); + // todo: figure out better detection of https://android.googlesource.com/platform/art/+/17c7ed2de734cf892b005b1d15b3db9855506f14 + const instrumentationIsPointer = apiLevel > 35; + spec.offset.instrumentation = instrumentationIsPointer + ? tryDetectInstrumentationPointer(api) + : tryDetectInstrumentationOffset(api); + spec.offset.jniIdsIndirection = tryDetectJniIdsIndirectionOffset(api); return spec; @@ -774,6 +785,57 @@ function parseArm64InstrumentationOffset (insn) { return offset; } +const instrumentationPointerParser = { + ia32: parsex86InstrumentationPointer, + x64: parsex86InstrumentationPointer, + arm: parseArmInstrumentationPointer, + arm64: parseArm64InstrumentationPointer +}; + +function tryDetectInstrumentationPointer (api) { + const impl = api['art::Runtime::DeoptimizeBootImage']; + if (impl === undefined) { + return null; + } + + return parseInstructionsAt(impl, instrumentationPointerParser[Process.arch], { limit: 30 }); +} + +function parsex86InstrumentationPointer (insn) { + return null; +} + +function parseArmInstrumentationPointer (insn) { + return null; +} + +function parseArm64InstrumentationPointer (insn) { + if (insn.mnemonic !== 'ldr') { + return null; + } + + const ops = insn.operands; + if (ops.length !== 2) { + return null; + } + + const dst = ops[0]; + if (dst.type !== 'reg' || dst.value === 'x0' || dst.value === 'sp') { + return null; + } + const isThisBase = (r) => r === 'x0' || r === 'x19'; + const mem = ops[1].value; + if (!mem || !isThisBase(mem.base)) { + return null; + } + + const off = (mem.disp ?? mem.offset ?? 0); + if (off < 0x100 || off > 0x400) { + return null; + } + return off; +} + const jniIdsIndirectionOffsetParsers = { ia32: parsex86JniIdsIndirectionOffset, x64: parsex86JniIdsIndirectionOffset, From 4f73e4ca610e06fc1f26adbb6d748545287c3d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20S=C3=B8rb=C3=B8?= Date: Fri, 5 Sep 2025 17:52:21 +0200 Subject: [PATCH 2/6] handle null --- lib/android.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/android.js b/lib/android.js index d598bef..9cb1add 100644 --- a/lib/android.js +++ b/lib/android.js @@ -466,7 +466,7 @@ function _getApi () { // todo: figure out better detection of https://android.googlesource.com/platform/art/+/17c7ed2de734cf892b005b1d15b3db9855506f14 const instrumentationIsPointer = apiLevel > 35; - if (instrumentationIsPointer) { + if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) { temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer(); } From 9a0397092eac0eb730b5b0433e6ea1e1c710419e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20S=C3=B8rb=C3=B8?= Date: Fri, 10 Oct 2025 13:48:26 +0200 Subject: [PATCH 3/6] Cleanups and simply pattern matching --- lib/android.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/android.js b/lib/android.js index 9cb1add..f3cbe29 100644 --- a/lib/android.js +++ b/lib/android.js @@ -464,8 +464,7 @@ function _getApi () { const instrumentationOffset = runtimeOffset.instrumentation; temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null; - // todo: figure out better detection of https://android.googlesource.com/platform/art/+/17c7ed2de734cf892b005b1d15b3db9855506f14 - const instrumentationIsPointer = apiLevel > 35; + const instrumentationIsPointer = getArtApexVersion() >= 36_000_000; if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) { temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer(); } @@ -815,25 +814,21 @@ function parseArm64InstrumentationPointer (insn) { } const ops = insn.operands; - if (ops.length !== 2) { - return null; - } - const dst = ops[0]; - if (dst.type !== 'reg' || dst.value === 'x0' || dst.value === 'sp') { + if (ops[0].value === 'x0') { return null; } - const isThisBase = (r) => r === 'x0' || r === 'x19'; + const mem = ops[1].value; - if (!mem || !isThisBase(mem.base)) { + if (mem.base !== 'x0') { return null; } - const off = (mem.disp ?? mem.offset ?? 0); - if (off < 0x100 || off > 0x400) { + const offset = mem.disp; + if (offset < 0x100 || offset > 0x400) { return null; } - return off; + return offset; } const jniIdsIndirectionOffsetParsers = { From bff3d51eb41a4713cd58aba64321064afa78fad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20S=C3=B8rb=C3=B8?= Date: Fri, 10 Oct 2025 14:35:30 +0200 Subject: [PATCH 4/6] android: fix duplicate instrumentationIsPointer --- lib/android.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/android.js b/lib/android.js index f3cbe29..97e5d48 100644 --- a/lib/android.js +++ b/lib/android.js @@ -699,8 +699,7 @@ function _getArtRuntimeSpec (api) { throw new Error('Unable to determine Runtime field offsets'); } - // todo: figure out better detection of https://android.googlesource.com/platform/art/+/17c7ed2de734cf892b005b1d15b3db9855506f14 - const instrumentationIsPointer = apiLevel > 35; + const instrumentationIsPointer = getArtApexVersion() >= 36_000_000; spec.offset.instrumentation = instrumentationIsPointer ? tryDetectInstrumentationPointer(api) : tryDetectInstrumentationOffset(api); From 4659a6d59fc22eb0799cf798e9f3e54499285122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20S=C3=B8rb=C3=B8?= Date: Fri, 10 Oct 2025 14:50:09 +0200 Subject: [PATCH 5/6] Correct version --- lib/android.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/android.js b/lib/android.js index 97e5d48..c4748cc 100644 --- a/lib/android.js +++ b/lib/android.js @@ -464,7 +464,7 @@ function _getApi () { const instrumentationOffset = runtimeOffset.instrumentation; temporaryApi.artInstrumentation = (instrumentationOffset !== null) ? artRuntime.add(instrumentationOffset) : null; - const instrumentationIsPointer = getArtApexVersion() >= 36_000_000; + const instrumentationIsPointer = getArtApexVersion() >= 360_000_000; if (instrumentationIsPointer && temporaryApi.artInstrumentation != null) { temporaryApi.artInstrumentation = temporaryApi.artInstrumentation.readPointer(); } @@ -699,7 +699,7 @@ function _getArtRuntimeSpec (api) { throw new Error('Unable to determine Runtime field offsets'); } - const instrumentationIsPointer = getArtApexVersion() >= 36_000_000; + const instrumentationIsPointer = getArtApexVersion() >= 360_000_000; spec.offset.instrumentation = instrumentationIsPointer ? tryDetectInstrumentationPointer(api) : tryDetectInstrumentationOffset(api); From 3e0bd976ef53cdaf8a322652bca138bc43b9e1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Sat, 11 Oct 2025 10:52:43 +0200 Subject: [PATCH 6/6] Wire up parsex86InstrumentationPointer for x86_64 --- lib/android.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/android.js b/lib/android.js index c4748cc..7b352dd 100644 --- a/lib/android.js +++ b/lib/android.js @@ -800,7 +800,32 @@ function tryDetectInstrumentationPointer (api) { } function parsex86InstrumentationPointer (insn) { - return null; + if (insn.mnemonic !== 'mov') { + return null; + } + + const ops = insn.operands; + + const dst = ops[0]; + if (dst.value !== 'rax') { + return null; + } + + const src = ops[1]; + if (src.type !== 'mem') { + return null; + } + + const mem = src.value; + if (mem.base !== 'rdi') { + return null; + } + + const offset = mem.disp; + if (offset < 0x100 || offset > 0x400) { + return null; + } + return offset; } function parseArmInstrumentationPointer (insn) {