SetWindowHookEx 是Windows
系统的一个函数,可用于让一个应用程序安装全局钩子,但读者需要格外注意该方法安装的钩子会由操作系统注入到所有可执行进程内,虽然该注入方式可以用于绕过游戏保护实现注入,但由于其属于全局注入所以所有的进程都会受到影响,而如果想要解决这个问题,则需要在DllMain()
也就是动态链接库开头位置进行判断,如果是我们所需操作的进程则执行该DLL模块内的功能,如果不是则自动跳过不执行任何操作即可实现指定进程的注入方式。
首先我们先来看一下该函数的原型定义;
HHOOK SetWindowsHookEx( int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId );
|
参数说明如下:
- idHook:钩子类型,标识了钩子函数要监视哪种事件。可以是整数值或预定义的常量值(如WH_MOUSE、WH_KEYBOARD、WH_SHELL等)。
- lpfn:钩子函数的地址。
- hMod:把钩子函数插入挂钩链中的应用程序的句柄,该参数通常被设置为包含钩子函数代码的DLL模块的句柄。
- dwThreadId:要设置钩子的线程标识符或进程标识符,如果为 0,则钩子通常与所有线程的输入消息联系起来。
在安装全局消息钩子时,读者需要在DLL中对外暴漏两个接口,其中SetHook()
用于设置钩子,UnHook()
则用于取消钩子,在DLL入口处,通过调用GetFristModuleName()
我们可以判断当前进程是否为我们所需操作的进程,如果是则执行进程内的流程,如果不是则跳过执行,这个流程可以描述为如下样子,读者可自行将如下代码编译为DLL文件。
#include <iostream> #include <TlHelp32.h> #include <windows.h> #include <tchar.h>
HHOOK global_Hook;
BOOL GetFristModuleName(DWORD Pid, LPCTSTR ExeName) { MODULEENTRY32 me32 = { 0 }; me32.dwSize = sizeof(MODULEENTRY32); HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, Pid);
if (INVALID_HANDLE_VALUE != hModuleSnap) { BOOL bRet = Module32First(hModuleSnap, &me32);
if (!_tcsicmp(ExeName, (LPCTSTR)me32.szModule)) { CloseHandle(hModuleSnap); return TRUE; } CloseHandle(hModuleSnap); return FALSE; } CloseHandle(hModuleSnap); return FALSE; }
char* GetMyDllName() { char szFileFullPath[MAX_PATH], szProcessName[MAX_PATH];
GetModuleFileNameA(NULL, szFileFullPath, MAX_PATH); int length = strlen(szFileFullPath);
for (int i = length - 1; i >= 0; i--) { if (szFileFullPath[i] == '\\') { i++; for (int j = 0; i <= length; j++) { szProcessName[j] = szFileFullPath[i++]; } break; } } return szProcessName; }
LRESULT CALLBACK MyProc(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(global_Hook, nCode, wParam, lParam); }
extern "C" __declspec(dllexport) void SetHook() { global_Hook = SetWindowsHookEx(WH_CBT, MyProc, GetModuleHandleA(GetMyDllName()), 0); }
extern "C" __declspec(dllexport) void UnHook() { if (global_Hook) { UnhookWindowsHookEx(global_Hook); } }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { BOOL flag = GetFristModuleName(GetCurrentProcessId(), TEXT("lyshark.exe")); if (flag == TRUE) { MessageBoxA(0, "hello lyshark", 0, 0); } break; } case DLL_THREAD_ATTACH: { break; } case DLL_THREAD_DETACH: { break; } case DLL_PROCESS_DETACH: { UnHook(); break; } default: break; } return TRUE; }
|
接着我们需要编写一个专门用来加载该DLL的程序,在调用DLL之前,我们需要通过LoadLibrary()
将此模块加载到内存中,并通过GetProcAddress(hMod, "SetHook")
获取到该模块的中SetHook
函数的内存地址,最后直接调用SetHook()
安装一个全局钩子,实现安装的代码流程如下所示;
#include <iostream> #include <windows.h>
int main(int argc, char* argv[]) { HMODULE hMod = LoadLibrary(TEXT("d://hook.dll"));
typedef void(*pSetHook)(void); pSetHook SetHook = (pSetHook)GetProcAddress(hMod, "SetHook"); SetHook();
while (1) { Sleep(1000); }
typedef BOOL(*pUnSetHook)(HHOOK); pUnSetHook UnsetHook = (pUnSetHook)GetProcAddress(hMod, "UnHook"); pUnSetHook();
FreeLibrary(hMod); return 0; }
|