2014-03-30 47 views
10

如果你看看一个简单的DLL注入的以下工作代码:DLL注入用CreateRemoteThread

//Open the target process with read , write and execute priviledges 
    Process = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, ID); 

    //Get the address of LoadLibraryA 
    LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); 

    // Allocate space in the process for our DLL 
    Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll)+1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 

    // Write the string name of our DLL in the memory allocated 
    WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll)+1, NULL); 

    // Load our DLL 
    CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL); 

    //Let the program regain control of itself 
    CloseHandle(Process); 

的事情让我困惑的是,GetProcAddress回报LoadLibraryA温控功能地址当前进程,如何你可以通过它作为参数CreateRemoteThread和期望目标进程来运行它吗?

+0

由于CreateRemoteThread将'LoadLibrary'作为参数并对其进行调用。由于它也需要'Memory'作为参数,这是它传递给'LoadLibrary'的参数。 – Brandon

+0

这仍然无法解释为什么你需要当前进程**的'LoadLibrary'函数地址。 'Memory'是dll名称的地址,为什么不只是将'LoadLibrary'作为一个字符串传递,如果你只是想调用它? –

+2

因为在其他过程中的偏移量将完全相同。如果其他进程是x32并且进程是x32,则与kernel32的偏移量相同。如果您的进程是x64,而另一个进程是x64,则偏移量也是相同的。如果另一个进程是x32,而你的进程是x64,反之亦然,则偏移量将会不同,并且注入将失败。我相信User32.dll也始终加载在相同的偏移量。与Kernel32.dll类似 – Brandon

回答

15

它意外地工作。这是一个非常常见的意外,微软做出了很大的努力来确保操作系统DLL(如kernel32.dll)的基地址与任何其他DLL不冲突。进程初始化时,kernel32.dll进一步加强了进一步的加载,所以它必须争取得到它的首选基地址。

你会轻松逃脱。值得注意的是,这个在过去出现了错误,出现了XP安全更新哎呀,导致gdi32.dll重新定位,并导致大量机器在启动时崩溃。正确的方法是相当痛苦的,CreateToolhelp32Snapshot()+ Module32First/Next()找到重定位偏移并不是很大的喜悦。坦率地说,如果操作系统像这样“怪异”,你可能根本就不应该这样做。

+0

等待...所以它的工作原理是因为LoadLibrary满足LPTHREAD_START_ROUTINE签名并恰好在所有进程中的相同地址?所以DllMain在其他进程空间内被调用...我必须尝试它。 – Dmitry

2

LoadLibraryA住在kernel32.dll,这个模块总是被加载到每个进程中,并且恰好也被加载到每个进程中的相同地址。

+0

'LoadLibraryA ...碰巧也被加载到每个进程中的相同地址中'这个语句中是否有任何文档或引用? –

+0

也许,虽然我没有参考资料。由于ntdll.dll和kernel32.dll都是由Windows自动加载的,除了主exe以外的第一个两个模块,所以这两个模块的首选加载地址没有机会被别的东西占用。 –

+0

几个参考文献:http://blogs.msdn.com/b/calvin_hsia/archive/2007/07/27/dll-image-base-addresses-are-the-same-in-xp-different-on-vista .aspx和http://www.nynaeve.net/?p=198但最好从MSDN官方找到一些文档,而不仅仅是一些博客。 –

1

地址空间布局随机化(ASLR)是Windows处理的一种反攻击缓解功能,它允许地址重定位以帮助防止攻击者确定地址以利用内存中的某些东西(停止对地址/偏移量进行硬编码)。但是,Windows模块仅更改每个会话的地址。

如果你有一个使用kernel32.dll的进程(并非所有进程都使用kernel32.dll,我会在几分钟内进一步解释这一点),例程的地址可能是55AA1122作为一个例子(这是一个无效的示例地址)。现在,使用kernel32.dll的下一个进程将具有与之前相同的例程的55AA1122的相同地址....只有当这些进程都是相同的体系结构时。

32位进程与其他Windows模块导出(例如NTDLL,USER32等)也具有相同的kernel32.dll导出地址。对于32位进程,64位进程将具有不同的地址,但是64位进程也将具有与Windows模块相同的地址!

远程线程创建不是一个“意外”,微软有意实现它。为什么?微软在Windows本身使用它很多,也用于异步过程调用。微软也经常为他们自己的例程热补丁,作为一种反转技术,或者如果他们丢失了源代码到自己的项目,哈哈。

现在关于kernel32.dll被加载到进程中,它只被加载到使用Win32 API的进程中。这包括世界上99%的程序,但是可以编译一个不会使用它的本地进程。但是,这会强制您使用Native API,并且完全不使用Win32 API,并且名为smss.exe的Windows进程完全执行此操作。您也可以编译甚至没有正常的Win32 API DLL Entry例程的Native DLL。

简而言之,Windows模块例程的地址每次启动时都会更改一次。它将保持不变,直到下一次重新启动,等等。对于每个进程,32位进程都有自己的Windows模块共享地址,64位进程也是如此。因此,除非使用32位Kernel32.dll LoadLibraryA地址,否则不能使用64位进程的LoadLibraryA地址,同时将32位进程的DLL注入作为目标。不管怎样,更好的办法是使用LdrLoadDll,或者只是反射式DLL加载程序存根的shell代码注入。