Tip:
Before starting it is suggested to use the following typescript helper while writing frida scripts!!!
Pointer Arithmetics
NativePointer is a pointer type of frida. You can create NativePointer with `NativePointer("0x7fffabc0")` or short-hand`ptr("0x7fffabc0")`. Most of the time function arguments/return values will be pointer and you will be using NativePointer type.
You can add/sub/and/or/xor to pointer address :
You can read/write from/to NativePointer.There are several different functions to do that and you can combine them. Please check the docs for complete list meanwhile the most important ones:
Lets say you are playing with class of loginRequest and know the offsets of class members. If you got the instance of class, you can easily read structure:
Finding offset of function:
If your binary have function exports (cocos2d games) you can get function offsets by:
If your binary does not have function exports (unity games) you could get function offsets by:
Finding offset of function:
If your binary have function exports (cocos2d games) you can get function offsets by:
If your binary does not have function exports (unity games) you could get function offsets by:
Creating function
If you want to call function from library you need to create NativeFunction. First parameter is ptr to function address. Second paramater is return value type, third is array of types that function takes as argument.
If function is exported:
If function is not exported:
If you want to intercept function call and change/read/write to function arguments you will be using Interceptor.
Usefull snippets:
patch code:
If you want to change/read things after function returns use `this` to store onEnter and change on onLeave
Mem dump:
Backtrace with symbols:
Dump cpu context (registers):
Change CpuContext (to get arm registers):
Replace function:
Search memory:
Before starting it is suggested to use the following typescript helper while writing frida scripts!!!
Pointer Arithmetics
NativePointer is a pointer type of frida. You can create NativePointer with `NativePointer("0x7fffabc0")` or short-hand`ptr("0x7fffabc0")`. Most of the time function arguments/return values will be pointer and you will be using NativePointer type.
You can add/sub/and/or/xor to pointer address :
Code:
const libmb = ptr("0x7fffabc0")
let libmb_a = libmb.add(0x5) //0x7fffabc5
JavaScript:
//read
p.readByteArray(10), p.readPointer(), p.readInt(), p.readFloat(), p.readCString(), p.readAnsiString()
//write
p.writeInt(0x13), p.writeFloat(0.13), p.writeByteArray[0x13,0x37], p.writePointer(ptr("0x7fffabc0"))
JavaScript:
let loginReqStruct = args[0]
const loginReq = {
nameptr: loginReqStruct.add(0x11).readCString(),
uid: loginReqStruct.add(0x28).readInt(),
country: loginReqStruct.add(0x61).readCString(),
isguest: loginReqStruct.add(0x48).readCString(), // "1","0"
isfacebook: loginReqStruct.add(0x78).readByteArray(1),
secret: loginReqStruct.add(0x58).readPointer().readCString(),
devicetoken: loginReqStruct.add(0x98).readPointer().readCString()
console.log(JSON.stringify(loginReq))
};
If your binary have function exports (cocos2d games) you can get function offsets by:
JavaScript:
const tostyledstring = Module.getExportByName(libname,'_ZNK4Json5Value14toStyledStringEv')
JavaScript:
const libm = Process.getModuleByName("libil2cpp.so");
const libmb = libmodule.base;
const has_enough_chips = libmb.add(0x109474)
If your binary have function exports (cocos2d games) you can get function offsets by:
JavaScript:
const tostyledstring = Module.getExportByName(libname,'_ZNK4Json5Value14toStyledStringEv')
JavaScript:
const libm = Process.getModuleByName("libil2cpp.so");
const libmb = libmodule.base;
const has_enough_chips = libmb.add(0x109474)
If you want to call function from library you need to create NativeFunction. First parameter is ptr to function address. Second paramater is return value type, third is array of types that function takes as argument.
If function is exported:
JavaScript:
var login_serialize = NativeFunction(Module.findExportByName("libGameName.so",'_ZNK12LoginRequest9serializeERN4Json5ValueE'), 'int', ["pointer"]);
JavaScript:
var login_serialize = NativeFunction(libil2cppb.add(0x109474), 'int', ["pointer"]);
JavaScript:
let forceSkipFnc = new NativeFunction(libil2cppb.add(0x006A8490),['void'],['pointer'])
const MeetingHudUpdate = libil2cppb.add(0x006A7AF0);
Interceptor.attach(MeetingHudUpdate, {
onEnter: function (args) {
forceSkipFnc(args[0])
this.p = args[0]
args[0] = 1337
args[0] = ptr("0x7fffabc0")
},
onLeave: function (retval) {
retval.replace(1337)
retval.replace(ptr.add(0x30).readPointer())
},
});
patch code:
JavaScript:
Memory.patchCode(libil2cppb.add(0x6C5B98),8,function(code){
var armW = new Arm64Writer(code,{pc:libil2cppb.add(0x6C5B98)})
armW.putLdrRegAddress("x9",ptr("0x41414141"))
armW.putMovRegReg("x0","x20")
armW.putBlrReg("x9")
armW.flush()
})
JavaScript:
Interceptor.attach(MeetingHudUpdate, {
onEnter: function (args) {
this.p = args[0]
},
onLeave: function (retval) {
console.log(this.p.add(0x32).readInt())
},
});
JavaScript:
console.log(
hexdump(address, {
offset: 0,
length: 200,
header: true,
ansi: true,
})
);
JavaScript:
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
JavaScript:
console.log(JSON.stringify(this.context))
JavaScript:
let mycntx = <Arm64CpuContext>this.context
console.log(mycntx.x11)
JavaScript:
Interceptor.replace(ptr(0x400c55), new NativeCallback(function (p,p1,p2,p3,p4,p5,p6) {
console.log(JSON.stringify(this.context))
return 1
}, 'int', ['pointer','pointer','pointer','pointer','pointer','pointer','pointer']));
JavaScript:
var ranges = Process.enumerateRanges({protection: 'r--',coalesce:true});
var range;
console.log("start scanning")
function processNext(){
range = ranges.pop();
if(!range){
console.log("done.")
return;
}
Memory.scan(range.base, range.size, "66 72 69 65 6e 64 43 6f 75 6e 74", {
onMatch: function(address, size){
//console.log("module base ",address)
console.log('[+] Pattern found at: ' + address.toString());
console.log(hexdump(address, {
offset: 0,
length: 300,
header: true,
ansi: true
}));
},
onError: function(reason){
console.log('[!] err ',reason);
},
onComplete: function(){
processNext();
}
});
processNext();
}