2014-12-06 51 views
3

我最近在做DLL注入工作,所以我在谷歌上做了一些關於它的研究 。現在我知道使用CreateRemoteThread是一個好方法。LoadLibrary上的CreateRemoteThread並獲取HMODULE

的ASLR(地址空間佈局隨機化,因爲Windows Vista中),使KERNEL32.DLL的 地址是隨機的,但是這並不影響整體,因爲在一個會話 中的所有進程kernel32.dll的基址只是 相同 - 直到操作系統重置。

所以這個代碼可能是安全正常:

void launchAndInject(const char* app, const char* dll) 
{ 
    STARTUPINFOA si = {0}; 
    si.cb = sizeof(si); 
    PROCESS_INFORMATION pi = {0}; 

    if (CreateProcessA(app, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) 
    { 
     LPVOID loadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA"); 
     if (loadLibrary == NULL) { 
      return; 
     } 
     SIZE_T len = ::strlen(dll) + 1; 
     LPVOID addr = VirtualAllocEx(pi.hProcess, NULL, len, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 
     if (addr == NULL) { 
      return; 
     } 
     if (!WriteProcessMemory(pi.hProcess, addr, dll, len, NULL)) { 
      return; 
     } 
     HANDLE th = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibrary, addr, 0, NULL); 
     WaitForSingleObject(th, INFINITE); 
     DWORD ret = 0; 
     GetExitCodeThread(th, &ret); 
     CloseHandle(th); 
     ResumeThread(pi.hThread); 
    } 
} 

注入線程的退出代碼只是 調用LoadLibrary返回的值,因此RET是加載DLL的只是HMODULE(在 子進程當然),它的作用像一個魔術,到目前爲止非常好。

我已經閱讀了許多關於DLL注入的項目,他們使用DLLMain來做很多 作業 - 比如創建線程或鉤子API等等。他們必須非常小心地執行這些操作,參考微軟的文檔「創建DLL的 的最佳實踐」,諸如創建線程的行爲可能導致 死鎖,「理想的DllMain將只是一個空的存根」,所以我不認爲 這是一個非常好的方法。

因此,獲取加載的DLL的HMODULE很重要。通過這個句柄,你可以使用CreateRemoteThread調用一個注入DLL的導出函數,做任何你想要的 ,不需要擔心加載器鎖定的事情。

不幸的是,上面只有代碼與32位進程,這是因爲 的線程的退出代碼的類型爲DWORD - 32位無符號整數,但 HMODULE是一個指針,也可以是64位。因此,在64位進程中,您可能會從GetExitCodeThread獲得一個 DWORD值0xeb390000,但實際上由LoadLibrary返回的HMODULE 是0x7feeb390000。 0xeb390000只是一個截斷的64bit 指針。

我們該如何解決這個問題?

回答

1

對於64位進程,我可以使用IPC(http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574%28v=vs.85%29.aspx)來取回HMODULE。

我要指出,並非每一個IPC機制可以DllMain中的作品,例如 管會引起死鎖,請參閱文檔「最佳實踐創建 的DLL」(http://download.microsoft.com/download/a/f/7/af7777e5-7dcd-4800-8a0a-b18336565f5b/DLL_bestprac.doc)微軟的,在KERNEL32通話功能。 dll(除了某些指定的 函數)將會正常。

我測試過共享內存(在Windows XP上使用SP3和Windows 7 64bit PRO),它的工作原理是 。

2

您可以假設所示的代碼很可能會工作,並且截斷的HMODULE在大多數情況下可能實際上是正常的,因爲模塊通常在進程地址空間中加載得足夠低,以至於無關緊要。儘管你可以通過調用EnumProcessModules()函數來跟蹤你的'破壞'示例代碼,但要確保代碼始終有效。如果返回的HMODULE出現在目標進程的進程模塊列表中,那麼您很好。如果不是,則需要迭代返回的HMODULE,並調用GetModuleBaseName()GetModuleFileNameEx(),直到找到注入的DLL。或者,如果您已經作爲自定義調試程序運行(無論如何我都會發現它很有用),那麼您可以匹配當您注入相應的LOAD_DLL_DEBUG_EVENT時加載的模塊,這些模塊將被報告WaitForDebugEvent()。這將爲您提供HMODULE(圖像的基礎)和圖像文件名稱,並且在您注入DLL後立即發生該事件。

個人而言,我會採取後一種方法,但在實踐中我還沒有看到截斷HMODULE從破碎返回代碼是什麼,但正確的,但我希望我只是很幸運和我依靠加載器加載進程地址空間中低的DLL。

+1

我的另一個問題:http://stackoverflow.com/questions/27331014/enumprocessmodulesex-and-createtoolhelp32snapshot-fails-whatever-32bit-or-64bi我不知道爲什麼EnumProcessModules不起作用。對於調試事件,我擔心性能。我最終選擇了IPC解決方案。 – amanjiang 2014-12-08 02:30:59

+1

有關爲什麼EnumProcessModules不起作用的答案:http://stackoverflow.com/a/27317947/996540 – amanjiang 2014-12-08 03:50:07

+0

這對知道有用。 – 2014-12-08 07:22:49