2014-12-06 53 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