- 爱易网页
- 
                            Windows教程
- Windows上怎么改写目标进程的窗口函数来注入DLL 
日期:2014-05-17  浏览次数:21025 次 
                    
                        
                         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, \