标题: Frida 脚本示例:基础篇 分类: 逆向 创建: 2022-11-23 23:39 修改: 链接: http://0x2531.tech/reverse/202211232339.txt -------------------------------------------------------------------------------- 在 Frida 中,JavaScript 脚本调用 gumjs 暴露出的 JavaScript API,实现 hook 函数、枚举已 加载的库及其导入导出函数、读写内存和以特定模式搜索内存等功能。下面分别介绍实现这些功能所使用的脚 本: 1. hook 函数 以 Android 平台举例,包括 Java 和 C/C++ 两层。无论是 Java 的类方法还是原生的 C/C++ 函数, 都可以 hook。 a) hook Java ========== setImmediate(function() { Java.perform(function() { var random = Java.use("java.util.Random"); // int nextInt() random.nextInt.overload().implementation = function () { var intVal = this.nextInt(); console.log("[*] Random.nextInt called: " + intVal + "\n"); return intVal; }; }; }); ========== b) hook C/C++ ========== setTimeout(function() { Java.perform(function() { // Low-level intercept and backtrace example Interceptor.attach(Module.findExportByName("libc.so", "open"), { onEnter: function(args) { console.warn("\n*** entered open"); var filename = Memory.readCString(ptr(args[0])); console.log("\nfile name: " + filename); // print backtrace console.log("\nBacktrace:\n" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n")); }, onLeave: function(retval) { // print retval console.log("\nretval: " + retval); console.warn("\n*** exiting open"); } }); }); }, 1000); ========== 2. 枚举已加载的库及其导入导出函数 a) 枚举已加载的库 ========== Process.enumerateModules({ onMatch: function(module){ console.log('Name: ' + module.name + " - " + 'Path: ' + module.path + " - " + "Base Address: " + module.base.toString()); }, onComplete: function(){} }); ========== b) 枚举库导出函数 即库提供的 API ========== Module.enumerateExports("libart.so", { onMatch: function(exp){ console.log('Type: ' + exp.type + ' - Name: ' + exp.name + ' - Address: ' + exp.address.toString()); }, onComplete: function(){} }); ========== c) 枚举库导入函数 即库使用的其它库的 API ========== Module.enumerateImports("libfrida-agent.so", { onMatch: function(imp){ console.log('Type: ' + imp.type + ' - Name: ' + imp.name + ' - Module: ' + imp.module + ' - Address: ' + imp.address.toString()); }, onComplete: function(){} }); ========== 3. 读写内存 当然,成功读写内存的前提是具有读写内存的权限。 a) 读内存 ========== var buf = Memory.readByteArray(ptr('0x%x'), %d); console.log(hexdump(buf, { offset: 0, length: %d, header: true, ansi: false })); ========== 其中,%x 为读取内存起始地址(十六进制表示)、%d 为读取内存大小。 b) 写内存 ========== Memory.writeByteArray(ptr('0x%x'), %s); ========== 其中,%x 为写入内存起始地址(十六进制表示)、%s 为写入内容,格式形如 "0x29,0x2a,0x2b,0x2c" ,对应 ASCII 字符表示则为 ")*+,"。 4. 内存搜索 ========== var ranges = Process.enumerateRangesSync({protection: 'r--', coalesce: true}); var range; function processNext(){ range = ranges.pop(); if(!range){ // we are done return; } // due to the lack of blacklisting in Frida, there will be // always an extra match of the given pattern (if found) because // the search is done also in the memory owned by Frida. Memory.scan(range.base, range.size, '%s', { onMatch: function(address, size){ console.log('[+] Pattern found at: ' + address.toString()); }, onError: function(reason){ console.log('[!] There was an error scanning memory'); }, onComplete: function(){ processNext(); } }); } processNext(); ========== 其中,%s 为搜索内容模式,格式形如 "13 37 ?? ff",?? 匹配任意一个字节(00~ff)。 参考资料: https://github.com/poxyran/misc https://github.com/0xdea/frida-scripts