F在这里对其中的一部分API进行了介绍,这篇文章继续介绍后面的内容。
通过这部分的介绍,可以发现通过Frida操纵内存、查看模块等信息是如此的简单。操作内存,最重要的自然就是打补丁了,邪恶的微笑。
@[toc]
Module对象Module.load(path): loads the specified module from the filesystem path and returns a Module object. Throws an exception if the specified module cannot be loaded. 常用的API可以参考下面的代码,注释写的很清楚:
Process.EnumererateModules()Enumerates modules loaded right now, returning an array of Module objects.
//枚举当前加载的模块 var process_Obj_Module_Arr = Process.enumerateModules();for(var i = 0; i < process_Obj_Module_Arr.length; i ) { //包含"lib"字符串的 if(process_Obj_Module_Arr[i].path.indexOf("lib")!=-1) { console.log("模块名称:",process_Obj_Module_Arr[i].name); console.log("模块地址:",process_Obj_Module_Arr[i].base); console.log("大小:",process_Obj_Module_Arr[i].size); console.log("文件系统路径",process_Obj_Module_Arr[i].path); }}
enumerateImports(导入表)
Enumerates imports of module, returning an array of objects containing the following properties:
//枚举模块中所有中的所有导入表(Import)函数 function frida_Module_import() { Java.perform(function () { const hooks = Module.load('libc.so'); var Imports = hooks.enumerateImports(); for(var i = 0; i < Imports.length; i ) { //函数类型 console.log("type:",Imports[i].type); //函数名称 console.log("name:",Imports[i].name); //属于的模块 console.log("module:",Imports[i].module); //函数地址 console.log("address:",Imports[i].address); } });}setImmediate(frida_Module_import,0);
enumerateExports(导出表)
Enumerates exports of module, returning an array of objects containing the following properties:
var Exports = hooks.enumerateExports();for(var i = 0; i < Exports.length; i ) { //函数类型 console.log("type:",Exports[i].type); //函数名称 console.log("name:",Exports[i].name); //函数地址 console.log("address:",Exports[i].address); }
注:导出表和导入表后续文章会专门进行介绍。简单来说,导入表是这个库依赖的函数表,而导出表是这个库对外提供的函数表。
enumerateSymbols(符号表)Enumerates symbols of module, returning an array of objects containing the following properties。
function frida_Module_symbol() { Java.perform(function () { const hooks = Module.load('libc.so'); var Symbol = hooks.enumerateSymbols(); for(var i = 0; i < Symbol.length; i ) { console.log("isGlobal:",Symbol[i].isGlobal); console.log("type:",Symbol[i].type); console.log("section:",JSON.stringify(Symbol[i].section)); console.log("name:",Symbol[i].name); console.log("address:",Symbol[i].address); } });}setImmediate(frida_Module_symbol,0);
运行结果如下:
获取export的绝对地址返回so文件中Export函数库中函数名称为exportName函数的绝对地址。
Module.findExportByName(moduleName|null, exportName), Module.getExportByName(moduleName|null, exportName): returns the absolute address of the export named exportName in moduleName. If the module isn’t known you may pass null instead of its name, but this can be a costly search and should be avoided. In the event that no such module or export could be found, the find-prefixed function returns null whilst the get-prefixed function throws an exception.
function frida_Module_address() { Java.perform(function () { console.log("gets address of getExportByName :",Module.getExportByName('libc.so', 'gets')); console.log("gets address of findExportByName:",Module.findExportByName('libc.so', 'gets')); });}setImmediate(frida_Module_address,0);
运行结果:
Memory对象Memory的一些API通常是对内存处理,譬如Memory.copy()复制内存,又如writeByteArray写入字节到指定内存中。
Memory.scan其主要功能是搜索内存中以address地址开始,搜索长度为size,需要搜是条件是pattern,callbacks搜索之后的回调函数;此函数相当于搜索内存的功能。
Memory.scan(address, size, pattern, callbacks): scan memory for occurences of pattern in the memory range given by address and size.
本文选取的的是领跑娱乐.apk,为一个赌博类的APP,后续会专门分析这个app。
对apk的解包在这里进行了介绍,通过Radare2查看libgame.so这个库的函数信息,如下:
匹配规则对应的是opcode,下面的代码将pattern设置为"08 c6 8f e2 ?? ca 8c e2",正好匹配第一行和第二行的opcode。
var process_Obj_Module_Arr = Process.enumerateModules();for(var i = 0; i < process_Obj_Module_Arr.length; i ) { //包含"libgame"字符串的 if(process_Obj_Module_Arr[i].path.indexOf("libgame")!=-1) { console.log("模块名称:",process_Obj_Module_Arr[i].name); console.log("模块地址:",process_Obj_Module_Arr[i].base); console.log("大小:",process_Obj_Module_Arr[i].size); console.log("文件系统路径",process_Obj_Module_Arr[i].path); // Print its properties: console.log(JSON.stringify(process_Obj_Module_Arr[i])); // Dump it from its base address: console.log(hexdump(process_Obj_Module_Arr[i].base)); // The pattern that you are interested in: var pattern = '08 c6 8f e2 ?? ca 8c e2'; Memory.scan(process_Obj_Module_Arr[i].base, process_Obj_Module_Arr[i].size, pattern, { onMatch: function (address, size) { console.log('Memory.scan() found match at', address, 'with size', size); // Optionally stop scanning early: return 'stop'; }, onComplete: function () { console.log('Memory.scan() complete'); } }); } }
最终的运行结果:
很容易可以计算出偏移:0xc429f3bc - 0xc4041000 = 0x25e3bc
同步搜索内存数据Memory.scanSyncMemory.scanSync(address, size, pattern): synchronous version of scan() that returns an array of objects containing the following properties:
console.log(JSON.stringify(Memory.scanSync(process_Obj_Module_Arr[i].base,process_Obj_Module_Arr[i].size,pattern)));
如果符合条件的信息比较多,容易导致卡死,慎用。
内存分配Memory.alloc在目标进程中的堆上申请size大小的内存,并且会按照Process.pageSize对齐,返回一个NativePointer,并且申请的内存如果在JavaScript里面没有对这个内存的使用的时候会自动释放的。也就是说,如果你不想要这个内存被释放,你需要自己保存一份对这个内存块的引用。
Memory.alloc(size): allocate size bytes of memory on the heap, or, if size is a multiple of Process.pageSize, one or more raw memory pages managed by the OS. The returned value is a NativePointer and the underlying memory will be released when all JavaScript handles to it are gone. This means you need to keep a reference to it while the pointer is being used by code outside the JavaScript runtime.
function frida_Memory_Alloc() { Java.perform(function () { const r = Memory.alloc(10); console.log(hexdump(r, { offset: 0, length: 10, header: true, ansi: false })); });}setImmediate(frida_Memory_Alloc,0);
以上代码在目标进程中申请了10字节的空间
也可以使用: Memory.allocUtf8String(str) 分配utf字符串 Memory.allocUtf16String 分配utf16字符串 Memory.allocAnsiString 分配ansi字符串
内存复制Memory.copy类似与c语言中的memcpy
const r = Memory.alloc(10);//复制以module.base地址开始的10个字节 那肯定会是7F 45 4C 46...因为一个ELF文件的Magic属性如此。Memory.copy(r,process_Obj_Module_Arr[i].base,10);console.log(hexdump(r, { offset: 0, length: 10, header: true, ansi: false}));
将字节数组写入一个指定内存,代码示例如下:
var arr = [ 0x62, 0x20, 0x75,0x20, 0x72,0x20,0x6E,0x20,0x69,0x20,0x6E,0x20,0x67]; //申请一个新的内存空间 返回指针 大小是arr.length const r = Memory.alloc(arr.length); //将arr数组写入R地址中 Memory.writeByteArray(r,arr); //输出 console.log(hexdump(r, { offset: 0, length: arr.length, header: true, ansi: false }));
结果如下:
读取内存Memory.readByteArray将一个指定地址的数据,代码示例如下:
var buffer = Memory.readByteArray(r, arr.length); //输出 console.log("Memory.readByteArray:"); console.log(hexdump(buffer, { offset: 0, length: arr.length, header: true, ansi: false }));
结果同上。
公众号更多Frida相关内容,欢迎关注我的公众号:无情剑客
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved