【免杀研究】PE文件植入后门之CodeCave

admin 2025-12-22 00:37:09 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: CodeCave是一种隐蔽的PE文件后门植入技术,利用编译器在PE文件中生成的未使用字节区域注入恶意代码而不增加文件体积。文章详细介绍了其核心原理、实现效果及实操步骤,包括确定目标地址、准备Shellcode、寻找CodeCave、跳转到CodeCave、保存上下文、注入Shellcode、恢复上下文、恢复原始命令、注入返回跳转和保存补丁等步骤。这种技术可实现零体积增长、动态触发,具有一定免杀优势。 综合评分: 91 文章分类: 免杀,二进制安全,漏洞分析,红队,实战经验


cover_image

【免杀研究】PE文件植入后门之CodeCave

原创

红队安全圈

红队安全圈

2025年12月21日 15:12 重庆

Code Cave(代码洞穴)是一种隐蔽的PE文件后门植入技术。它利用编译器在PE文件中生成的未使用字节区域,如对齐填充、节区间隙,注入恶意代码而不增加文件体积,从而某些场景下规避静态检测

一、核心原理

通过分析PE文件的结构,找到合适的Codecave区域,将恶意代码或自定义功能代码注入其中。注入后,通过修改PE文件的控制流(如跳转指令、函数调用等),使程序在运行时能够执行注入的代码,同时尽量保持原程序的正常功能,避免程序崩溃

二、实现效果

  • • 零体积增长:后门隐藏于现有节区,文件大小与哈希值不变,规避一些特征码识别
  • • 动态触发:程序运行时自动执行恶意载荷(如反向连接、文件操作),而表面功能正常
  • • 免杀优势:传统添加新节区方法更容易被检测,CodeCave可一定程度降低发现概率

三、实操步骤

下面手把手演示操作,修改一个大家都很熟悉的 ssh 连接工具 putty.exe,在它里面植入计算器的 shellcode,受害者打开这个 putty.exe 的时候自动弹出计算器,实战中把计算器换成恶意后门的 shellcode

1. 确定目标地址(Hook Point)

在 xdbg 调试工具打开 PE 文件,确定程序中想植入后门逻辑的地址(例如,程序入口点 EP 或某个关键函数开头),观察程序流程,定位到目标指令地址(Hook_Addr),一般x32dbg打开程序会默认在入口点打了断点,在”Breakpoints”页面下直接双击断点就会跳转到”CPU”页面对应的位置,比如下图中的 0x00454AD0

记录这个地址和该地址以及下面几行的内容,Ctrl+C复制暂时保存到文本里,以便后续恢复

2. 准备 Shellcode

CS/MSF等生成payload,用脚本转成shellcode,这里以打开计算器为例

3. 寻找Code Cave(代码洞穴)

有很多小工具可以自动化发现 codecave,这里我为了演示原理,就手动查找

找到一段足够长的连续空闲内存区域来存放Shellcode,一般先在.text段中搜索,可以先通过MemoryMap页面找到程序的.text段,双击进入到CPU页面对应的位置

然后在CPU页面该位置处右键 -> searchfor -> CurrentRegion -> Pattern -> Hex输入框,搜索的很长串00字节,多按一些00,确保搜到的区域长度大于 shellcode 的长度。或者直接拉到CPU页面的最下面,程序的最后面通常可能会有未使用的空区域点击OK搜索后进入到References页面,可以看到搜索到了全是原程序未使用的代码洞穴区域,双击左侧的地址进入的CPU页面对应的位置

比如下图的 0x0045C961 就是代码洞穴的首行

4. 跳转到Code Cave

在第1步的hook地址那一行0x00454AD0,右键 Assemble (或者空格键) 输入jmp指令跳转到第3步获取到的代码洞穴,假设就跳转到代码洞穴的第一个的内存地址

jmp 0x0045C961

jmp命令需要占用5个字节,也就是原始的 0x00454AD0 到 0x00454AD4 处的内容被覆盖了,后续需要恢复

