Frida0B - native hook

各位读者你们好啊,今天一起讨论下hook so 中的函数的相关 api。

函数Hook

Native hook 主要使用的 api 是 interceptor:

https://frida.re/docs/javascript-api/#interceptor

可以通过符号来hook:

Interceptor.attach(Module.getExportByName('libc.so', 'read'), {
  onEnter(args) {
    this.fileDescriptor = args[0].toInt32();
  },
  onLeave(retval) {
    if (retval.toInt32() > 0) {
      /* do something with this.fileDescriptor */
    }
  }
});

也可以通过地址偏移来hook:

var nativelibmodule = Process.getModuleByName("libnative-lib.so");
var subf0ac = nativelibmodule.base.add(0xf0ac);
Interceptor.attach(subf0ac, {
    onEnter: function (args) {
        console.log("secret key: ", hexdump(args[1]), '\n length:', args[2]);
    }, onLeave: function () {
    }
});

拿到了函数地址后,甚至还可以直接调用该函数:

var offset = 0xF658;
var module = Process.getModuleByName("libnative-lib.so");
var sub_address = module.base.add(offset);

var arg1_address = Memory.alloc(10);
let arg2_address = Memory.alloc(10);
arg1_address.writeUtf8String(arg1);
arg2_address.writeUtf8String(arg2);

var hooked_sub_f658 = new NativeFunction(sub_address, 'pointer', ['pointer', 'pointer']);
hooked_sub_f658(arg1_address, arg2_address);

NativeFunction

https://frida.re/docs/javascript-api/#nativefunction

NativeFunction可以描述一个Native函数,与Java函数的签名是一样的,参数为:

  • 函数地址

  • 返回值类型

  • 参数类型列表

支持的类型有:

void
pointer
int
uint
long
ulong
char
uchar
size_t
ssize_t
float
double
int8
uint8
int16
uint16
int32
uint32
int64
uint64
bool

其中,pointer 类型是指针类型,它使用 NativePointer 来描述。

NativePointer

https://frida.re/docs/javascript-api/#nativepointer

比如,当我们需要打印 jstring类型的参数,javascript 是没有这个类型的,就需要先做一些转换:

Java.vm.getEnv().getStringUtfChars(argxxx, null).readCString()

上面的代码中,Java.vm.getEnv().getStringUtfChars(argxxx, null) 返回的就是一个 NativePointer 类型:

https://github.com/frida/frida-java-bridge/blob/main/lib/env.js

Env.prototype.getStringUtfChars = proxy(169, 'pointer', ['pointer', 'pointer', 'pointer'], function (impl, str) {
  return impl(this.handle, str, NULL);
});

function proxy (offset, retType, argTypes, wrapper) {
  let impl = null;
  return function () {
    if (impl === null) {
      impl = new NativeFunction(vtable(this).add(offset * pointerSize).readPointer(), retType, argTypes, nativeFunctionOptions);
    }
    let args = [impl];
    args = args.concat.apply(args, arguments);
    return wrapper.apply(this, args);
  };
}

frida 针对 NativePointer提供了很多的 api,具体可看文档,其中就有 readCString

替换返回值与参数

frida 文档里面说了,retval 是一个 NativePointer 的衍生对象,包含了原始的值,直接使用 replace 方法即可替换返回值:

  • You may call retval.replace(1337) to replace the return value with the integer 1337,

  • or retval.replace(ptr("0x1234")) to replace with a pointer.

举个例子,比如我想替换字符串,可以使用 JNI 中的任意函数达成目标,如果你熟悉 JNI 开发就最好不过了:

onLeave:function(retval) {

 var newRetval = Java.vm.getEnv().newStringUtf("nice to meet you");
 retval.replace(newRetval);

}

onEnter(args) 里面的 args 是一个 NativePointer类型的数组(这里感觉有点奇怪,一个 int 参数也是 NativePointer 类型???),想要替换参数,直接构建一个新参数替换即可:

onEnter:function(args) {

 var args2 = Java.vm.getEnv().newStringUtf("nice to meet you");
 args[2] = args2;

}

替换方法

使用 Interceptor.replace 来实现,工作模式与 inline hook 很相似,方法参数:

  • 地址

  • 替换后的实现

  • 返回值类型

  • 参数类型列表

const openPtr = Module.getExportByName('libc.so', 'open');
const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
Interceptor.replace(openPtr, new NativeCallback((pathPtr, flags) => {
  const path = pathPtr.readUtf8String();
  log('Opening "' + path + '"');
  // 调用了原来的方法
  const fd = open(pathPtr, flags);
  log('Got fd: ' + fd);
  return fd;
}, 'int', ['pointer', 'int']));

查看so中的导出函数

使用 Module 的 enumerateExports 函数即可。

二手的程序员

欢迎关注二手的程序员,这里主要分享逆向相关的知识。专注于完整系列,让知识不再碎片化。不定时更新,也欢迎关注我的博客:lyldalek.top

公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二手的程序员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值