I'm using Frida to reverse-engineer an Android app that uses a library (libapp.so). I have a list of function names and their offsets, and I'm successfully hooking them
My goal is to log the return value of these native functions as a readable string.
Here’s my current script
Java.perform(function () {
var libapp = null;
const libName = "libapp.so";
const checkInterval = 200;
const maxWaitTime = 10000;
let waited = 0;
const waitForLibApp = setInterval(function () {
libapp = Module.findBaseAddress(libName);
if (libapp !== null || waited > maxWaitTime) {
clearInterval(waitForLibApp);
if (libapp === null) {
console.log("[-] libapp.so not found in memory.");
return;
}
console.log("[+] libapp.so loaded at", libapp);
hookTargetFunctions(libapp);
}
waited += checkInterval;
}, checkInterval);
function hookTargetFunctions(base) {
const functionList = [
{ name: "addData", offset: 0x795b4c },
{ name: "getData", offset: 0x795cbc },
];
functionList.forEach(func => {
try {
const addr = base.add(ptr(func.offset));
Interceptor.attach(addr, {
onEnter: function (args) {
console.log(`[+] Called ${func.name} @ ${addr}`);
},
onLeave: function (retval) {
// This is where I want to convert the return value to a readable string
}
});
} catch (err) {
console.error(`[-] Error hooking ${func.name}:`, err);
}
});
}
});
Your question does miss some details so I had to guess:
I assume the return value is pointer to a common null terminated string containing ASCII or UTF-8 characters. In Frida those strings are called "CString" and "Utf8String".
Interceptor.attach(addr, {
onEnter: function (args) {
console.log(`[+] Called ${func.name} @ ${addr}`);
},
onLeave: function (retval) {
let str = retval.readCString();
console.log(`returned string: ${str}`);
}
});
Depending on the string type to be read Frida has this functions:
readCString()
readUtf8String()
readUtf16String()
readAnsiString()
See also Frida documentation on NativePointer