- 爱易网页
-
Windows教程
- Windows上怎么改写目标进程的窗口函数来注入DLL
日期:2014-05-17 浏览次数:20888 次
Windows下如何改写目标进程的窗口函数来注入DLL
Windows下如何改写目标进程的窗口函数来注入DLL
2011年02月21日
Windows的UI线程简单地说就是创建了窗口的线程,
其创建的窗口都有窗口函数,在这里,我介绍一个改写
UI线程窗口过程来注入DLL的方法,不需要调用VirtualAllocEx,也不需要GetThreadContext和SetThreadContext
对付一些常用的杀毒软件应该没有问题
一:获取一个进程的窗口句柄,例如Notepad.exe进程的主窗口类名是 "NOTEPAD"
通过 FindWindowW(L"NOTEPAD",NULL) 就可以得到运行的 Notepad.exe 的
主窗口的句柄设为 hWndNotepad, 通过 GetWindowThreadProcessId()
就可以获取到 创建该窗口的线程ID和Notepad.exe进程ID,通过 GetClassLongW(
hWndNotepad,GCL_WNDPROC)可以得到窗口过程函数地址。
代码大致如下:
HWND hWndNotepad = ::FindWindowW(L"NOTEPAD",NULL);
DWORD proID;
DWORD dThreadID = ::GetWindowThreadProcessId(hWndNotepad ,&proID);
HANDLE hPRocess = ::OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE ,FALSE,proID);
HANDLE hThread = ::OpenThread(THREAD_SUSPEND_RESUME,dThreadID);
//注意必须用UNICODE,否则取出来的不是窗口函数地址,而是一个HANDLE值
DWORD dWndProc = ::GetClassLongW(hWndNotepad,GCL_WNDPROC);
//更改窗口函数地址所在内存页面的控制标志,使之能够被覆盖
DWORD dpOld;
::VirtualProtectEx(hPRocess,LPVOID(dWndProc),8192, PAGE_EXECUTE_READWRITE,&dpOld)
二:创建注入的函数
typedef HMODULE (__stdcall *pLoadLibrary)(LPCSTR lpLibFileName);
//必须定义如下4个参数,否则目标线程会发生函数调用错误
LRESULT __stdcall test(HWND hwnd,UINT uMsg,WPARAM wPAram,LPARAM lParam)
{
//不能直接使用常量字符串,否则会引起目标进程读取数据异常。
char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d', 'l','l','\0'};
//必须用2088770939这个 LoadLibrary 函数的绝对地址(在我的xp下是这个地址,使用时应该在自己的windows下获取)
pLoadLibrary pFunc = pLoadLibrary(2088770939);
//调用LoadLibrary,因为LoadLibrary函数在windows下每个进程中绝对地址都是一样的。
pFunc(dllname);
return;
}
然后将目标线程挂起
::SuspendThread(hThread );
接着将目标窗口过程一部分或全部读出来
BYTE sCodes[1024];
DWORD dLen;
::ReadProcessMemory(hPRocess,(LPVOID)dWndProc,sCod es,1024, &dLen);
将目标窗口过程一部分或全部用我们的函数覆盖
::WriteProcessMemory(hProcess,pRemote,(LPVOID)test ,1024,&dWriten);
此时目标窗口函数已经被我们改写了,如果唤醒目标线程的话,单击TASKBAR上的记事本窗口
我们的dll就会被自动装载了,但此时目标线程的窗口过程已经无法恢复了,我们需要做恢复工作
恢复工作思路是 在装载的dll里DllMain函数编写代码获取到之前
备份的目标窗口函数的1024字节内容,将我们覆盖的1024字节恢复,同时调用
::SetClassLongW()替换窗口过程函数,让窗口过程恢复之前的工作。
如何获取呢?.....对了,使用共享内存,主控程序建立有名称的共享内存(FileMapping),将上述
数据写入共享内存中,恢复的时候就从共享内存中读取数据,代码如下:
HANDLE hfileMap = ::CreateFileMappingW(INVALID_HANDLE_VALUE,NULL,PAG E_READWRITE,\
0,4096,L"注入DLL的测试");
LPVOID lpAddr = ::MapViewOfFile(hfileMap,FILE_MAP_WRITE,0,0,4096)/ /映射整个4096字节范围。
//将窗口句柄写入
BYTE *pStart = (BYTE*)lpAddr;
memcpy(pStart,&hWndNotepad,sizeof(HWND));
pStart += sizeof(HWND);
//将备份的目标窗口函数的1024字节内容写入
memcpy(pStart,sCodes,1024);
//等待第三步创建好dll后,唤醒目标线程
::ResumeThread(hThread);
//发送windows消息使得目标线程执行覆盖的窗口函数
::SendMessage(hWndNotepad,99999999,0,0)
//注意不能立即结束控制进程,必须等待到dll装载后才能结束控制进程,否则
//之前创建的共享内存将不能够被映射,这里仅仅是调用Sleep
::Sleep(9999999);
三:编写我们的dll
#include
WNDPROC g_WndPRoc = 0;
LRESULT CALLBACK newWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ::CallWindowProcW(g_WndPRoc,hWnd,uMsg,wParam,lPara m); } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
{ if(DLL_PROCESS_ATTACH == ul_reason_for_call) { //不能调用messagebox等UI函数,这样会导致窗口过程函数重入,导致崩溃
//写log到文件中便于观察
HANDLE hFile = ::CreateFile("C:\\dllTest.log",GENERIC_READ|GENERI C_WRITE, \
FILE_SHARE_READ,NULL,OPEN_ALWAYS, \