|
|
[bgcolor=#f5f5f5]其创建的窗口都有窗口函数,在这里,我介绍一个改写[/bgcolor]
[bgcolor=#f5f5f5]UI线程窗口过程来注入DLL的方法:[/bgcolor]
[bgcolor=#f5f5f5]一:获取一个进程的窗口句柄,例如Notepad.exe进程的主窗口类名是 “NOTEPAD”[/bgcolor]
[bgcolor=#f5f5f5] 通过 FindWindowW(L"NOTEPAD",NULL) 就可以得到运行的 Notepad.exe 的[/bgcolor]
[bgcolor=#f5f5f5] 主窗口的句柄设为 hWndNotepad, 通过 GetWindowThreadProcessId()[/bgcolor]
[bgcolor=#f5f5f5] 就可以获取到 创建该窗口的线程ID和Notepad.exe进程ID,通过 GetClassLongW([/bgcolor]
[bgcolor=#f5f5f5] hWndNotepad,GCL_WNDPROC)可以得到窗口过程函数地址。[/bgcolor]
[bgcolor=#f5f5f5] 代码大致如下:[/bgcolor]
[bgcolor=#f5f5f5] HWND hWndNotepad = ::FindWindowW(L"NOTEPAD",NULL);[/bgcolor]
[bgcolor=#f5f5f5] DWORD proID;[/bgcolor]
[bgcolor=#f5f5f5] DWORD dThreadID = ::GetWindowThreadProcessId(hWndNotepad ,&proID);[/bgcolor]
[bgcolor=#f5f5f5] HANDLE hPRocess = ::OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE ,FALSE,proID);[/bgcolor]
[bgcolor=#f5f5f5] HANDLE hThread = ::OpenThread(THREAD_ALL_ACCESS,dThreadID);[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //注意必须用UNICODE,否则取出来的不是窗口函数地址,而是一个HANDLE值[/bgcolor]
[bgcolor=#f5f5f5] DWORD dWndProc = ::GetClassLongW(hWndNotepad,GCL_WNDPROC); [/bgcolor]
[bgcolor=#f5f5f5] //更改窗口函数地址所在内存页面的控制标志,使之能够被覆盖[/bgcolor]
[bgcolor=#f5f5f5] DWORD dpOld;[/bgcolor]
[bgcolor=#f5f5f5] ::VirtualProtectEx(hPRocess,LPVOID(dWndProc),8192,PAGE_EXECUTE_READWRITE,&dpOld)[/bgcolor]
[bgcolor=#f5f5f5]二:创建注入的函数[/bgcolor]
[bgcolor=#f5f5f5] typedef HMODULE (__stdcall *pLoadLibrary)(LPCSTR lpLibFileName);[/bgcolor]
[bgcolor=#f5f5f5] //必须定义如下4个参数,否则目标线程会发生函数调用错误[/bgcolor]
[bgcolor=#f5f5f5] void test(HWND hwnd,UINT uMsg,WPARAM wPAram,LPARAM lParam)[/bgcolor]
[bgcolor=#f5f5f5] {[/bgcolor]
[bgcolor=#f5f5f5] //不能直接使用常量字符串,否则会引起目标进程读取数据异常。[/bgcolor]
[bgcolor=#f5f5f5] char dllname[] = {'c',':','\\','d','l','l','t','e','s','t','.','d','l','l','\0'};[/bgcolor]
[bgcolor=#f5f5f5] //必须用2088770939这个 LoadLibrary 函数的绝对地址(在我的xp下是这个地址,使用时应该在自己的windows下获取)[/bgcolor]
[bgcolor=#f5f5f5] pLoadLibrary pFunc = pLoadLibrary(2088770939);[/bgcolor]
[bgcolor=#f5f5f5] //调用LoadLibrary,因为LoadLibrary函数在windows下每个进程中绝对地址都是一样的。[/bgcolor]
[bgcolor=#f5f5f5] pFunc(dllname);[/bgcolor]
[bgcolor=#f5f5f5] return;[/bgcolor]
[bgcolor=#f5f5f5] }[/bgcolor]
[bgcolor=#f5f5f5] 然后将目标线程挂起,取得其当前的CPU CONTEXT(注意,我们的注入控制程序仅仅获取,并不设置),[/bgcolor]
[bgcolor=#f5f5f5] ::SuspendThread(hThread );[/bgcolor]
[bgcolor=#f5f5f5] CONTEXT context;[/bgcolor]
[bgcolor=#f5f5f5] memset(&context,0,sizeof(context));[/bgcolor]
[bgcolor=#f5f5f5] context.ContextFlags = CONTEXT_CONTROL;[/bgcolor]
[bgcolor=#f5f5f5] ::GetThreadContext(hThread,&context);[/bgcolor]
[bgcolor=#f5f5f5] 接着将目标窗口过程一部分或全部读出来[/bgcolor]
[bgcolor=#f5f5f5] BYTE sCodes[1024];[/bgcolor]
[bgcolor=#f5f5f5] DWORD dLen;[/bgcolor]
[bgcolor=#f5f5f5] ::ReadProcessMemory(hPRocess,(LPVOID)dWndProc,sCodes,1024, &dLen);[/bgcolor]
[bgcolor=#f5f5f5] 将目标窗口过程一部分或全部用我们的函数覆盖[/bgcolor]
[bgcolor=#f5f5f5] ::WriteProcessMemory(hProcess,pRemote,(LPVOID)test,1024,&dWriten);[/bgcolor]
[bgcolor=#f5f5f5] 此时目标窗口函数已经被我们改写了,如果唤醒目标线程的话,单击TASKBAR上的记事本窗口[/bgcolor]
[bgcolor=#f5f5f5] 我们的dll就会被自动装载了,但此时目标线程的窗口过程已经无法恢复了,我们需要做恢复工作[/bgcolor]
[bgcolor=#f5f5f5] 恢复工作思路是 在装载的dll里DllMain函数编写代码获取到之前保存的CPU CONTEXT数据和[/bgcolor]
[bgcolor=#f5f5f5] 备份的目标窗口函数的1024字节内容,将我们覆盖的1024字节恢复,同时调用[/bgcolor]
[bgcolor=#f5f5f5] SetThreadContext()产生时光倒流,让窗口过程恢复之前的工作。[/bgcolor]
[bgcolor=#f5f5f5] 如何获取呢?.....对了,使用共享内存,主控程序建立有名称的共享内存(FileMapping),将上述[/bgcolor]
[bgcolor=#f5f5f5] 数据写入共享内存中,恢复的时候就从共享内存中读取数据,代码如下:[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] HANDLE hfileMap = ::CreateFileMappingW(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,\[/bgcolor]
[bgcolor=#f5f5f5] 0,4096,L"注入DLL的测试");[/bgcolor]
[bgcolor=#f5f5f5] LPVOID lpAddr = ::MapViewOfFile(hfileMap,FILE_MAP_WRITE,0,0,4096)//映射整个4096字节范围。[/bgcolor]
[bgcolor=#f5f5f5] //将窗口句柄写入[/bgcolor]
[bgcolor=#f5f5f5] BYTE *pStart = (BYTE*)lpAddr;[/bgcolor]
[bgcolor=#f5f5f5] memcpy(pStart,&hWndNotepad,sizeof(HWND));[/bgcolor]
[bgcolor=#f5f5f5] //将CPU Context写入[/bgcolor]
[bgcolor=#f5f5f5] pStart += sizeof(HWND);[/bgcolor]
[bgcolor=#f5f5f5] memcpy(pStart,&context,sizeof(CONTEXT));[/bgcolor]
[bgcolor=#f5f5f5] //将备份的目标窗口函数的1024字节内容写入[/bgcolor]
[bgcolor=#f5f5f5] pStart += sizeof(CONTEXT);[/bgcolor]
[bgcolor=#f5f5f5] memcpy(pStart,sCodes,1024);[/bgcolor]
[bgcolor=#f5f5f5] //等待第三步创建好dll后,唤醒目标线程[/bgcolor]
[bgcolor=#f5f5f5] ::ResumeThread(hThread);[/bgcolor]
[bgcolor=#f5f5f5] //发送windows消息使得目标线程执行覆盖的窗口函数[/bgcolor]
[bgcolor=#f5f5f5] ::SendMessage(hWndNotepad,99999999,0,0)[/bgcolor]
[bgcolor=#f5f5f5] //注意不能立即结束控制进程,必须等待到dll装载后才能结束控制进程,否则[/bgcolor]
[bgcolor=#f5f5f5] //之前创建的共享内存将不能够被映射,这里仅仅是调用Sleep[/bgcolor]
[bgcolor=#f5f5f5] ::Sleep(9999999);[/bgcolor]
[bgcolor=#f5f5f5]三:编写我们的dll[/bgcolor]
[bgcolor=#f5f5f5] #include <windows.h>[/bgcolor]
[bgcolor=#f5f5f5] BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved[/bgcolor]
[bgcolor=#f5f5f5] {[/bgcolor]
[bgcolor=#f5f5f5] if(DLL_PROCESS_ATTACH == ul_reason_for_call)[/bgcolor]
[bgcolor=#f5f5f5] {[/bgcolor]
[bgcolor=#f5f5f5] //不能调用messagebox等UI函数,这样会导致窗口过程函数重入,导致崩溃[/bgcolor]
[bgcolor=#f5f5f5] //写log到文件中便于观察[/bgcolor]
[bgcolor=#f5f5f5] HANDLE hFile = ::CreateFile("C:\\dllTest.log",GENERIC_READ|GENERIC_WRITE, \[/bgcolor]
[bgcolor=#f5f5f5] FILE_SHARE_READ,NULL,OPEN_ALWAYS, \[/bgcolor]
[bgcolor=#f5f5f5] FILE_ATTRIBUTE_NORMAL,NULL);[/bgcolor]
[bgcolor=#f5f5f5] //移动文件指针到文件尾[/bgcolor]
[bgcolor=#f5f5f5] ::SetFilePointer(hFile,0,0,FILE_END)[/bgcolor]
[bgcolor=#f5f5f5] DWORD dLen;[/bgcolor]
[bgcolor=#f5f5f5] const char *pData = "this is a test \r\n";[/bgcolor]
[bgcolor=#f5f5f5] ::WriteFile(hFile,pData ,strlen(pData ),&dLen,NULL);[/bgcolor]
[bgcolor=#f5f5f5] ::CloseHandle(hFile);[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //下面是恢复的工作[/bgcolor]
[bgcolor=#f5f5f5] HANDLE hfileMap = ::OpenFileMappingW(FILE_MAP_READ,FALSE,L"注入DLL的测试");[/bgcolor]
[bgcolor=#f5f5f5] LPVOID lpAddr = ::MapViewOfFile(hfileMap,FILE_MAP_READ,0,0,4096)//映射整个4096字节范围。[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //取出恢复工作需要的数据[/bgcolor]
[bgcolor=#f5f5f5] HWND hWndMain;[/bgcolor]
[bgcolor=#f5f5f5] CONTEXT context;[/bgcolor]
[bgcolor=#f5f5f5] BYTE sCodes[1024];[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] BYTE* pStart = (BYTE*)lpAddr;[/bgcolor]
[bgcolor=#f5f5f5] memcpy(&hWndMain,pStart,sizeof(HWND));[/bgcolor]
[bgcolor=#f5f5f5] pStart += sizeof(HWND);[/bgcolor]
[bgcolor=#f5f5f5] memcpy(&context,pStart,sizeof(CONTEXT ));[/bgcolor]
[bgcolor=#f5f5f5] pStart += sizeof(CONTEXT );[/bgcolor]
[bgcolor=#f5f5f5] memcpy(sCodes,pStart,1024);[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //释放共享内存[/bgcolor]
[bgcolor=#f5f5f5] ::UnmapViewOfFile(lpAddr);[/bgcolor]
[bgcolor=#f5f5f5] ::CloseHandle(hfileMap);[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //这里仅仅在dllMain里做恢复,或许不妥,最好的[/bgcolor]
[bgcolor=#f5f5f5] //办法是创建一个线程,在线程里恢复,因为[/bgcolor]
[bgcolor=#f5f5f5] //memcpy((LPVOID)wndProc,sCodes,1024); 可能会导致下面的代码应经不存在了(微笑)[/bgcolor]
[bgcolor=#f5f5f5] //只是可能,就看dllMain函数与窗口函数的偏移量是多少了,应该大于1024字节的。[/bgcolor]
[bgcolor=#f5f5f5] [/bgcolor]
[bgcolor=#f5f5f5] //恢复窗口函数1024个字节内容[/bgcolor]
[bgcolor=#f5f5f5] WNDPROC wndProc = ::GetClassLongW(hWndMain,GCL_WNDPROC);[/bgcolor]
[bgcolor=#f5f5f5] memcpy((LPVOID)wndProc,sCodes,1024);[/bgcolor]
[bgcolor=#f5f5f5] //设置线程Context结构,产生时光倒流[/bgcolor]
[bgcolor=#f5f5f5] DWORD proID;[/bgcolor]
[bgcolor=#f5f5f5] DWORD dThreadID = ::GetWindowThreadProcessId(hWndMain,&proID);[/bgcolor]
[bgcolor=#f5f5f5] HANDLE hThread = ::OpenThread(THREAD_ALL_ACCESS,dThreadID);[/bgcolor]
[bgcolor=#f5f5f5] ::SetThreadConText(hThread,&Context);[/bgcolor]
[bgcolor=#f5f5f5] }[/bgcolor]
[bgcolor=#f5f5f5] }[/bgcolor]
|
|