5. 保存上下文

在执行shellcode之前,先要在 Code Cave 的第一条指令处,右键 Assemble (或者空格键) 输入使用指令保存 CPU 状态,写下面两行,备份通用寄存器和标志寄存器的状态,注意64位的程序稍有不同

# 32位
pushad
pushfd

# 64位
64位需手动push
pushfq
6. 注入 Shellcode

将第2步准备好的 Shellcode 机器码写入CodeCave中,从上一步pushfd的下面一行开始,选中尽可能多的00行,右键 -> Binary -> Edit,把shellcode复制到Hex区域保存,可以加一些断点一步一步运行看看效果

可能出现的情况:

比如shellcode运行后,主程序突然直接结束了,xdebug的界面直接空白,这可能是shellcode结束时调用了类似exit退出的东西,导致整个程序直接结束,而没有继续运行后面的代码。因此需要找到具体是哪一步退出,在shellcode的汇编代码的部分找到所有的call调用,都打上断点,一步一步运行调试,看到哪一步调用导致程序退出

有个取巧的办法,直接跳过这个call调用,跳过让程序导致终止退出的代码。

下面这个例子,从顶部到0x0045CA20都属于刚刚复制进来的shellcode,然而经过测试运行到0x0045CA19这个call调用的时候,程序终止了,因此可以在它的前面,比如0045CA16这一行执行一个jmp语句,跳到下面的00区域:jmp 0x0045CA25,这样就不会执行那个导致程序终止的call,然后再进行后续的操作即可

注意由于强制jmp,属于非正常结束,提前脱离了 Code Cave 的执行流,要隔离后面的代码块,至少隔开1个空行(00),而不是紧接着的0x0045CA23,防止执行错误

为了保证最高的可靠性,一个健壮的 Code Cave 注入结构应该始终包含清晰的阶段划分,这样做的效果是:

  1. 1. 强制对齐: 确保 Shellcode 结束后,指令指针指向的第一个有效指令是 popfd
  2. 2. 防止截断: 避免 Shellcode 的最后一条机器码不小心“溢出”到 popfd 的第一个字节

7. 恢复上下文

在 Shellcode 执行完毕后,要恢复 CPU 的原始状态,紧接第6步在shellcode的下面(Code Cave区域)恢复通用寄存器和标志寄存器的状态,写下面两行

# 32位
popfd
popad

# 64位
popfq
64位需手动pop

8. 恢复原始命令

在shellcode和恢复CPU状态的末尾,也就是第7步的最下面插入原始命令,因为第4步在原Hook_Addr地址插入jmp(5个字节)跳转语句时覆盖了两行内容,现在要还原回去

多选中要修改的空白行,右键Binary -> Edit,在Hex输入框粘贴原始的Hex值,即第1步中备份的内容

9. 注入返回跳转

首先要确定跳回去的内存地址,hook地址从 0x00454AD0 开始jmp(5个字节),返回地址本应该是 0x00454AD5,但原始指令没有 0x00454AD5 和 0x00454AD6,由于指令修复的原因,返回跳转的地址就是 00454AD7

正确的 原始返回地址 = Hook地址 + JMP补丁长度(5字节) + 跳过未使用的字节

所以紧接着第8步,写一条jmp跳转,跳转到原程序流程,将控制权还给原始程序,确保原始程序流程逻辑不被破坏

jmp 0x00454AD7

10. 保存补丁

在CPU页面右键选择 Patchs,点击Select All 全选,点击Patch File 保存为新的 EXE 文件,这样就将所有的修改(Hook_Addr 处的 JMP 和 Cave_Addr 处的代码等等)永久写入磁盘文件

最终输出的新文件就是被注入了 shellcode 的 putty.exe,发给受害者运行,对方打开的时候自动运行恶意后门,同时原 putty 的功能不受影响

获取更多红队实战技巧

欢迎关注红队安全圈👇

如果我的文章对你有帮助,期待一键三连😄


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:红队安全圈 红队安全圈《

评论:0   参与:  3