复现《逆向工程核心原理》Hook
简介
利用Hook,我们可以查看,修改,截断 ‘用户-os-应用程序’ 之间所有的信息

接下来以keyBoard为例,实际操作一下,目的是向notepad.exe中注入KeyHook.dll实现键盘输入的钩取,并且改写成全局钩子,显示获取到的key
函数总览
main
HookMain.cpp //注入函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include"stdio.h" #include"Windows.h" #include"conio.h"
#define DLL_NAME "KeyHook.dll" #define HOOKSTART "HookStart" #define HOOKSTOP "HookStop"
typedef void(*FN_HOOKSTART)(); typedef void(*FN_HOOKSTOP)();
int main() { HMODULE hDll = NULL; FN_HOOKSTART HookStart = NULL; FN_HOOKSTOP HookStop = NULL;
hDll = LoadLibraryA(DLL_NAME);
HookStart = (FN_HOOKSTART)GetProcAddress(hDll, HOOKSTART); HookStop = (FN_HOOKSTOP)GetProcAddress(hDll, HOOKSTOP);
HookStart();
printf("press 'q' to quit this hook procdure"); while (_getch() != 'q');
HookStop();
FreeLibrary(hDll);
return 1; }
|
dll
KeyHook.cpp //dll实现函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include "stdio.h" #include "windows.h" #include <iostream> #include <fstream>
#define PROCESS_NAME "notepad.exe"
HINSTANCE g_hInstance = NULL; HHOOK g_Hook = NULL; HWND g_hWnd = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: g_hInstance = hinstDLL; break; case DLL_PROCESS_DETACH: break; default: break; } return TRUE; }
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, '\\');
if (!_stricmp(p + 1, PROCESS_NAME)) { return 1; }
} } return CallNextHookEx(g_Hook, nCode, wParam, lParam); } #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HookStart() { g_Hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); } __declspec(dllexport) void HookStop() { if (g_Hook) { UnhookWindowsHookEx(g_Hook); g_Hook = NULL; } } #ifdef __cplusplus } #endif
|
逐块解释
dll
下面逐块解释一下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| HINSTANCE g_hInstance = NULL; HHOOK g_Hook = NULL; HWND g_hWnd = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: g_hInstance = hinstDLL; break; case DLL_PROCESS_DETACH: break; default: break; } return TRUE; }
|
这是DLL的程序入口,是一种框架代码,一般的Dll都会这样写。
程序会根据fdwReason的值执行不同的函数,fdwReason有四种取值
1 2 3 4
| fdwReason 0 DLL_PROCESS_ATTACH //DLL被加载 fdwReason 1 DLL_PROCESS_DETACH //DLL被卸载 fdwReason 2 DLL_THREAD_ATTACH //创建进程时 fdwReason 3 DLL_THREAD_DETACH //卸载进程时
|
当fdwReason为DLL_PROCESS_ATTACH时, lpvReserved为NULL表示动态加载,不为NULL表示静态加载。当fdwReason为DLL_PROCESS_DETACH时, lpvReserved为NULL表示FreeLibrary被调用或DLL加载失败,不为NULL表示进程正在终止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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, '\\'); if (!_stricmp(p + 1, PROCESS_NAME)) { return 1; }
} } return CallNextHookEx(g_Hook, nCode, wParam, lParam); }
|
这个函数将作为SetWindowsHookEx函数的一个参数,负责处理Hook到的消息,通俗的来讲,你要对截获的信息进行处理,可以是舍弃,变更,修改等等,所以要写一个函数来实现,对于这个程序,功能为判断这个输入是否是在notepad.exe进程中,如果是就不向下传递,如果不是就调用CallNextHookEx(),将信息传递下去。
ncode参数
1 2 3
| 小于0:必须调用CallNextHookEx函数传递消息 0:表示参数wParam和lParam 包含关于虚拟键值相关信息 3:在值为0的基础上,表示这个消息被某个进程用PeekMessage查看过
|
也就是当ncode>0的时候,可以对进行操作,否则只能传递钩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void HookStart() { g_Hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); } __declspec(dllexport) void HookStop() { if (g_Hook) { UnhookWindowsHookEx(g_Hook); g_Hook = NULL; } } #ifdef __cplusplus } #endif
|
1 2 3 4 5 6 7
| #ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } #endif
|
有些函数只能在c语言下解析,但是dll源文件是cpp,这个就是告诉编译器什么时候再c语言下解析,什么时候再cpp下解析。
__declspec(dllexport) 标志导出函数
1 2 3 4 5 6
| HHOOK SetWindowsHookExA( [in] int idHook, [in] HOOKPROC lpfn, [in] HINSTANCE hmod, [in] DWORD dwThreadId );
|
main
主函数较为简单
LoadLibraryA 加载dll
GetProcAddress 获取dll中的函数地址
测试
测试环境 : win10,xp
看到网上说win10环境下会出现问题,但是我自己试的的时候好像没什么问题。两种测试环境大同小异,win10要编译成64位可执行程序,xp编译成32位可执行程序即可。我这里使用g++编译器
1 2 3 4
| g++ -shared ./KeyHook.cpp -o KeyHook.dll
g++ ./KeyHook.dll hookMain.cpp -o KeyHook.exe
|
生成这两个文件,说明成功
先运行exe文件,后打开notepad

此时键盘输入无效,打开进程管理工具发现KeyHook.dll成功注入

xp 平台测试与win10类似,gcc要用32位版本,而且似乎xp并不支持在当前路劲打开cmd,要用绝对路径。
全局钩子和显示key
1 2 3 4 5 6 7 8
| if (!_stricmp(p + 1, "conhost.exe")) { return CallNextHookEx(g_Hook, nCode, wParam, lParam); return 1; } else{ GetKeyNameTextA(lParam,str,50); }
|
1 2 3 4 5
| int GetKeyNameTextA( [in] LONG lParam, [out] LPSTR lpString, [in] int cchSize );
|
开始以为参数是存放在wParam中,一直没有成功。
