windows向用户提供GUI,它以事件驱动的方式工作。操作系统中借助鼠标,键盘,选择菜单,按钮,以及移动鼠标,改变窗口大小与位置等都属于事件(对此我感受最深的是学QT编程的时候,每个按钮或其他事件都会对应一个槽函数,通过槽函数的调用来实现相应的功能)。发生事件时,OS会把事先定义好的消息发送给相应的程序,应用程序收到消息后会执行相应的操作。所以,敲击键盘时,消息会从os移动到应用程序,所谓的消息钩子,就是在此间偷看这些信息。
应用程序和OS之间好似有一条运输通道,而钩子,就是埋伏在这条运输通道上的小偷,他会翻看OS与应用程序之间的消息队列,必要时,还会对有些消息进行改变或者丢弃。
再一点,如果同时加上多个钩子,钩子就会向一条链一样,链起来,形象的称为“钩链”。
钩子的主程序是以dll的形式存在着,然后通过一个应用程序进行调用,应用程序作为一个启动程序,将钩子的dll注册到windows上,主体是dll文件。
Dll文件的主函数,当dll被注入进程时,会首先调用该函数,该函数还可对一些变量进行一些初始化和变量赋值。
#ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HookStart() { g_hHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); } __declspec (dllexport) void HookStop() { if (g_hHook) { UnhookWindowsHookEx(g_hHook); g_hHook = NULL; } } #ifdef __cplusplus } #endif导入导出函数,用于在启动程序中来启动或卸载钩子。此处还声明了钩子类型,回调函数…
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { char szPath[MAX_PATH] = { 0, }; char* p = NULL; if (nCode == 0) { if (!(lParam & 0x80000000)) { GetModuleFileNameA(NULL, szPath, MAX_PATH); p = strrchr(szPath, '\\'); g_hWnd = FindWindow(NULL, (LPCWSTR)DEF_PROCESS_NAME); if (!_stricmp(p + 1, DEF_PROCESS_NAME)) { return 1; } } } return CallNextHookEx(g_hHook, nCode, wParam, lParam); }钩子函数中最关键的回调函数,当发生键盘输入事件时,会调用该函数进行消息处理,MSDN对他的定义如下
LRESULT CALLBACK KeyboardProc( _In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam );code,用来表示钩子程序如何处理消息,如果code的值小于0,则钩子程序需要直接将消息传给CallNextHookEx函数。
wParam,传递的是虚拟键值,在这,’A‘和’a‘ 是相同的虚拟键值。
lParam,传递一些额外扩展信息,用32比特来传递一些信息,具体情况请参考微软官网.
相比之下简单多了,通过调用dll的导出函数,直接实现了钩子的注册及卸载,可以看到,在调用HookStart后,执行一个死循环,也就是说,这就是个启动程序,启动之后就没用了。
思维扩展一点,可以将启动程序换到某个有实际功能的程序里,当该程序运行时,多起一个线程运行钩子,悄无声息的截获你的消息。:)
多方查找,这是个很傻*的错误,原因是32位程序无法注入64位程序,可能是一开始我就是用32位注入64位出错了,我的操作系统是win10,再后来,我编译了64位的程序,可还是有程序会崩溃,于是上网查资料,遇到了同样经历的一位大哥,https://bbs.pediy.com/thread-250189.htm,我试了又试,还是回到了这个傻逼的架构不匹配的问题上。
由于32位和64位架构不匹配,当你64位的钩子注入到32位的程序里时,会使用sendmessage来传递消息,而这个进程,也就卡在了这里。。。
本来想着在钩子里加个文件记录功能,能记录敲击的键盘按键,谁知virtual studio竟然不让我用fopen,气死我了。无奈转战createFile,谁知也是一地鸡毛,死活就是写不进去了。
最后通过改宏定义用上了fopen,说来也怪,能用fopen之后,CreateFile也能行了,不知道是不是那个宏的原因。
右键工程名–>属性–>C/C++–>预处理器–>预处理器定义,编辑右边输入框加入: 奈转战createFile,谁知也是一地鸡毛,死活就是写不进去了。
参考文章:《逆向工程核心原理》 https://blog.csdn.net/weixin_39449570/article/details/78801573
