安卓逆向-SO层相关HOOK

一、SO层相关

1. hook_so层

  • hook_so层只需要得到它的函数地址,有函数地址就能hook与主动调用,而得到函数地址的方式有两种;
1.1 方式一
  • 通过frida提供的api来得到,该函数必须有符号的才可以;
    • 有符号是指此函数是否出现在导出、导入、符号表里;
1.2 方式二
  • 通过计算得到地址:so基址+函数在so中的偏移[+1](32位+1)

2. 各种枚举

2.1 枚举导入表
  • 通过枚举导入表,可以得到出现在导入表中的函数地址;(enumerateImports
var imports = Module.enumerateImports("libifeng_secure.so");
// console.log(JSON.stringify(imports[0]))
for (var i = 0; i < imports.length; i++) {
    // if (imports[i].name == "atoi") {
    //     console.log(JSON.stringify(imports[i]));
    console.log('导入函数名--->>>',imports[i].name);
    console.log('导入函数地址--->>>',imports[i].address);
    console.log('-----------------------------------------------------------------')
    // break;
    // }
}

  • 以某so为例,得到的结果如下:

在这里插入图片描述

2.2 枚举导出表
  • 通过枚举导出表,可以得到出现在导出表中的函数地址,与导入表同理,api不同;(enumerateExports
var imports = Module.enumerateExports("libifeng_secure.so");
// console.log(JSON.stringify(imports[0]))
for (var i = 0; i < imports.length; i++) {
    // if (imports[i].name == "atoi") {
    //     console.log(JSON.stringify(imports[i]));
    console.log('导出函数名--->>>',imports[i].name);
    console.log('导出函数地址--->>>',imports[i].address);
    console.log('-----------------------------------------------------------------')
    // break;
    // }
}
  • 以某so为例结果如下:

在这里插入图片描述

2.3 枚举符号表
  • 通过枚举符号表,可以得到出现在符号表中的函数地址;
var symbols = Module.enumerateSymbols("libifeng_secure.so");
// console.log(JSON.stringify(symbols[0]))

for (var i = 0; i < symbols.length; i++) {
    console.log('符号表函数名--->>>',symbols[i].name);
    console.log('符号表函数地址--->>>',symbols[i].address);
    console.log('-----------------------------------------------------------------')
}
2.4 枚举模块
  • 通过枚举模块,再枚举模块里面的导出表,可以快速找到某个导入函数出自哪个so;
// 枚举进程中已加载的模块
var modules = Process.enumerateModules();
var module = modules[0].enumerateExports()
for(let i = 0; i < module.length; i++){
    console.log('枚举进程函数名--->>>',module[i].name);
    console.log('枚举进程函数地址--->>>',module[i].address);
    console.log('-----------------------------------------------------------------')
}
// console.log(JSON.stringify(modules[0].enumerateExports()));
  • 通过枚举模块得到的是一个数组,取第一个后就可以调用上述三个方法;

在这里插入图片描述

3. hook导出函数

  • 在so导出表里的函数,可以通过frida提供的api来获取函数地址,Module.findExportByName(“xxxx.so”, “add”),函数名以汇编中出现的为准;
// 导出函数的hook
var funcAddr = Module.findExportByName("libencryptlib.so", "_ZN7MD5_CTX11MakePassMD5EPhjS0_");
console.log('函数地址--->>>',funcAddr);
Interceptor.attach(funcAddr, {
    onEnter: function (args) {
        console.log("funcAddr onEnter args[1]: ", hexdump(args[1]));
        console.log("funcAddr onEnter args[2]: ", args[2].toInt32());
        this.args3 = args[3];
    }, onLeave: function (retval) {
        console.log("funcAddr onLeave args[3]: ", hexdump(this.args3));
    }
});
  • 在这里以口袋48为例:

在这里插入图片描述

  • 在这里我们的前置条件是,传了三个参数,这里初始打印第三个参数时,发现结果全是0,这里大概就是一个缓冲区,这里是因为C语言里,非常喜欢将参数当作返回值使用,那么这里我们就需要在离开的时候再读取内存;
this.args3 = args[3];
console.log("funcAddr onLeave args[3]: ", hexdump(this.args3));

在这里插入图片描述

  • 在这里我们知道它是MD5,我们对比一下结果;

在这里插入图片描述

  • 可以发现与hook到的结果是一致的;

4. 获取模块基址

  • 在此的前提是,我们需要的函数不在三个表里,我们就没办法直接使用frida提供的api来获取函数地址,在此需要计算它的函数地址;
  • 计算公式如下:
so基址+函数在so中的偏移[+1] 32位则 +1
  • 因此,我们需要先得到so基址,也就是模块基址;
4.1 findModuleByName
  • 使用findModuleByName时,指明so文件即可,得到的是一个module对象,可以进行转换,也可以直接.base取地址;
var module1 = Process.findModuleByName("libencryptlib.so");
console.log("module1对象--->>>",JSON.stringify(module1));
console.log("module1基址--->>>", module1.base);
  • 直接.base取的就是基址;

在这里插入图片描述

4.2 getModuleByName
  • 与findModuleByName类似,得到的也是一个对象;
var module2 = Process.getModuleByName("libencryptlib.so");
console.log("module2对象--->>>",JSON.stringify(module2));
console.log("module2基址--->>>", module2.base);
  • 结果如下:

在这里插入图片描述

4.3 findBaseAddress(推荐)
  • 与前两个有所不同,这里得到的直接就是函数地址,也就是基址;
var soAddr = Module.findBaseAddress("libencryptlib.so");
console.log("soAddr基址--->>>", soAddr);
  • 这里就无需再去操作,返回值就是地址;

在这里插入图片描述

4.4 enumerateModules
  • 通过枚举所有模块,再判断是否与我们需要的模块一样,如果一致则输出地址等;
var modules = Process.enumerateModules();
for(let i = 0; i < modules.length; i++){
    if(modules[i].name == "libencryptlib.so"){
        console.log(modules[i].name + " " + modules[i].base);
    }
}
  • 不过此方式用的较少;

  • 也可以通过地址找模块,这也就可以调用一些方法;

var module = Process.findModuleByAddress(Module.findBaseAddress("libencryptlib.so"));
console.log("module " + module.name + " " + module.base);

5. 函数地址计算

5.1 偏移
  • 上述描述可知,函数地址计算如下:
so基址+函数在so中的偏移[+1]  [ 32位则 +1]
  • 基址我们已经能够获取到了,那就剩下偏移;
  • 以口袋48app为例,这里我们需要找某函数的偏移;

在这里插入图片描述

  • 在其定义位置按下tab,则可转到汇编,界面如下:

在这里插入图片描述

  • 实际上这就是它的偏移,它是相对so基址的偏移;得到这个偏移就可以计算出函数地址了;
  • 在这里是否+1呢,在目前来说,大部分是64位的so,此时则不需要加,若为32位则需要加;
5.2 地址计算
  • 依据公式,首先得到基址,再加上偏移;
var soAddr = Module.findBaseAddress("libencryptlib.so");
console.log(ptr(soAddr).add(0xxx));
  • soAddr得到是基址,其实也就是指针,在这里通过add (sub方法为减) 加上偏移,ptr实际上就是指针,也可以不加ptr;

在这里插入图片描述

  • 而add里面是一个数值,不是字符串,这里是十六进制,则需要加上0x;
  • 何时加ptr呢,若你的soAddr为具体的数值,则需要加,如:
var soAddr = Module.findBaseAddress("libencryptlib.so");
var so = 0x72777a6000;
console.log("soAddr基址--->>>" + soAddr);
console.log(ptr(so).add(0x1FA38)); // new NativePointer() == ptr()
  • 在一个具体的数值add时,由于不是指针,则无法调用add方法,加上ptr即可,也是同样可以得到地址的;

6. hook任意函数

  • 根据上述条件,我们已经可以hook任意的函数了,得到一个地址即可;
var soAddr = Module.findBaseAddress("libencryptlib.so");
// var so = 0x72777a6000;
console.log("soAddr基址--->>>" + soAddr);
// console.log(ptr(so).add(0x1FA38)); // new NativePointer()
var funcAddr = soAddr.add(0x1FA38);
console.log("funcAddr函数地址--->>>" + funcAddr);
Interceptor.attach(funcAddr, {
    onEnter: function (args) {
        console.log("funcAddr onEnter args[1]: ", hexdump(args[1]));
        console.log("funcAddr onEnter args[2]: ", args[2].toInt32());
        this.args3 = args[3];
    }, onLeave: function (retval) {
        console.log("funcAddr onLeave args[3]: ", hexdump(this.args3));
    }
});
  • 其余就与hook导出函数是类似的;
  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值