45、PE文件修改实战:修改资源、修改导入表、添加节区、修改入口点

说实话,PE文件修改这事儿,是逆向工程里最“硬核”的活儿之一。你光会看反汇编还不够,得能动手改文件本身。我当年第一次改PE文件时,差点把一个系统DLL改废了——嗯,从那以后我就养成了“改之前先备份”的强迫症。

这一章,咱们直接上实战。四个核心操作:改资源、改导入表、加节区、改入口点。每个操作我都会讲清楚原理,再给实操步骤。你跟着走一遍,基本就能应付大部分PE修改场景了。

4.1 修改资源:给程序换个图标

资源修改是最常见的需求。比如你想把某个EXE的图标换成自己的,或者改掉它的版本信息。

实操步骤:

  1. Resource HackerRestorator 打开目标PE文件
  2. 找到 Icon 目录下的 1(通常是主图标)
  3. 右键选择“替换资源”,导入你的ICO文件
  4. 保存即可
我的经验: 替换图标后,如果程序运行报错“资源损坏”,多半是ICO格式不兼容。Windows只认标准ICO,别拿PNG改后缀糊弄它。

但如果你要批量改资源,或者程序有资源校验,就得用十六进制编辑器手动改了。资源数据在PE文件中的位置,可以通过 IMAGE_RESOURCE_DIRECTORY 结构定位。

4.2 修改导入表:让程序加载你的DLL

修改导入表,说白了就是让目标程序在启动时自动加载你指定的DLL。这是DLL注入的经典手法之一。

核心原理: PE文件的导入表记录了程序需要哪些DLL和函数。我们往这个表里加一条记录,程序启动时就会加载我们的DLL。

实操步骤:

  1. LordPECFF Explorer 打开PE文件
  2. 找到“导入表”选项卡
  3. 右键添加一个新的DLL条目,比如 MyHook.dll
  4. 添加你想劫持的函数,比如 MessageBoxA
  5. 保存文件
注意: 修改导入表后,如果目标程序有数字签名,签名会失效。另外,有些程序会校验导入表完整性,改了直接崩溃。

我曾经在分析一个恶意软件时,发现它通过修改系统DLL的导入表来实现持久化。它把自身DLL的路径写进了 kernel32.dll 的导入表里——这招够狠,但也很容易被安全软件检测到。

4.3 添加节区:给PE文件“加料”

添加节区,就是给PE文件新增一个段。这个段可以用来存放你的代码、数据,或者作为后续修改的“缓冲区”。

为什么需要加节区? 因为直接修改原有节区,可能会破坏文件对齐,或者空间不够。加一个新节区,干净利落。

实操步骤:

  1. 用十六进制编辑器打开PE文件
  2. 定位到节区表(Section Table),通常在PE头后面
  3. 在最后一个节区后面,添加一个新的 IMAGE_SECTION_HEADER 结构(40字节)
  4. 设置新节区的名称、虚拟大小、原始大小、属性(比如可读可写可执行)
  5. 在文件末尾追加新节区的数据
  6. 更新PE头中的 NumberOfSections 字段
关键点: 新节区的 VirtualAddress 必须是上一个节区 VirtualAddress + VirtualSize 向上对齐到 SectionAlignment 的值。文件偏移同理,要对齐到 FileAlignment

我习惯用 010 Editor 的PE模板来做这件事,它能自动计算对齐值,省得我手动算偏移。你想想看,要是算错一个字节,整个PE文件就废了。

4.4 修改入口点:劫持程序执行流

修改入口点(Entry Point),是让程序启动后先执行你的代码,再跳回原入口。这是代码注入的经典手法。

原理: PE头中的 AddressOfEntryPoint 字段指向程序的第一条指令。我们把它改成新节区中我们的代码地址,等我们的代码执行完,再跳回原入口。

实操步骤:

  1. 在新节区中写入你的Shellcode(比如弹个MessageBox)
  2. Shellcode末尾加上一条 jmp 指令,跳回原入口点
  3. 用十六进制编辑器修改PE头中的 AddressOfEntryPoint,指向新节区
  4. 保存文件
避坑指南: 我曾经写Shellcode时忘了保存原入口点地址,结果程序跑完我的代码后直接崩溃。后来我学乖了,在Shellcode开头先把原入口点压栈,最后 ret 回去。

下面这张图展示了修改入口点的完整流程:

原始PE文件 定位 AddressOfEntryPoint (PE头偏移 0x28) 修改为新节区地址 (指向Shellcode) 新节区写入Shellcode (含跳回原入口的jmp) 保存文件 (更新SizeOfImage等字段) 程序启动 → 执行Shellcode → 跳回原入口 修改入口点流程图 先改入口指向Shellcode,Shellcode执行完再跳回原入口

4.5 综合实战:给计算器加个“关于”弹窗

咱们把上面四个操作串起来,做个完整的例子。目标:修改Windows计算器(calc.exe),让它启动时弹个“Hello, Reverse!”的对话框。

步骤概览:

步骤 操作 工具
1 添加新节区 .mycode 010 Editor + PE模板
2 在新节区写入Shellcode(调用MessageBoxA) 汇编器 + 十六进制编辑器
3 修改入口点指向Shellcode 十六进制编辑器
4 修改导入表,添加 user32.dllMessageBoxA CFF Explorer
5 保存并测试 运行修改后的calc.exe
Shellcode示例(NASM语法):
; 新节区代码
push 0          ; MB_OK
push caption    ; "Title"
push message    ; "Hello, Reverse!"
push 0          ; hWnd
call MessageBoxA
; 跳回原入口
jmp original_entry

这里有个坑:MessageBoxA 的地址在Shellcode里不能写死,因为不同系统版本地址不同。我一般用导入表的方式,让PE加载器帮我们解析地址。说白了,就是让导入表里的 IAT 自动填好函数地址,Shellcode里直接call那个地址就行。

重要提醒: 修改后的calc.exe会被杀软报毒,因为修改入口点+添加节区是典型的病毒行为。测试时记得关掉实时防护,或者用虚拟机。

做完这步,你基本就掌握了PE修改的核心技能。以后遇到需要给程序“加料”的场景,不管是加功能还是做调试,都能游刃有余。


公众号:蓝海资料掘金营,微信deep3321