Hooking.h: #ifndef Hooking_H #define Hooking_H extern "C" _declspec(dllexport)BOOL WINAPI SetHook(DWORD dwThread); #endif Hooking.cpp: #include "stdafx.h" #include#include #include "Hooking.h" LRESULT CALLBACK HookmProc(int nCode, WPARAM wParam, LPARAM lParam); HHOOK g_hHook = NULL; HINSTANCE g_hinstDll = NULL; BOOL WINAPI Typedef_eSetHook(DWORD dwThread) { g_hinstDll = GetModuleHandle(L"Hooking.dll"); g_hHook = SetWindowsHookExW(WH_CBT, HookmProc, g_hinstDll, dwThread); if (NULL == g_hHook) { printf("sethook failed!"); } return TRUE; } LRESULT CALLBACK HookmProc(int nCode, WPARAM wParam, LPARAM lParam) { CreateFileW(L"C:\\Users\\Administrator\\Desktop\\hook success.txt", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL); return(CallNextHookEx(g_hHook, nCode, wParam, lParam)); } dllmian.cpp: LRESULT CALLBACK HookmProc(int nCode, WPARAM wParam, LPARAM lParam); BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { /*g_hCurrentMoudle = hModule; g_hHook = SetWindowsHookExW(WH_KEYBOARD, HookmProc, hModule, 0);*/ //LoadDll();//1.找出感兴趣的进程 2.从证书中获取密钥 3.加载文件过滤DLL } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } Hooking.def: LIBRARY "Hooking" EXPORTS Typedef_eSetHook @1
在windows核心编程中的第22章中提到了插入DLL和挂接API这个内容,刚开始看到并不是很明白,所以当时关于注入DLL ,我选取的是一个相对我自己而言比较容易理解的远程注入,在做毕设的过程中,我发现挂钩注入DLL其实是更加方便和强悍的一种方法,我也在网上搜索过很多例子,试图先寻找一个样板依葫芦画瓢,可是一直没有满意的,所以自己下定决心写了一个,发现也没那么难,仔细一点就好了,下面是原理和实现的过程。
众所周知,windows这个强大的消息是基于事件驱动的,事件驱动就会引发消息,所以在窗口接受到消息之前可以对其进行一些你想要的处理就会发生窗口处理消息之前先处理你所需要的操作,就达到了消息过滤的过程,这个主要基于windows的消息机制——系统一旦发生操作就会引发消息,并将消息放到消息队列中,应用程序从消息队列中获取消息并发送到相应的窗口让钩子函数在这个函数“有机可趁”。消息过滤与我所要讲的挂钩注入DLL又有什么联系呢,主要是挂钩注入DLL中用到一个函数SetWindowsHookEx,这个函数大家网上一搜一堆解读,这边就不做赘述,其第一个参数就是消息钩子,也就是说,DLL所要注入的那个进程发送了某种消息给窗口后才会引发钩子钩住并注入DLL,这与消息过滤其实是一个意思。我这边主要做的是注入特定的进程,而不是全局钩子,其实全局钩子也很简单,只需要将上述函数的最后一个参数设为0,但这样会导致,但凡发送了相同消息给窗口的都会导致钩子钩住并注入DLL执行相应处理,这样我就不知道是不是我要的线程发送了这个消息,所以最后一个参数我传递了指定线程的ID。下面是实现的过程——将自己写的Hooking.dll通过自己写的应用程序MyHook.exe注入到word进程,目前是在word进程已经存在,由于设置的是WH_CBT钩子,所以一旦word进程最大化或者成为活动窗口之类的就会发送相应的消息,导致相应的处理,这里我只是做简单的处理比如在桌面上建立一个小文件。
1.首先打开VS2008,创建一个工程,在该工程下面创建两个项目,一个是Hooking的DLL项目,一个是MyHook项目,是负责设置挂钩的
2.在该DLL中主要就是挂钩函数SetWindowsHookExW(WH_CBT, HookmProc, g_hinstDll, dwThread)和处理函数LRESULT CALLBACK HookmProc(int nCode, WPARAM wParam, LPARAM lParam),之所以能将DLL注入到指定进程,就是因为,以dwThread为ID的指定进程向窗口发送与WH_CBT挂钩相关联的消息,导致其执行处理函数HookmProc,而处理函数又在以g_hinstDll为句柄的DLL中,所以必须先将DLL注入到指定进程才能执行该处理函数,处理函数这里只进行了简单的操作证明其注入成功了,例如创建一个桌面文件。这里的DLL的句柄参数就是就是挂钩函数所在的DLL ,但DLL并不执行挂钩函数,而是作为接口,由MyHook.exe调用
3.所以MyHook模块中主要就是加载Hooking.dll调用其接口函数SetHook,以指定被注入的线程的句柄为参数,在这之前,先要遍历系统进程找到WINWORD.EXE并将其线程句柄获得传入,这里用到了快照方法,这个也不做赘述,网上一堆。
4.由此,先启动word进程并将其窗口最小化,然后运行程序就会得到想要的效果,DLL被注入,再最大化word窗口,桌面就会出现小文件
5.总结一下,这中间遇到了一些问题,但都与挂钩注入DLL无关,还是自己的基础不牢。
下面要考虑的就是,加上监视word启动的代码,这样一旦word启动了就进行上述操作,不启动则不进行
MyHook.h: #pragma once typedef BOOL(WINAPI *Typedef_eSetHook)(DWORD); extern Typedef_eSetHook SetHook; MyHook.cpp: #include#include #include "stdio.h" #include "MyHook.h" #include Typedef_eSetHook SetHook = NULL; BOOL LoadNativeLibrary() { HMODULE hDll = LoadLibraryW(L"..\\Debug\\Hooking.dll"); if (hDll != NULL) { SetHook = (Typedef_eSetHook)GetProcAddress(hDll, MAKEINTRESOURCEA(1)); } else { printf("LoadLibrary failed\n"); } if(NULL == SetHook) { printf("SetHook is null\n"); OutputDebugStringA("0x103200 no init func."); } return TRUE; } int main() { LoadNativeLibrary(); DWORD dwProcessID = 0; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, dwProcessID); if (hSnapshot == NULL) { return 0; } PROCESSENTRY32 processinfo = {0}; processinfo.dwSize = sizeof(processinfo); Process32FirstW(hSnapshot, &processinfo); do { if (0 == lstrcmpiW(processinfo.szExeFile, L"WINWORD.EXE")) { dwProcessID = processinfo.th32ProcessID; break; } } while (Process32NextW(hSnapshot, &processinfo)); CloseHandle(hSnapshot); unsigned long pTID; _asm { mov eax, fs:[0x18] add eax, 36 mov [pTID], eax } DWORD threadID; HANDLE hProcess = OpenProcess(PROCESS_VM_READ, false, dwProcessID); ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL); SetHook(threadID); printf("..."); getche(); return 0; }
其实一开始我主要是纠结于哪个函数放在哪个cpp还是dll里面,还有word干嘛了会让setwindowshook函数将dll注入到其进程。后来我想自己肯定要有一个应用程序去执行挂钩这个过程,本来想把setwindowshook这个函数也放在自己的应用程序里,后来想想最好把其和处理函数放在一起,然后处理函数必然要在dll里,于是就把setwindowshook函数也放在dll里,因为放在dll里他也不会执行,只要自己的应用程序去执行就行了,所以把setwindowshook这个函数封装起来作为接口传给自己的应用程序,应用程序一调用就进行挂钩了而且也把这个dll注入到了相应进程了。
以上肯定还有很多不完善和不正确的表述,也欢迎大家指出,谢谢!!!