欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

DLL注入的几种姿势(二):CreateRemoteThread And More

来源:本站整理 作者:佚名 时间:2016-02-01 TAG: 我要投稿

关于这个系列其实有很多内容,并且在给出的实例都是自己编写的源码,在Open security和Infosec Institute中也有相关文章介绍。当然在这里有很多大牛讲的更加深入。我并不是想在这些人的基础上做补充,而是希望花时间去理解这些东西,这样才会更好的帮助我们提升自己。
0×01 远程线程注入方法CreateRemoteThread
在上一篇博客中,我们介绍了SetWindowsHookEx方法注入。这部分的工作已经做完了,但是看起来还不是很棒。为了向一个进程中注入一个想要运行的DLL,我们需要获得这个进程的线程ID,这样就可以注入到任何接收到hook信息的进程中。幸运的是,还有一种方法可以做到这点。在这篇文章中,我们将会尝试CreareRemoteThread方法。在SetWindowsHookEx中,我们使用LoadLibrary将DLL加载至当前进程(不是目标进程)的地址空间中。接着使用GetProcAddress获得所需函数的地址。下面的事情就交给SetWindowsHookEX了,我们构造一个钩子,钩取一个会自动加载我们DLL的进程,这样就搞定整个DLL注入过程了。而CreateRemoteThread则跟上述过程不一样,下面是其步骤:
    1. 使用VirtualAllocEx在目标进程的地址空间中创建一块我们DLL所在路径长度的内存空间。
    2. 使用WriteProcessMemory将DLL路径写入分配的内存。
    3. 一旦DLL路径写入内存中,再使用CreateRemoteThread(或者其他无正式说明的功能),它再调用LoadLibrary函数将DLL注入目标进程中。
0×02 Windows功能的暗点
在Windows中无正式说明的功能是指在微软当中没有详细文档介绍其信息的这些功能。这样在使用这些功能就会存在一些问题。最明显的问题就是没有一个特定功能的文档。不过在 ReactOS项目中对许多这种功能做了文档说明,而这篇文章则给了我们最直观的理解。此外在微软没有正式通过的情况先,这些功能可能最终会被“越界”使用。最后呢,他们都需要更多的代码,了解并需要正确使用。
试想一下这些问题,为何要使用这些无正式说明的功能?基本的原因就是自从Vista之后,如果目标进程不在当前会话中而是在一个不同的会话中,那么CreateRemoteThread将会失效。而这些无正式说明功能就不会。当然这个从逆向工程的角度也不会立即就能理解。最后这个只过是在Windows中一些不知名的功能中捣点小乱而已。
在我们的代码中,我们使用CreateRemote 线程和两个无正式说明的函数NtCreateThreadEx 和RtlCreateUserThread。也许你听说过Mimikatz 和 Metasploit。这两个都是使用RtlCreateUserThread来实现DLL注入的。如果你想看这些代码,Mimikatz可以在这里找到,Meterpreter则在这里。需要说明的是Mimikatz的博客是法语,如果有语言障碍则可以看这里。
那么这两个函数该挑选哪一个呢?NtCreateThreadEx是一个系统调用,是用户空间应用和内核打交道的方法。快速在IDA中查通过名字标签找到看一下RtlCreateUserThread。将ntdll.dll拖进IDA中,通过名字标签找到RtlCreateUserThread,进入其中,可以看到如下信息:
 

后面的代码看这里:
 

当你跟踪这段代码你会发现,RtlCreateUserThread调用NtCreateThreadEx 。因此RtlCreateUserThread应该是NtCreateThreadEx 的封装。我们想调用RtlCreateUserThread是因为NtCreateThreadEx 的系统调用选项可以在Windows版本间改变。因此,RtlCreateUserThread更好用一些。 Mimikatz 和Meterpreter使用RtlCreateUserThread是由于这个选项更加安全。
0×03 代码
对下面的代码进行一些改进,下面使用CreateRemoteThread方法一步步实现上述步骤:
1. 使用VirtualAllocEx在目标进程的地址空间中创建一块我们DLL所在路径长度的内存空间。
//This dll path should be relative to the target process or an absolute path
char* dll = "inject.dll";
//We need a handle to the process we will be injecting into
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
//Create the space needed for the dll we are going to be injecting
LPVOID lpSpace = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(dll), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
VirtualAlloc.c
2.使用WriteProcessMemory将DLL路径写入分配的内存
//Write inject.dll to memory of process
int n = WriteProcessMemory(hProcess, lpSpace, dll, strlen(dll), NULL);
WriteProcessMem.c
3. 一旦DLL路径写入内存中,再使用CreateRemoteThread(或者其他无正式说明的功能),它再调用LoadLibrary函数将DLL注入目标进程中。
HMODULE hModule = GetModuleHandle("kernel32.dll");
LPVOID lpBaseAddress = (LPVOID)GetProcAddress(hModule,"LoadLibraryA");
//Create Remote Thread using the address to LoadLibraryA and the space for the DLL
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, NULL, NULL);
CreateRemThread.c

远程线程DLL注入
下一步是使用这些无正式说明的功能代替CreateRemoteThread。首先需要调用这些函数。在CreateRemoteThread中,我们可以直接调用因为它是Windows API的一部分。而这些函数是不具备这个特点的,因此需要创建一个模板。那就从RtlCreateUserThread开始。首先使用相同的名字(没必要一定是相同的名字,但是这样会更加清楚一些)来创建这个方法。这个方法来声明这个函数的原型。这个原型需要和通过NtInternals给出的模板相匹配。接着创建线程的句柄,作为输入,RtlCreateUserThread的指针指向这个线程的句柄,并且将RtlCreateUserThread 设置成创建的线程的句柄。接着我们获取到ntdll.dll的句柄,正是RtlCreateUserThread保存的地方。在不同的DLL中的函数都可以被输出了,因此可以直接使用。在DLL中我们可以使同样的方法“__declspec(dllexport)”来输出函数。由于无正式说明的函数没有被输出,因此我们必须要获得其句柄并且得到地址。下一步则是使用GetProcAddress获得进程中的地址。最后调用,并且返回线程的句柄。模板如下:

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载