背景
我们经常想要监控接口调用或者修改接口的行为以及返回值,通过监控系统接口的调用我们可以了解目标程序的行为,通过修改接口的实现或修改接口的返回值我们可以控制程序的逻辑,比如我们可以通过此方式绕过程序对于授权的检查行为,当然我们也可以通过调试器实现这些功能,但是通过调试器一旦使用 Virbox Protector 进行加壳保护,使其具有反调试的功能我们将无法通过调试器实现这一目的。
这时我们可以通过对目标接口进行Hook,这样我们就能够实现上述的功能了,本篇文章我们将要进行介绍的是使用Frida实现这一功能。
步骤
环境准备
要想使用 Frida 我们首先当然是需要安装 Frida 了,Frida 基于Python,我们首先需要安装Python3,安装Python3后我们就可以使用命令行安装Frida了
base
pip install frida frida-tools
当然,我们如果想要实现远程 Hook,比如Hook Android上的应用我们也可以安装 frida-server
安装完成后我们可以使用下面的命令来验证一下 frida 是否安装成功
base
frida --version
Hook Windows 接口 MessageBox
编写示例程序
我们首先需要编写一个示例程序,用于一会在进行监测使用,我们这里使用C++语言简单实现一个示例程序
c++
#include <iostream>
#include <Windows.h>
int main()
{
printf("MessageBoxW address: 0x%p\n", MessageBox);
fflush(stdout);
MessageBox(NULL, L"Step.1", L"Debug", MB_OK);
MessageBox(NULL, L"Step.2", L"Debug", MB_OK);
MessageBox(NULL, L"Step.3", L"Debug", MB_OK);
MessageBox(NULL, L"Step.4", L"Debug", MB_OK);
MessageBox(NULL, L"Step.5", L"Debug", MB_OK);
MessageBox(NULL, L"Step.6", L"Debug", MB_OK);
std::cout << "Hello World!\n";
}
现在这个程序就已经足够我们使用了,为了方便我们这里直接打印了MessageBox接口的地址,当然我们也可以直接在Frida脚本中获取接口的地址
这个程序首先会打印 MessageBox 的接口地址,然后会依次弹出窗口,我们要做的就是监视接口的调用
Frida 脚本准备
这里我们直接使用 Python 进行编写,当然也可以直接使用 JS 进行编写。脚本如下
python
import frida
import sys
# 如果需要进行远程调试,可以使用如下的方式进行编写
# device = frida.get_device_manager().add_remote_device("127.0.0.1")
# session = device.attach('test_sdk')
session = frida.attach('hookTest.exe')
script = session.create_script("""
Interceptor.attach(ptr(%s), {
onEnter(args) {
// 参数说明:
// args[0] - hWnd (窗口句柄)
// args[1] - lpText (消息内容)
// args[2] - lpCaption (标题)
// args[3] - uType (按钮/图标类型)
const hWnd = args[0];
const text = args[1].isNull() ? null : args[1].readUtf16String();
const caption = args[2].isNull() ? null : args[2].readUtf16String();
const type = args[3].toInt32();
console.log(`[+] MessageBoxW called:`);
console.log(` hWnd: ${hWnd}`);
console.log(` Text: ${text}`);
console.log(` Caption: ${caption}`);
console.log(` Type: 0x${type.toString(16)}`);
// 可以在这里修改参数
// args[1] = Memory.allocAnsiString("Frida Hook");
},
onLeave: function (retval) {
// 返回值是用户点击的按钮ID
console.log(`[-] write returned: ${retval.toInt32()}`);
}
});
""" % int(sys.argv[1], 16))
def on_message(message, data):
print(message)
script.on('message', on_message)
script.load()
sys.stdin.read()
好了,现在我们有了python脚本我们就可以把它保存为 .py 文件了,比如我将其保存为 frida_test.py
Hook 测试
首先我们运行我们的目标程序,目标程序运行起来了以后会打印接口地址,我们使用如下的命令行运行我们的frida脚本
bash
python frida_test.py 0x00007FFDD3FA8900
注意,命令行中的地址需要改为你自己的
现在我们点击目标程序的弹窗按钮就可以看到实际上已经监测到了接口的调用了,包括参数也一同打印了出来,当然我们还可以修改接口的返回值,参数,等等,这里我就不再赘述了
防范
俗话说能破就能立,我们知道了如何使用frida进行hook接口,为了防止有人使用该功能hook我们的程序,对我们造成损失,我们应该怎么办呢?
在即将发版的 Virbox Protector 中将发布Hook检测功能,我们可以调用SDK对接口进行检测,如果有人对我们的接口进行了Hook,我们的SDK接口就会返回非0值,我们就可以根据返回值做出相关动作,是退出程序还是提示用户或者上报信息都随你意啦,总而言之,软件安全不容小觑啊