Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会收到系统的通知,这时程序就能在第一时间对该事件做出响应。
自己理解的原理
解释:HOOK通过在HOOK点进行修改,是原先的代码执行到HOOK点后,跳转到自己的代码上执行,得到数据或者进行自己的操作后,返回到原先的代码继续执行(自己理解,若有不足或错误,欢迎指正)
使用MFC的动态链接库,实现动态HOOK
- 测试程序(自己写的取和计算)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fyVQBFi6-1589989765101)(https://i.loli.net/2020/05/20/FAzDbHC5qliLKr4.png)]
在没HOOK 前,是实现的简单加法运算,并且打印和
- HOOK 后展示
将a + b 转换为a + 2 * b 并且在编辑框打印a 和b 的值
代码实现
HOOK
- 找到HOOK 点
这里主要是实现对函数的修改,及让程序执行自己的函数,执行完成后跳会原先的代码,继续执行,下面是原先的代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-coOQ4jOp-1589989765106)(https://i.loli.net/2020/05/20/2CvZEbdGFpxz76U.png)]
这里我们只需要修改CALL后面的地址,及将
call 0x00401000
修改为
CALL 自定义函数地址
-
新建项目MFC_DLL
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4IW7vTZF-1589989765109)(https://i.loli.net/2020/05/20/VcUoQpZriKqCwSL.png)] -
新建的MFC DLL 没有窗口,所以先添加窗口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNyOtKVm-1589989765113)(https://i.loli.net/2020/05/20/Y4HJrksRmOtMgPq.png)] -
双击新建的界面,新建窗口类,在初始化方法添加窗口显示代码
// CMFCDLLDyncHookApp 初始化
#include "CDlgPageOne.h"
CDlgPageOne cpg1;
DWORD WINAPI ShowDlgProc(
LPVOID lpParameter // thread data
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// 通过模态方式实现(阻塞),所以子线程执行
cpg1.DoModal();
// 卸载DLL
FreeLibraryAndExitThread(theApp.m_hInstance, 1);
}
BOOL CMFCDLLDyncHookApp::InitInstance()
{
CWinApp::InitInstance();
::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ShowDlgProc, 0, 0, 0);
return TRUE;
}
- 定义函数
void MyAddFunc(int a, int b)
{
int c = a + b + a * b;
printf("结果 = %d\r\n", c);
return;
}
- HOOK
int Hook()
{
// 求函数地址偏移
DWORD funcAddr = (DWORD)MyAddFunc;
DWORD offset = funcAddr - 0x5 - 0x401081; // 00401081 | E8 7AFFFFFF | call hook-test.401000 | 修改call 后的目标地址,使他跳转到自定义函数上
// 修改页面属性
DWORD oldProtect = 0;
VirtualProtect((LPVOID)0x00401081, 20, PAGE_EXECUTE_READWRITE/*可写可读*/, &oldProtect);
// 写入目标地址
DWORD *_offset = (DWORD*)0x401082; // hook 的地址
*_offset = offset;
// 恢复原先页面属性
VirtualProtect((LPVOID)0x00401081, 20, oldProtect, &oldProtect);
return 0;
}
- UNHOOK
与HOOK 类似,将原先的代码重新修改回去
int UnHook()
{
// 修改页面属性
DWORD oldProtect = 0;
VirtualProtect((LPVOID)0x00401081, 20, PAGE_EXECUTE_READWRITE, &oldProtect);
// 写入目标地址
DWORD *_offset = (DWORD*)0x401082;
*_offset = 0xFFFFFF7A;
// 恢复页面属性
VirtualProtect((LPVOID)0x00401081, 20, oldProtect, &oldProtect);
return 0;
}
到这里,实现了动态HOOK,可以实现对原有代码的修改,但是还不能再窗口上实时打印参数的值,这里还需要修改一些代码
- 实现数据的实时打印
- 修改自定义函数
void MyAddFunc(int a, int b)
{
int c = a + b + a * b;
printf("结果 = %d\r\n", c);
// 将参数赋值给EDIT 控件绑定的参数m_ValueStr
cpg1.m_ValueStr.Format("a = %d, b = %d", a, b);
// 因为当前函数是执行在HOOK_Test(被hook exe)上的,而非MFC 上,二者不在同一个线程,直接更新数据会造成数
// 据不同步,而出现程序崩溃,所以这里使用消息发送的方式,进行数据更新
cpg1.SendMessage(WM_USER + 1, 222, 111);
return;
}
- 接受MyAddFunc 函数来的消息,重写WindowProc 函数
LRESULT CDlgPageOne::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: 在此添加专用代码和/或调用基类
if (message == WM_USER + 1)
{
UpdateData(FALSE);
}
return CDialogEx::WindowProc(message, wParam, lParam);
}
经过上述操作,即可实现动态HOOK,并且同步获取数据进行显示