Skip to content

upx

一、 UPX 壳基础原理

UPX 是一种开源的可执行文件压缩工具,其主要目的是减小文件体积,而非提供强力的反调试或代码混淆保护。

  1. 区段结构变化:

    加壳后,原本的 PE(Portable Executable)或 ELF 文件区段会被重构。典型的 UPX 壳包含以下特征区段:

    • UPX0:在文件中占用大小通常为 0,但在内存中分配了较大的虚拟空间(Virtual Size)。这里用于存放解压后的原始代码和数据。

    • UPX1:包含压缩后的原始程序数据以及 UPX 的解压存根(Stub)代码。程序启动时,首先执行此处的存根代码。

    • UPX2(可选):通常用于存放资源文件(Resource)或导入表(Import Table)等信息。

  2. 执行流程:

    带壳程序的执行流如下:

    入口点 (EntryPoint) -> 执行 UPX 解压存根 -> 将 UPX1 中的数据解压至 UPX0 -> 恢复导入表 (IAT) -> 跳转至原始入口点 (OEP, Original Entry Point) -> 执行原程序


二、 UPX 壳的识别与特征

在分析未知二进制文件时,可通过以下特征快速判断是否加了 UPX 壳:

  1. 查壳工具检测:

    使用 Detect It Easy (DIE)、Exeinfo PE 或 PEiD 等静态分析工具,通常能直接识别出 "UPX"。

  2. 字符串与区段名:

    • 区段表(Section Table)中存在名为 .UPX0、.UPX1 的区段。

    • 文件内部存在明显的 UPX! 魔数字符串标志。

  3. 内存与体积特征:

    文件实际大小(Raw Size)远小于其在内存中展开的大小(Virtual Size)。


三、 标准 UPX 的自动化脱壳

对于未经任何修改的标准 UPX 壳,最简单且首选的方法是使用官方工具进行静态脱壳。

  • 脱壳命令:

    upx -d [被加壳文件名] -o [脱壳后的输出文件名]
    

    例如:upx -d task.exe -o task_unpacked.exe

  • 适用场景:文件头、区段名及内部特征标志未被破坏的常规题目。


四、 动态/手动脱壳技术(寻找 OEP)

当官方工具失效,或需要进行底层行为分析时,需采用动态调试器(如 x64dbg, OllyDbg)进行手动脱壳。手动脱壳的核心目标是找到 OEP(原始入口点)并转储(Dump)内存文件,最后修复导入表。

1. ESP 定律法

ESP 定律基于栈平衡原理。UPX 在执行解压代码前,会保存当前寄存器状态;在解压完成即将跳转到 OEP 时,会恢复这些状态。

  • 操作步骤:

    1. 程序载入调试器,停在入口点。

    2. 单步步过(F8)第一条指令(通常是 pushad 或 push eax 等),此时观察 ESP 寄存器的值发生变化。

    3. 在内存窗口中跳转到该 ESP 地址,设置硬件访问断点(Hardware Breakpoint on Access/Dword)。

    4. 运行程序(F9)。程序将在即将完成解压、恢复寄存器状态(popad)之后断下。

    5. 断下后,向下单步执行(F8),遇到大跨度的跳转指令(通常为 jmp),该跳转的目的地址即为 OEP。

2. 单步跟踪法

  • 操作步骤:

    1. 载入程序,使用单步步过(F8)向下执行。

    2. 核心原则:遇到向上的跳转(如循环)则在下一条指令处设断点并运行(F4),跳过循环;遇到向下的跳转则跟随。

    3. 最终会来到一个 popad 指令,随后跟随一个 jmp 指令跳转至 OEP。

3. 内存转储与 IAT 修复

到达 OEP 后,内存中的代码已解压完毕,但此时的文件无法直接保存运行,需要进行转储和修复:

  • Dump 内存:使用调试器插件(如 OllyDumpEx)将当前内存镜像保存为 PE 文件。

  • 修复 IAT:由于加壳程序破坏了原始的导入地址表(Import Address Table),需使用 Scylla 或 ImportREC 等工具:

    1. 附加当前调试进程。

    2. 填入刚刚找到的 OEP 相对虚拟地址(RVA)。

    3. 点击 "IAT Autosearch" 和 "Get Imports"。

    4. 点击 "Fix Dump",选择刚才 Dump 出的文件,生成修复后的最终程序。


五、 CTF 常见“魔改” UPX 及其修复策略

在 CTF 比赛中,出题人经常会对 UPX 壳进行轻微修改,导致 upx -d 命令报错(如提示 NotPackedException)。

  1. 抹除或篡改特征标志:

    • 现象:文件内部的 UPX! 魔数被替换成了其他字符(例如 CTF!、VMP! 等)。

    • 修复方案:使用十六进制编辑器(如 010 Editor、Hex Workshop)打开文件,搜索被篡改的特征字符串,将其全面替换回标准的 UPX!。

  2. 修改区段名称:

    • 现象:.UPX0 和 .UPX1 区段名被修改为随机乱码或 .text、.data 以伪装成无壳文件。

    • 修复方案:利用 PE 查看工具(如 CFF Explorer),在区段头部(Section Headers)将区段名手动修改回 UPX0 和 UPX1。

  3. 修复后处理:

    完成上述特征复原后,保存文件,再次尝试使用 upx -d 进行自动化脱壳,成功率会大幅提升。如果依然失败,则必须退回使用“手动脱壳(ESP 定律)”进行处理。