安全编程技术-消息 Hook实验
消息Hook实验
Windows系统建立在事件驱动机制上,整个系统通过消息传递实现的。在Windows系统里,消息Hook就是一个Windows消息的拦截机制,可以拦截单个进程的消息(线程钩子),也可以拦截所有进程的消息(系统钩子),也可以对拦截的消息进行自定义的处理:
- 如果对于同一事件(如鼠标消息)既安装了线程Hook又安装了系统Hook,那么系统会自动先调用线程Hook,然后调用系统Hook(类似栈)。
- 对于同一事件消息可安装多个Hook处理过程,这些Hook处理过程形成了Hook链,后加入的有优先控制权。
在Windows中,利用SetWindowsHookEx函数创建钩子(Hooks)可以实现DLL注入,本实验使用消息Hook实现dll注入,实现类似插桩的效果。
- 编制键盘消息的Hook函数一KeyHook.dll中的KeyboardProc函数
- 通过SetWindowsHookEx创建键盘消息钩子实现DLL注入(执行DLL内部代码)
实验环境:Win xp sp3、vc6.0
- 编写DLL文件:
在VC 6中新建一个Win32 Dynamic-Link Library项目,Project name: KeyHook
创建一个空的DLL项目
添加一个代码文件KeyHook.cpp
#include "stdio.h"
#include "windows.h"
#define DEF_PROCESS_NAME "notepad.exe" //定义hook进程名称
HINSTANCE g_hInstance = NULL;
HHOOK g_hHook = NULL;
HWND g_hWnd = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved){
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
g_hInstance = hinstDLL;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//Hook函数(自定义的键盘消息处理函数)
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{//这里对第二个参数lParam进行了处理
char szPath[MAX_PATH] = {0,};
char *p = NULL;
if( nCode >= 0 ){
// lParam 第31位bit: 0 => key press, 1 => key release
if( !(lParam & 0x80000000) ) { //当按键被释放时
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');
//比较当前进程名称,若为notepad.exe,则消息不会继续传递
if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
return 1; //丢弃该Keyboard消息
}
}
//若不为notepad.exe,调用CallNextHookEx()函数将消息传递给下一个“钩子”或应用程序
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
#ifdef __cplusplus //这里定义了两个导出函数HookStart()、HookStop(),允许外部调用
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
得到项目文件夹下的KeyHook.dll文件
-
编写DLL注入功能的可执行文件
新建一个VC6的控制台程序,添加源文件HookMain.cpp如下:#include "stdio.h" #include "conio.h" #include "windows.h" #define DEF_DLL_NAME "KeyHook.dll"//定义一些宏 #define DEF_HOOKSTART "HookStart" #define DEF_HOOKSTOP "HookStop" typedef void (*PFN_HOOKSTART)();//用于指向动态链接库的两个函数 typedef void (*PFN_HOOKSTOP)(); void main() { HMODULE hDll = NULL; PFN_HOOKSTART HookStart = NULL; PFN_HOOKSTOP HookStop = NULL; char ch = 0; hDll = LoadLibraryA(DEF_DLL_NAME); // 加载KeyHook.dll (这里为相对路径,dll与exe要位于同一路径下) if( hDll == NULL ){ printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError()); return; } // 获取导出函数地址 HookStart = (PFN_HOOKSTART)GetProcAddress(hDll, DEF_HOOKSTART);//获得特定函数地址 HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll, DEF_HOOKSTOP); HookStart(); // 开始Hook // 等待直到用户输入'q' printf("press 'q' to quit!\n"); while( _getch() != 'q' ) ; HookStop(); // 结束Hook FreeLibrary(hDll); // 卸载KeyHook.dll }
将HookMain.exe和KeyHook.dll放在相同目录下,运行HookMain.exe安装键盘消息Hook后,将实现notepad.exe进程的键盘消息拦截,使之无法显示在记事本中。直到输入“q”才可停止键盘Hook。
结果:
- 在记事本中无法输入
- 在其他程序中可以正常输入
- 输入q结束HookMain.exe后,记事本中也可以正常输入