【Windows代码注入教程】第一课 Windows消息的HOOK
本文是我学习《逆向工程核心原理》一书dll注入部分的学习总结,如有理解不到位或错误的地方欢迎大家以评论的方式完善指正很多朋友一谈到Hook就觉得很神秘,其实Hook很好理解
那么如何打开spy++呢?
如下图所示
Spy++ (SPYXX.EXE) 是一个基于 Win32 的实用工具,它提供系统的进程、线程、窗口和窗口消息的图形视图。使用 Spy++ 可以执行下列操作: 显示系统对象(包括进程、线程和窗口)之间关系的图形树。 搜索指定的窗口、线程、进程或消息。 查看选定的窗口、线程、进程或消息的属性。
下图是打开后Spy++的界面
我们在winuser.h中看一下这个函数的定义
我们在微软的支持库里看一下这个函数的解释
如果英文的看不懂,就看下文的中文解释
HOOKPROClpfn不太好理解,单独说下,它的意思是钩子过程
如果还看不懂就看下图的详细解释
做一个练习,用键盘hook技术拦截notepad.exe进程的键盘消息,使之无法显示在记事本中
首先看一下HookMain.exe的源码(关键代码处我已经做好了中文注释)
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#defineDEF_DLL_NAME"KeyHook.dll"
#defineDEF_HOOKSTART"HookStart"
#defineDEF_HOOKSTOP"HookStop"
typedef void (*PFN_HOOKSTART)();
typedef void (*PFN_HOOKSTOP)();
void main()
{
HMODULEhDll = NULL;
PFN_HOOKSTARTHookStart = NULL;
PFN_HOOKSTOPHookStop = NULL;
charch = 0;
// 加载KeyHook.dll
hDll = LoadLibraryA(DEF_DLL_NAME);
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);
//开始hook
HookStart();
//用户输入‘q’停止hook
printf("press 'q' to quit!\n");
while( _getch() != 'q' );
// 停止hook
HookStop();
//卸载 KeyHook.dll
FreeLibrary(hDll);
} 接下来看KeyHook.dll的源码
#include "stdio.h"
#include "windows.h"
#define DEF_PROCESS_NAME"notepad.exe"
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;
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char szPath = {0,};
char *p = NULL;
if( nCode >= 0 )
{
// bit 31 : 0 => press, 1 => release
if( !(lParam & 0x80000000) )//释放键盘按键时
{
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p = strrchr(szPath, '\\');
// 比较当前进程名称,若为notepad.exe,则消息不会传递给应用程序(或者下一个钩子)
if( !_stricmp(p + 1, DEF_PROCESS_NAME) )
return 1;
}
}
// 如果不是notepad.exe,则调用CallNextHookEx函数,将消息传递给应用程序
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
#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 我们再通过图来更深的了解一下HookMain.exe和keyhook.dll的关系
接下来开始运行调试我们写好的HookMain.exe
首先dll和注入器要在一个文件夹里(windows调用dll时会优先从同目录下寻找dll,所以不用放在system32文件夹里)
用OD打开HookMain.exe
上图显示的是 HookMain . exe 的 EP 代码,它是典型的 VC + +启动函数,其中最受关注的是开始进行键盘钩取的部分。
查找核心代码有几种方法可以帮助我们找到关注的核心代码:
入口逐行跟踪。
入口检索相关 API 。
入口检索相关字符串。
第一种方法是程序无法正常运行或难以预测时使用的下策,此处略去不谈。这样就剩下后面 2 种方法(检索 API 或字符串)了。由于已经运行过 HookMain . exe 程序,我们知道了该程序的功能(键盘钩取)与输出的字符串,所以下面要使用检索字符串( “ Press ' q ' to quit ! " )的方法。引用该字符串代码的前后就是我们关注的代码。在 OllyDbg 的代码窗口中,选择鼠标右键菜单中的 search for :一 All referenced text strings 项
双击进去,到达main函数
出现如下代码
执行完dll中的键盘hook函数后,键盘钩子就已经安装好了
用Process Explorer查看我们装好的钩子
然后我们运行到40104D处,让控制台输出字符串
执行40104D处的代码,程序跑起来了
不管按什么键盘按键,记事本什么都不显示,因为我们发出的键盘消息被拦截,它现在什么都收不到(可怜的记事本~~~~~~)
检索注入keyhook.dll的所有进程(查找——查找句柄或DLL)
输入要查找的dll,可以看到我们所有进程都被注入了keyhook.dll
因为我们安装的是全局钩子(前文讲SetWindowsHookEx参数时已经说明白了,不懂回去看)
源码中也可以看到为什么我们设置的全局钩子但只对notepad.exe有效了
接下来调试Notepad.exe进程内的KeyHook.dll
我使用学破解论坛的2.0OD
我们在段首下CC断点
然后在nopad.exe中随便输入一个字符
程序会断下
看堆栈可以看到充当回调函数的是user32.dll中的函数,user32.dll也就是参数HOOKPROCl pfn的实际过程
总结一下上述操作的顺序
好了,历经6个小时,终于写完了这一课,大家一定要自己亲手操作来学习,切不可走马观花,下一课会讲DLL注入,比这一课难很多,如果这节课没有理解,DLL注入的3种方法更不可能理解了。
页:
[1]