我们想要用自己写的一个函数来接管A程序对某消息的处理,那么首先你这个函数所在的文件,是要在这个A程序里面的,也就是说,SetWindowsHookEx函数,在他下钩子的过程当中,操作系统帮助我们完成了一次注入。
HHOOK SetWindowsHookExA(
int idHook, //钩子程序的类型,常用的有WH_KEYBOARD用于钩取键盘消息
HOOKPROC lpfn, //回调函数,就是接收到消息后怎么处理。如果填NULL程序会崩溃
HINSTANCE hmod, //lpfn函数所在模块的地址
DWORD dwThreadId //钩子针对的线程,如果填0就是针对所有进程,叫全局钩子
);
关于SetWindowsHookExA第二参指定函数地址的理解:
- 如果说,你想注入一个其他进程创建的线程,就是当dwThreadId是其他进程创建的线程,或者是0(所有线程)的时候,这个lpfn必须是一个动态链接库里的函数。只有当你想hook本程序的线程,也就是自己hook自己的时候,这个lpfn才可以是当前进程相关代码中定义的函数。
- 如果你想给自己的程序下钩子(自己hook自己),这时候dwThreadId填自己进程的线程,然后lpfn可以是自己进程对应代码里的函数,也可以是动态链接库的函数。如果lpfn是自己进程对应代码的函数的话,hMod一定得是空。
- 我们给一个别的程序做注入,lpfn对应的函数,必须不能写在注入器里,因为如果你把lpfn写在注入器里,hMod就要是注入器模块,但是注入器是个.exe文件,你觉得能把一个.exe文件注入到另一个.exe文件中吗?不行。所以我们必须是把lpfn函数写在一个.dll文件对应的代码里。这里我们把.dll文件命名为CheatMode。
- 所以现在又面临一个问题,就是你怎么让注入器这里得到CheatMode里的函数?假如CheatMode是一个动态链接库,那啥事没有,但是如果CheatMode是一个静态链接库,不是动态链接库,那又该怎么办?我这里给出的解决方案是,在CheatMode里把该函数给导出(在CheatMode.def里写下这个函数的名字),这样我们就可以在注入器里先HMODULE hMod = LoadLibrary(L"CheatMode.dll"),加载CheatMode.dll模块,然后GetProcAddress(hMod, "lpfn"),这样就得到这个函数了。
整体概括:当调用完SetWindowsHookExA函数后,就会把hMod模块注入到dwThreadId线程所在的进程当中。之后一旦dwThreadId线程接收到idHook类型的消息,就会调用hMod模块里的lpfn函数。