Windows下Hook API技术
2011-08-26 16:18
363 查看
Windows下Hook API技术 |
什么叫Hook API?所谓Hook就是钩子的意思,而API是指Windows开放给程序员的编程接口,使得在用户级别下可以对操作系统进行控制,也就是一般的应用程 序都需要调用API来完成某些功能,Hook API的意思就是在这些应用程序调用真正的系统API前可以先被截获,从而进行一些处理再调用真正的API来完成功能。在讲Hook API之前先来看一下如何Hook消息,例如Hook全局键盘消息,从而可以知道用户按了哪些键,这种Hook消息的功能可以由以下函数来完成,该函数将 一个新的Hook加入到原来的Hook链中,当某一消息到达后会依次经过它的Hook链再交给应用程序。 HHOOK SetWindowsHookEx( int idHook, //Hook类型,例如WH_KEYBOARD,WH_MOUSE HOOKPROC lpfn, //Hook处理过程函数的地址 HINSTANCE hMod, //包含Hook处理过程函数的dll句柄(若在本进程可以为NULL) DWORD dwThreadId, //要Hook的线程ID,若为0,表示全局Hook所有 ); [align=left][/align] [align=left] 这里需要提一下的就是如果是Hook全局的而不是某个特定的进程则需要将Hook过程编写为一个DLL,以便让任何程序都可以加载它来获取Hook过程函数。[/align] 而对于Hook API微软并没有提供直接的接口函数,也许它并不想让我们这样做, 不过有2种方法可以完成该功能。第一种,修改可执行文件的IAT表(即输入表),因为在该表中记录了所有调用API的函数地址,则只需将这些地址改为自己 函数的地址即可,但是这样有一个局限,因为有的程序会加壳,这样会隐藏真实的IAT表,从而使该方法失效。第二种方法是直接跳转,改变API函数的头几个 字节,使程序跳转到自己的函数,然后恢复API开头的几个字节,在调用AP完成功能后再改回来又能继续Hook了,但是这种方法也有一个问题就是同步的问 题,当然这是可以克服的,并且该方法不受程序加壳的限制。 [align=left] 下面将以一个Hook指定程序send函数的例子来详细描述如何Hook API,以达到监视程序发送的每个封包的目的。采用的是第二种方法,编写为一个dll。首先是一些全局声明,[/align] [align=left][/align] //本dll的handle HANDLE g_hInstance = NULL; //修改API入口为 mov eax, 00400000;jmp eax是程序能跳转到自己的函数 BYTE g_btNewBytes[8] = { 0xB8, 0x0, 0x0, 0x40, 0x0, 0xFF, 0xE0, 0x0 }; //保存原API入口的8个字节 DWORD g_dwOldBytes[2][2] = { 0x0, 0x0, 0x0, 0x0 }; //钩子句柄 HHOOK g_hOldHook = NULL; //API中send函数的地址 DWORD g_pSend = 0; //事务,解决同步问题 HANDLE g_hSendEvent = NULL; [align=left]//自己的send函数地址,参数必须与API的send函数地址相同[/align] [align=left]int _stdcall hook_send( SOCKET s, const char *buf, int len, int flags );[/align] [align=left]//要Hook的进程和主线程ID号[/align] DWORD g_dwProcessID = 0; DWORD g_dwThreadID = 0; [align=left][/align] [align=left] 从声明可以看出,我们会把API函数的首8个字节改为 mov eax, 00400000;jmp eax ,使程序能够跳转,只需获取我们自己的函数地址填充掉00400000即可实现跳转。而g_dwOldBytes是用来保存API开头原始的8个字节,在 真正执行API函数是需要写回。还有一点,在声明新的函数时,该例中为hook_send,除了保正参数与API的一致外,还需要声明为 __stdcall类型,表示函数在退出前自己来清理堆栈,因为这里是直接跳转到新函数处,所以必须自己清理堆栈。下面看主函数,[/align] [align=left][/align] BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if(ul_reason_for_call == DLL_PROCESS_ATTACH) { //获取本dll句柄 g_hInstance = hModule; [align=left] [/align] //创建事务 g_hSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL ); //重写API开头的8字节 HMODULE hWsock = LoadLibrary( "wsock32.dll" ); g_pSend = ( DWORD )GetProcAddress( hWsock, "send" ); [align=left][/align] [align=left] //保存原始字节[/align] ReadProcessMemory( INVALID_HANDLE_VALUE, ( void * )g_pSend, ( void * )g_dwOldBytes[0], sizeof( DWORD )*2, NULL ); //将00400000改写为我们函数的地址 *( DWORD* )( g_btNewBytes + 1 ) = ( DWORD )hook_send; WriteProcessMemory( INVALID_HANDLE_VALUE, ( void * )g_pSend, ( void * )g_btNewBytes, sizeof( DWORD )*2, NULL ); } return TRUE; } [align=left][/align] [align=left] 以上是dll的main函数,在被指定的程序加载的时候会自动运行dll的main函数来完成初始化,这里就是改写API的首地址来完成跳转。当然本程序 是对于指定程序进行Hook,如果要进行全局Hook,可以在main函数中用GetModuleFileName函数来获取exe文件完整路径,判断当 前进程是否是想要Hook的进程。写函数中使用INVALID_HANDLE_VALUE,表示写本进程。[/align] [align=left][/align] int _stdcall hook_send( SOCKET s, const char *buf, int len, int flags ) { int nRet; [align=left] WaitForSingleObject( g_hSendEvent, INFINITE );[/align] [align=left] [/align] //恢复API头8个字节 WriteProcessMemory( INVALID_HANDLE_VALUE, ( void* )g_pSend, ( void* )g_dwOldBytes[0], sizeof( DWORD )*2, NULL ); [align=left][/align] [align=left] /*[/align] [align=left] 这里可以添加想要进行的处理过程[/align] [align=left] */[/align] [align=left][/align] //真正执行API函数 nRet = send( s, buf, len, flags ); [align=left][/align] //写入跳转语句,继续Hook WriteProcessMemory( INVALID_HANDLE_VALUE, ( void* )g_pSend, ( void* )g_btNewBytes, sizeof( DWORD )*2, NULL ); [align=left][/align] [align=left] SetEvent( g_hSendEvent );[/align] [align=left][/align] return nRet; } [align=left][/align] HOOK_API BOOL StartHook(HWND hWnd) { //通过传入的窗口句柄获取线程句柄 g_dwThreadID = GetWindowThreadProcessId( hWnd, &g_dwProcessID ); [align=left][/align] //WH_CALLWNDPROC类型的Hook g_hOldHook = SetWindowsHookEx( WH_CALLWNDPROC, HookProc, [align=left] ( HINSTANCE ) g_hInstance, g_dwThreadID );[/align] if( g_hOldHook == NULL ) return FALSE; return TRUE; } [align=left][/align] static LRESULT WINAPI HookProc( int nCode, WPARAM wParam, LPARAM lParam ) { return CallNextHookEx( g_hOldHook, nCode, wParam, lParam ); } [align=left][/align] HOOK_API void StopHook(void) { if(g_hOldHook != NULL) { WaitForSingleObject( g_hSendEvent, INFINITE ); HANDLE hProcess = NULL; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, g_dwProcessID); DWORD dwOldProc; DWORD dwNewProc; [align=left][/align] //改变页面属性为读写 VirtualProtectEx( hProcess, ( void* )g_pSend, 8, PAGE_READWRITE, &dwOldProc ); [align=left][/align] //恢复API的首8个字节 WriteProcessMemory( hProcess, ( void* )g_pSend, ( void* )g_dwOldBytes[0], sizeof( DWORD )*2, NULL ); [align=left][/align] //恢复页面文件的属性 VirtualProtectEx( hProcess, ( void* )g_pSend, 8, dwOldProc, &dwNewProc ); CloseHandle(g_hSendEvent); UnhookWindowsHookEx( g_hOldHook ); } } [align=left][/align] [align=left] 可以看出,我们创建的Hook类型是WH_CALLWNDPROC类型,该类型的Hook在进程与系统一通信时就会被加载到进程空间,从而调用dll的 main函数完成真正的Hook,而在SetWindowsHookEx函数中指定的HookProc函数将不作任何处理,只是调用 CallNextHookEx将消息交给Hook链中下一个环节处理,因为这里SetWindowsHookEx的唯一作用就是让进程加载我们的dll。[/align] [align=left] 以上就是一个最简单的Hook API的例子,该种技术可以完成许多功能。例如网游外挂制作过程中截取发送的与收到的封包即可使用该方法,或者也可以在Hook到API后加入木马功能, 反向连接指定的主机或者监听某一端口,还有许多加壳也是用该原理来隐藏IAT表,填入自己的函数地址。[/align] |
相关文章推荐
- Windows下Hook API技术小结
- Windows下Hook API技术小结 (转)
- Windows下Hook API技术
- Windows下Hook API技术小结 (转)
- Windows下Hook API技术
- Windows下Hook API技术小结
- Windows下Hook API技术
- Windows下Hook API技术小结
- Windows管道技术 [转]
- 查找Windows内存泄露的工具与技术介绍
- “ Windows 激活技术 ” 将于近期推出在线更新以帮助用户远离 Windows 7 盗版风险
- Windows内核技术的精华站点
- 论Java加密技术与Windows的结合
- DirectX技术与Windows应用程序
- Windows下usb接口驱动技术
- windows 下iis与apache共存技术(IIS的网站用非80端口,也可以不用加端口号访问)
- 3.26关于Windows运维的那些事儿-51CTO技术沙龙回顾 推荐
- Windows下网络数据报的监听和拦截技术
- Windows内存隐藏技术初探
- 微软揭秘Windows 7虚拟XP模式技术细节