Frida API使用(3)

66 篇文章 7 订阅
52 篇文章 5 订阅

在这里插入图片描述
这里对其中的一部分API进行了介绍,这篇文章继续介绍后面的内容。

通过这部分的介绍,可以发现通过Frida操纵内存、查看模块等信息是如此的简单。操作内存,最重要的自然就是打补丁了,邪恶的微笑。

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:

  • type: string specifying either function or variable
  • name: import name as a string
  • module: module name as a string
  • address: absolute address as a NativePointer
  • slot: memory location where the import is stored, as a NativePointer
 //枚举模块中所有中的所有导入表(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:

  • type: string specifying either function or variable
  • name: export name as a string
  • address: absolute address as a NativePointer
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。

  • isGlobal: boolean specifying whether symbol is globally visible
  • type: string specifying one of:
    • unknown
    • section
    • undefined (Mach-O)
    • absolute (Mach-O)
    • prebound-undefined (Mach-O)
    • indirect (Mach-O)
    • object (ELF)
    • function (ELF)
    • file (ELF)
    • common (ELF)
    • tls (ELF)
  • section: if present, is an object containing:
    • id: string containing section index, segment name (if applicable) and section name – same format as r2’s section IDs
    • protection: protection like in Process.enumerateRanges()
  • name: symbol name as a string
  • address: absolute address as a NativePointer
  • size: if present, a number specifying the symbol’s size in bytes
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.

  • pattern must be of the form “13 37 ?? ff” to match 0x13 followed by 0x37 followed by any byte followed by 0xff. For more advanced matching it is also possible to specify an r2-style mask. The mask is bitwise AND-ed against both the needle and the haystack. To specify the mask append a : character after the needle, followed by the mask using the same syntax. For example: “13 37 13 37 : 1f ff ff f1”. For convenience it is also possible to specify nibble-level wildcards, like “?3 37 13 ?7”, which gets translated into masks behind the scenes.

  • callbacks is an object with:

    • onMatch: function (address, size): called with address containing the address of the occurence as a NativePointer and size specifying the size as a number.

      This function may return the string stop to cancel the memory scanning early.

    • onError: function (reason): called with reason when there was a memory access error while scanning

    • onComplete: function (): called when the memory range has been fully scanned

本文选取的的是领跑娱乐.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.scanSync

Memory.scanSync(address, size, pattern): synchronous version of scan() that returns an array of objects containing the following properties:

  • address: absolute address as a NativePointer.
  • size: size in bytes
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
}));

在这里插入图片描述

写入内存Memory.writeByteArray

将字节数组写入一个指定内存,代码示例如下:

        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相关内容,欢迎关注我的公众号:无情剑客
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloworddm

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值