Skip to content

Instantly share code, notes, and snippets.

@Ahmeth4n
Created March 2, 2025 20:44
Show Gist options
  • Save Ahmeth4n/8b0a21228fc2437864bb58b9402180ad to your computer and use it in GitHub Desktop.
Save Ahmeth4n/8b0a21228fc2437864bb58b9402180ad to your computer and use it in GitHub Desktop.
simple PairIP executeVM() analyzer frida script.
function hookNative() {
const jniOnLoad = moduleHandle.findExportByName("JNI_OnLoad");
if (!jniOnLoad) {
console.log("[-] JNI_OnLoad not found!");
return;
}
console.log("[+] JNI_OnLoad founded:", jniOnLoad);
var hook3 = Interceptor.attach(jniOnLoad, {
onEnter: function(args) {
console.log("[+] JNI_OnLoad called");
console.log("JavaVM pointer:", args[0]);
console.log("reserved:", args[1]);
console.log("Backtrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join("\n"));
startStalker(this.threadId, Process.getModuleByName('libpairipcore.so'));
},
onLeave: function(retval) {
console.log("[+] JNI_OnLoad return value:", retval);
stopStalker(this.threadId);
hook3.detach();
}
});
const moduleHandle = Process.findModuleByName('libpairipcore.so');
if (!moduleHandle) {
console.log("[-] libpairipcore.so not found!");
return;
}
const registerNativesOffset = moduleHandle.base.add(0x6a3b4);
Interceptor.attach(registerNativesOffset, {
onEnter: function(args) {
console.log("[+] RegisterNatives called");
console.log(" JNIEnv*:", this.context.x0);
console.log(" jclass:", this.context.x1);
console.log(" JNINativeMethod*:", this.context.x2);
console.log(" nMethods:", this.context.x3);
const nMethods = this.context.x3.toInt32();
const methods = this.context.x2;
for(let i = 0; i < nMethods; i++) {
const methodInfo = methods.add(i * Process.pointerSize * 3);
const name = methodInfo.readPointer().readCString();
const sig = methodInfo.add(Process.pointerSize).readPointer().readCString();
const fnPtr = methodInfo.add(Process.pointerSize * 2).readPointer();
const ghidraOffset = ptr(fnPtr).sub(moduleHandle.base).add(0x00100000);
console.log(` Method[${i}]:`);
console.log(` name: ${name}`);
console.log(` signature: ${sig}`);
console.log(` fnPtr: ${fnPtr}`);
console.log(` ghidraOffset: ${ghidraOffset}`);
console.log(` Ghidra offset: 0x${ghidraOffset.toString(16)}`);
console.log(`[+] ${name} function's memory dump:`);
const dumpSize = 128;
const dumpData = Memory.readByteArray(fnPtr, dumpSize);
console.log(hexdump(dumpData, {
offset: 0,
length: dumpSize,
header: true,
ansi: false
}));
}
},
onLeave: function(retval) {
console.log("[+] RegisterNatives finished, return value is:", retval);
}
});
}
function startStalker(threadId, targetModule){
Stalker.follow(threadId, {
transform: function(iterator){
var instruction;
while((instruction = iterator.next()) != null){
if(instruction.address <= targetModule.base.add(targetModule.size) &&
instruction.address >= targetModule.base){
var offset = instruction.address.sub(targetModule.base);
console.log(`[+] ${offset}: ${instruction.toString()}`);
if (instruction.mnemonic.startsWith('bl') || instruction.mnemonic.startsWith('b.')) {
iterator.putCallout(function(context) {
console.log(` x8=${context.x8.toString(16)}`);
console.log(` x0=${context.x0.toString(16)}`);
var moduleDetails = Process.findModuleByAddress(context.x8);
if (moduleDetails) {
console.log(` Module: ${moduleDetails.name}`);
console.log(` Base: ${moduleDetails.base}`);
console.log(` Offset in module: 0x${context.x8.sub(moduleDetails.base).toString(16)}`);
var symbol = DebugSymbol.fromAddress(context.x8);
if (symbol && symbol.name && symbol.name.indexOf("0x") == -1) {
console.log(` Symbol: ${symbol.name}`);
}
}
});
}
}
iterator.keep();
}
}
});
}
function stopStalker(threadId){
Stalker.unfollow(threadId);
Stalker.flush();
}
var libnative_loaded = 0;
var do_dlopen = null;
var call_ctor = null;
Process.findModuleByName('linker64').enumerateSymbols().forEach(function (sym) {
if (sym.name.indexOf('do_dlopen') >= 0) {
do_dlopen = sym.address;
} else if (sym.name.indexOf('call_constructor') >= 0) {
call_ctor = sym.address;
}
});
Interceptor.attach(do_dlopen, function () {
var libraryPath = this.context.x0.readCString();
if (libraryPath.indexOf('libpairipcore.so') > -1) {
console.log(`libpairipcore.so loaded.`);
Interceptor.attach(call_ctor, function () {
if (libnative_loaded == 0) {
var native_mod = Process.findModuleByName('libpairipcore.so');
console.warn(`[+] libpairipcore.so loaded @${native_mod.base}`);
hookNative();
}
libnative_loaded = 1;
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment