Skip to content

Commit

Permalink
Start on 32-bit ARM support
Browse files Browse the repository at this point in the history
  • Loading branch information
oleavr committed Dec 12, 2024
1 parent da3c5df commit a70d8c1
Showing 1 changed file with 149 additions and 69 deletions.
218 changes: 149 additions & 69 deletions lib/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,16 +405,15 @@ function _getApi () {
if (procSelfCmdlineAddr !== null) {
procSelfCmdlineAddr = procSelfCmdlineAddr.add(1);

exp = findAdrpAddReferenceToString(
'libart.so',
'?0 ?? ff ?0 00 ?? ?? 91',
exp = findPcRelativeReferenceToString(
'libart.so', '?0 ?? ff ?0 00 ?? ?? 91', 0,
procSelfCmdlineAddr,
adrpAddAddr => {
for (let off = 0; off !== 40; off += 4) {
const dis = Instruction.parse(adrpAddAddr.sub(off));
const mnemonic = dis.mnemonic;
const insn = Instruction.parse(adrpAddAddr.sub(off));
const mnemonic = insn.mnemonic;
if (mnemonic === 'b' || mnemonic === 'bl') {
const branchAddr = ptr(dis.operands[0].value);
const branchAddr = ptr(insn.operands[0].value);
const nextDis = Instruction.parse(branchAddr);
if (nextDis.mnemonic === 'stp') {
return {
Expand Down Expand Up @@ -585,24 +584,33 @@ function tryGetEnvJvmti (vm, runtime) {

vm.perform(() => {
let ensurePluginLoadedAddr = Module.findExportByName('libart.so', '_ZN3art7Runtime18EnsurePluginLoadedEPKcPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE');
if (ensurePluginLoadedAddr === null && Process.arch === 'arm64') {
console.log('arch:', Process.arch, 'ensurePluginLoadedAddr:', ensurePluginLoadedAddr);
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);
if (libopenjdkjvmtiSoAddr !== null) {
ensurePluginLoadedAddr = findAdrpAddReferenceToString(
'libart.so',
'?1 ?? ff ?0 21 ?? ?? 91',
libopenjdkjvmtiSoAddr,
adrpAddAddr => {
for (let off = 0; ; off += 4) {
const dis = Instruction.parse(adrpAddAddr.add(off));
const mnemonic = dis.mnemonic;
if (mnemonic === 'b' || mnemonic === 'bl') {
return ptr(dis.operands[0].value);
if (Process.arch === 'arm64') {
ensurePluginLoadedAddr = findPcRelativeReferenceToString(
'libart.so', '?1 ?? ff ?0 21 ?? ?? 91', 0,
libopenjdkjvmtiSoAddr,
adrpAddAddr => {
for (let off = 0; ; off += 4) {
const insn = Instruction.parse(adrpAddAddr.add(off));
const mnemonic = insn.mnemonic;
if (mnemonic === 'b' || mnemonic === 'bl') {
return ptr(insn.operands[0].value);
}
}
}
}
);
);
} else {
ensurePluginLoadedAddr = findPcRelativeReferenceToString(
'libart.so', '49 0d f1 ?? 0a', -1,
libopenjdkjvmtiSoAddr,
match => scanForward(match.add.next, 4, insn => (insn.mnemonic === 'bl') ? ptr(insn.operands[0].value).or(1) : null)
);
}
console.log('ensurePluginLoadedAddr:', ensurePluginLoadedAddr?.sub(Module.getBaseAddress('libart.so')));
}
}
if (ensurePluginLoadedAddr === null) {
Expand Down Expand Up @@ -1945,19 +1953,18 @@ function instrumentArtMethodInvocationFromInterpreter () {
const invokingPercentSAddr = findStringInRodata('libart.so', invokingPercentSString);
if (invokingPercentSAddr !== null) {
const foundFuncs = [];
const doCallFuncAddrs = findAdrpAddReferenceToString(
'libart.so',
'?2 e? ff ?0 42 ?? ?? 91',
const doCallFuncAddrs = findPcRelativeReferenceToString(
'libart.so', '?2 e? ff ?0 42 ?? ?? 91', 0,
invokingPercentSAddr,
adrpAddAddr => {
for (let off = 0; ; off += 4) {
let dis = Instruction.parse(adrpAddAddr.sub(off));
if (dis.mnemonic === 'str') {
dis = Instruction.parse(dis.next);
if (dis.mnemonic === 'stp') {
dis = Instruction.parse(dis.next);
if (dis.mnemonic === 'stp') {
foundFuncs.push(dis.address.sub(8));
let insn = Instruction.parse(adrpAddAddr.sub(off));
if (insn.mnemonic === 'str') {
insn = Instruction.parse(insn.next);
if (insn.mnemonic === 'stp') {
insn = Instruction.parse(insn.next);
if (insn.mnemonic === 'stp') {
foundFuncs.push(insn.address.sub(8));
break;
}
}
Expand Down Expand Up @@ -2007,17 +2014,16 @@ function ensureArtKnowsHowToHandleReplacementMethods (vm) {
const copyingPhaseString = '43 6f 70 79 69 6e 67 50 68 61 73 65';
const copyingPhaseAddr = findStringInRodata('libart.so', copyingPhaseString);
if (copyingPhaseAddr !== null) {
copyingPhase = findAdrpAddReferenceToString(
'libart.so',
'?1 ?? ff ?0 21 ?? ?? 91',
copyingPhase = findPcRelativeReferenceToString(
'libart.so', '?1 ?? ff ?0 21 ?? ?? 91', 0,
copyingPhaseAddr,
adrpAddAddr => {
for (let off = 0; ; off += 4) {
let dis = Instruction.parse(adrpAddAddr.sub(off));
if (dis.mnemonic === 'sub') {
dis = Instruction.parse(dis.next);
if (dis.mnemonic === 'stp') {
return dis.address.sub(4);
let insn = Instruction.parse(adrpAddAddr.sub(off));
if (insn.mnemonic === 'sub') {
insn = Instruction.parse(insn.next);
if (insn.mnemonic === 'stp') {
return insn.address.sub(4);
}
}
}
Expand Down Expand Up @@ -4062,9 +4068,8 @@ function makeArtThreadStateTransitionImpl (vm, env, callback) {

if (jniFatalErrorCalledAddr !== null) {
const occurrences = [];
if (findAdrpAddReferenceToString(
'libart.so',
'?1 ?? ff ?0 21 ?? ?? 91',
if (findPcRelativeReferenceToString(
'libart.so', '?1 ?? ff ?0 21 ?? ?? 91', 0,
jniFatalErrorCalledAddr,
address => {
occurrences.push(address);
Expand Down Expand Up @@ -5282,57 +5287,132 @@ function findStringInRodata (modName, stringBytes) {
return matches[0].address;
}

function findAdrpAddReferenceToString (modName, pattern, stringAddr, callback) {
function findPcRelativeReferenceToString (modName, pattern, offset, stringAddr, predicate) {
const arch = Process.arch;

let firstMnemonic;
if (arch === 'arm64') {
firstMnemonic = 'adrp';
} else if (arch === 'arm') {
firstMnemonic = 'adr';
} else {
if (!arch.startsWith('arm')) {
return null;
}

const textSection = Module.enumerateSections(modName).find(s => s.name === '.text');
const matches = Memory.scanSync(textSection.address, textSection.size, pattern);

for (const match of Memory.scanSync(textSection.address, textSection.size, pattern)) {
let dis = Instruction.parse(match.address);
if (dis.mnemonic !== firstMnemonic) {
continue;
}
const baseVal = dis.operands[1].value;
if (arch === 'arm64') {
for (const match of matches) {
const candidate = match.address.add(offset);

dis = Instruction.parse(dis.next);
if (dis.mnemonic !== 'add') {
dis = Instruction.parse(dis.next);
if (dis.mnemonic !== 'add') {
const adrp = Instruction.parse(candidate);
if (adrp.mnemonic !== 'adrp') {
continue;
}
}
const adrpOps = adrp.operands;
const destReg = adrpOps[0].value;
const baseVal = adrpOps[1].value;

const addOp = dis.operands[2];
if (addOp.type !== 'imm') {
continue;
const offsetVal = scanForward(adrp.next, 2, insn => {
if (insn.mnemonic !== 'add') {
return null;
}

const addOps = insn.operands;
if (addOps[0].value !== destReg || addOps[1].value !== destReg) {
return null;
}

const immOp = addOps[2];
if (immOp.type !== 'imm') {
return null;
}

return immOp.value;
});
if (offsetVal === null) {
continue;
}

if (ptr(baseVal).add(offsetVal).equals(stringAddr)) {
const result = predicate(candidate);
if (result !== null) {
return result;
}
}
}
const offsetVal = addOp.value;
} else {
const insnAlignMask = ptr(3).not();

if (ptr(baseVal).add(offsetVal).equals(stringAddr)) {
const result = callback(match.address);
if (result !== null) {
return result;
for (const match of matches) {
const candidate = match.address.add(offset);

const ldr = Instruction.parse(candidate.or(1));
if (ldr.mnemonic !== 'ldr') {
continue;
}

const ldrOps = ldr.operands;
const ldrSrc = ldrOps[1];
if (ldrSrc.type !== 'mem') {
continue;
}
const ldrSrcVal = ldrSrc.value;
if (ldrSrcVal.base !== 'pc') {
continue;
}

const destReg = ldrOps[0].value;

const add = scanForward(ldr.next, 4, insn => {
if (insn.mnemonic !== 'add') {
return null;
}

const ops = insn.operands;
if (ops[0].value !== destReg) {
return null;
}

if (ops[1].value !== 'pc') {
return null;
}

return insn;
});
if (add === null) {
continue;
}

const baseVal = ldr.address.and(insnAlignMask).add(4 + ldrSrcVal.disp).readPointer();
const offsetVal = add.address.add(4);

if (baseVal.add(offsetVal).equals(stringAddr)) {
const result = predicate({ ldr, add });
if (result !== null) {
return result;
}
}
}
}

return null;
}

function scanForward (startAddress, limit, predicate) {
let cursor = startAddress;
for (let i = 0; i !== limit; i++) {
const insn = Instruction.parse(cursor);

const result = predicate(insn);
if (result !== null) { return result; }

cursor = insn.next;
}
return null;
}

function scanBackwardForSubStp (startAddress) {
for (let off = 0; ; off += 4) {
const dis = Instruction.parse(startAddress.sub(off));
if (dis.mnemonic === 'sub') {
const nextDis = Instruction.parse(dis.next);
const insn = Instruction.parse(startAddress.sub(off));
if (insn.mnemonic === 'sub') {
const nextDis = Instruction.parse(insn.next);
if (nextDis.mnemonic === 'stp') {
return nextDis.address.sub(4);
}
Expand Down

0 comments on commit a70d8c1

Please sign in to comment.