NDK Hook

前言

本文将在前文的基础上,利用 frida 对第一个 NDK 程序进行原生函数的 hook 。前面实现了一个简单计算器功能的 NDK 程序,本文将对其中的加法进行 hook 使之无法计算出正确结果。

为了客观公正,我们需要忘记自己是如何编写的这个程序。只能知道,这个程序有一个使用 native 实现的加法,我们需要去 hook 它。对了,生成的链接库的名字我们也得知道。

本文用到的 APK 来自于前文中编写的 APK,可以从这里直接下载。NDK_TEST.apk

IDA 分析

既然知道是要进行 native 层的 Hook 了,那就将 apk 文件直接用压缩软件解压,然后在 NDK_TEST/lib/x86 下找到文件 libcalc.so (因为前文中设置的名字就是 calc)。

然后打开 ida32 (别问我为啥要用 32 位的,问就是用 ida64 它让我用 ida32 的) ,将上述的 libcalc.so 直接拖进 ida 中。

然后打开 Exports 面板,查看有哪些函数。

IDA 查看导出函数表

嗯,函数有点多,一个一个找不现实。但是我们知道我们要找的函数是给 Java 用的,应该和这个关键字有关系,于是我们 Ctrl+F 搜索一些关键字 “Java” 。果然搜到了所有想要的函数。

搜索关键字过滤

这里我们选择加法,没有为啥,就是随便选了一个,其他的都是同理的。

然后我们双击我们想要查看的函数,这里我就想看加法 Java_com_example_ndk_1test_MainActivity_add ,双击进去,已经看到了我们的 log TAG 信息.

定位关键函数

这个看着不舒服,我们来看看 C 代码,按一下 F5 ,我们就查看反编译的 C 代码。

切换反编译C代码

这个代码看起来就很舒服了,第 4 行就是我们函数对加法的返回值,那我们就决定修改它了。

虽然我们早就知道这个源码是啥样,但是我们必须假装不知道。所以“多此一举”来看源码。

frida hook

有了上述的分析,我们只需要 hookJava_com_example_ndk_1test_MainActivity_add 方法的返回值就好了。

那么就不废话了,直接上代码。

loader.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import frida
import time


def my_message_handler(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)


device = frida.get_device_manager().add_remote_device("127.0.0.1:27042")
pid = device.spawn(["com.example.ndk_test"]) # 应用的包名,记得改
device.resume(pid)
time.sleep(1)
session = device.attach(pid)

with open("inject.js", "r", encoding="utf-8") as f:
script = session.create_script(f.read())
script.on("message", my_message_handler)
script.load()

input()

inject.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log("Script loaded successfully ");

var nativePointer = Module.findExportByName("libcalc.so","Java_com_example_ndk_1test_MainActivity_add");//需要 hook 的文件和方法
send("native function add pointers at:" + nativePointer);
Interceptor.attach(nativePointer,{
onEnter:function(args){
send("args is: a= " + args[2].toInt32() + ", b=" + args[3].toInt32());
// args[2] 就是第一个参数 args[3] 就是第二个参数
// .toInt32() 可以转化为 int;
// 如果是 string 就直接打印不用转化
},
onLeave:function(retval){ // 当函数返回时 调用此方法
send("before change res=" + retval.toInt32());
retval.replace(114514); // 修改返回值为 114514
send("after change res=" + retval.toInt32()); // 将修改后的返回值发送到 python 端
}

});

代码很好懂,这里就不解释了。就是 onLeave 即返回要返回的时候下一个钩子,我们将所以加法的结果都修改为返回 114514

运行测试

上述代码写好之后,我们就接上调试机,然后开始进行调试。

运行结果,终端显示如下

运行 load.py

调试机端显示如下,可以看到 114 + 514 = 114514 。计算错误, Hook 成功。

Hook 成功

总结

本文只是简单使用体验一下 NDK 的 Hook 其中还有大量的知识不娴熟或者新学中,并且还有大量未知的知识。如 frida 除了 onLeave 还有哪些类似的函数,这些函数的参数是什么,参数又是怎么样的结构?等等。边学边记吧。

参考链接

参考链接1: frida 对 NDK 进行 Hook https://blog.csdn.net/cpongo1/article/details/102580584

参考链接2: frida onEnter 函数 https://frida.re/docs/quickstart/

参考链接3:frida 接收参数 https://bbs.pediy.com/thread-248772.htm