转载:http://blog.sina.com.cn/s/blog_651cccf70100tkvb.html
上一篇博文《HOOK钩子教程》中,作者较为详细地讲述了如何使用HOOK,并举了一个例子:用HOOK拦截WM_CLOSE消息一次。
实际上,HOOK有多种用法,本文讲述其中一种:利用HOOK技术实现DLL远程进程注入。
远程进程注入,按照作者的理解,就是让其他进程替你并运行DLL中的代码。而上一篇博文中,作者讲到对其他进程安装钩子时,钩子的过程必须封装在DLL中,就是说HOOK的代码被执行的时候,目标进程实际上就是在执行DLL中的代码。于是注入的思路就有了,把要执行的函数封装在DLL中,同时把HookProc写在同一个DLL中,HOOK成功了之后,接收到消息的HookProc就会执行,于是就能执行想执行的代码了。
还有一个问题,那就是HookProc是回调函数,要等到有消息传来的时候才会被调用,而DLL注入要让线程主动执行DLL中的代码。那要怎么做呢?
其实也很简单,上一篇博文中,最后的例程里,DllMain给记事本主动发了一个WM_CLOSE消息,HookProc便被执行了。
完整的流程就出来了:
首先SetWindowsHookEx设置了钩子,然后PostMessage给目标进程发送消息,在HookProc中判断是不是这个消息,是就执行相应代码,并阻止该消息传递到目标进程,最后调用UnhookWindowsHookEx卸载钩子。
第二步中,要给目标进程发送一个消息,那到底应该发送什么消息才好呢?作者作了多次尝试,发现WM_KEYDOWN、WM_CREATE等消息均无效(估计是后面的参数没设置好,如果有知道具体原因的,欢迎在评论中留言讨论),而WM_CLOSE和WM_DESTROY能被捕获。作者在这里选择了WM_CLOSE。
接收到这个消息之后,HookProc便弹出一个MessageBox表示注入成功:
MessageBox(NULL,”This is a messagebox from notepad.exe”,”hook”,MB_OK);
所以整个HookProc的代码如下:
extern “C” __declspec(dllexport) LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam){if(nCode<0)return CallNextHookEx(hooker,nCode,wParam,lParam);tagMSG* msg;msg=(tagMSG*)lParam;if(nCode==HC_ACTION && (msg->message==WM_CLOSE)){if(handled==FALSE){handled=TRUE;MessageBox(NULL,”This is a messagebox from notepad.exe”,”hook”,MB_OK);}UnhookWindowsHookEx(hooker);msg->message=WM_NULL;return CallNextHookEx(hooker,nCode,wParam,(LPARAM)msg);}return CallNextHookEx(hooker,nCode,wParam,lParam);}
而DllMain则负责进行钩子的安装,所以整个DLL的代码如下:
// notepadhook.cpp : Defines the entry point for the DLL application.//
#include “stdafx.h”#include <stdio.h>#include <stdlib.h>HHOOK hooker;HWND notepadhandle;BOOL handled;extern “C” __declspec(dllexport) LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam);char* ConvertInttoChar(int i);
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){if(ul_reason_for_call==DLL_PROCESS_ATTACH){handled=FALSE;notepadhandle=FindWindow(“Notepad”,NULL);if(notepadhandle==NULL){printf(“Notepad Not Found.\n”);return TRUE;}hooker=SetWindowsHookEx(WH_GETMESSAGE,HookProc,(HINSTANCE)hModule,GetWindowThreadProcessId(notepadhandle,NULL));if(hooker){printf(“Hook Successfully.\nHookID:%d\n”,hooker);}else{printf(“Hook Failed.\nError:%d\n”,GetLastError());return TRUE;}PostMessage(notepadhandle,WM_CLOSE,0,0);}return TRUE;}
extern “C” __declspec(dllexport) LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam){if(nCode<0)return CallNextHookEx(hooker,nCode,wParam,lParam);tagMSG* msg;msg=(tagMSG*)lParam;if(nCode==HC_ACTION && (msg->message==WM_CLOSE)){if(handled==FALSE){handled=TRUE;MessageBox(NULL,”This is a messagebox from notepad.exe”,”hook”,MB_OK);}UnhookWindowsHookEx(hooker);msg->message=WM_NULL;return CallNextHookEx(hooker,nCode,wParam,(LPARAM)msg);}return CallNextHookEx(hooker,nCode,wParam,lParam);}
新建一个DLL工程,命名为notepadhook,如图:
在notepadhook.cpp中键入如上代码,编译连接得到notepadhook.dll。
新建一个C++ Source File,命名为hook:
键入如下代码以加载DLL:
#include <stdio.h>#include <windows.h>int main(){LoadLibrary(“notepadhook.dll”);getchar();return 1;} 编译连接得到hook.exe,将hook.exe与notepadhook.dll放在同一目录中,打开记事本,运行hook.exe,可以看到记事本中弹出了一个消息框,如图:
如上图所示,对话框是从记事本弹出的,说明注入已经成功。
至此,我们的DLL注入已经完成了,但是还有一些问题。就算我们把所有的printf去掉,也把getchar去掉而改成Sleep,打开程序依然会有一个黑框,根本没办法做到隐蔽。作者经查阅资料得知这是因为编译器给EXE加上了某些参数,作者的解决办法是用RADASM编写一个一样功能的EXE:
新建一个Win32 App工程,在Asm文件中键入如下代码:
.386.model flat, stdcalloption casemap :none ;case sensitive
include windows.incinclude kernel32.incincludelib kernel32.lib
assume cs:xCode
xCode segment.dataxDllName db ’notepadhook.dll’,0
.codestart:invoke LoadLibrary,offset xDllNameinvoke Sleep,1000invoke ExitProcess,NULLend start
编译构建得到exe,将exe与dll放到同一目录,运行记事本,运行EXE,发现黑框就没了,而且即使DLL有printf也不会出现黑框。
以上是《利用HOOK技术实现DLL远程进程注入》的全部内容,对于文中内容有疑问的,或有改进意见的,欢迎通过评论留言。(作者仅对X_TK博客中的评论进行回复,转载至其他论坛及博客的,本作者概不负责)。感谢您阅读本文。
