Communitygithub.com

使用 UPX Unpacker 分析加壳恶意软件

识别并解包 UPX 加壳的恶意软件样本,包括经过修改的二进制文件(如篡改 UPX 魔数或头部信息导致自动解压失败),以恢复原始可执行文件进行静态分析。当样本呈现高熵、导入表极少或仅包含 LoadLibrary/GetProcAddress 时,或者在为 Ghidra 或 IDA 反汇编准备加壳二进制文件时使用。

使用 UPX Unpacker 分析加壳恶意软件 是什么?

该技能专门用于分析和解包 UPX 加壳的恶意软件。核心功能是识别加壳二进制文件,并利用自动和手动方法恢复原始可执行文件。当标准解包工具(如 upx -d)因恶意软件作者篡改 UPX 魔数(“UPX!”)或 PE 节名称而失败时,此技能尤其有效。它提供了全面的工作流程,包括:使用 Detect It Easy 和 Python 脚本进行加壳识别、标准 UPX 解包、基于 Python 的头部修复以恢复被篡改的魔数、使用 x64dbg 和 Scylla 进行手动动态解包,以及验证解包后的二进制文件以确保其有效且完整(检查节熵、导入表和文件大小)。该技能适用于 Windows PE 文件,并依赖 UPX、Detect It Easy(DIE)、x64dbg、Scylla 和 PE-bear 等工具。其主要优势在于,它通过结合自动修复技术和手动调试技术,系统性地处理现实世界中恶意软件的加壳情况,即使是针对经过精心修改的样本,也能恢复可分析的二进制文件。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/analyzing-packed-malware-with-upx-unpacker

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

使用 UPX Unpacker 分析加壳恶意软件 是做什么的?

使用时机

  • 静态分析显示高熵节且导入表极少,表明二进制文件被加壳
  • PEiD、Detect It Easy 或 PEStudio 识别出 UPX 或其他已知加壳器
  • 导入表仅包含 LoadLibrary 和 GetProcAddress(加壳二进制文件典型的运行时导入解析)
  • 您需要恢复原始二进制文件,以便在 Ghidra 或 IDA 中进行正确的反汇编和反编译
  • 因恶意软件作者修改了 UPX 魔数或头部信息,自动 UPX 解压缩失败

请勿使用于处理自定义加壳器、基于 VM 的保护程序(Themida、VMProtect)或更适合通过调试进行动态脱壳的样本。

前置条件

  • 已安装 UPX(可执行文件终极打包工具)(apt install upx-ucl 或从 https://upx.github.io/ 下载)
  • Detect It Easy (DIE) 用于加壳器识别
  • Python 3.8+ 及 pefile 库,用于手动头部修复
  • x64dbg 或 x32dbg,用于当自动化工具失败时进行手动脱壳
  • PE-bear 或 CFF Explorer,用于 PE 头部检查和修复
  • 无网络连接的隔离分析虚拟机

工作流程

第 1 步:识别加壳器

确定样本是否被加壳并识别加壳器:

# 使用 Detect It Easy 检查
diec suspect.exe

# 使用 UPX 检查(测试而不解包)
upx -t suspect.exe

# 基于 Python 的熵和加壳器检测
python3 << 'PYEOF'
import pefile
import math

pe = pefile.PE("suspect.exe")

print("节分析:")
for section in pe.sections:
    name = section.Name.decode().rstrip('\x00')
    entropy = section.get_entropy()
    raw = section.SizeOfRawData
    virtual = section.Misc_VirtualSize
    print(f"  {name:8s} 熵: {entropy:.2f}  原始大小: {raw:>8}  虚拟大小: {virtual:>8}")

# 检查 UPX 节名称
section_names = [s.Name.decode().rstrip('\x00') for s in pe.sections]
if 'UPX0' in section_names or 'UPX1' in section_names:
    print("\n[!] 检测到 UPX 节名称")
elif '.upx' in [s.lower() for s in section_names]:
    print("\n[!] 检测到 UPX 变种节名称")

# 检查导入数量(加壳二进制文件通常很少)
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
    total_imports = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT)
    print(f"\n导入总数: {total_imports}")
    if total_imports < 10:
        print("[!] 导入非常少 - 可能已加壳")
else:
    print("\n[!] 无导入目录 - 高度加壳")
PYEOF

第 2 步:尝试标准 UPX 解压缩

尝试内置的 UPX 解压缩:

# 标准 UPX 解压缩
upx -d suspect.exe -o unpacked.exe

# 如果 UPX 报错 "not packed by UPX",则头部可能已被修改
# 启用详细输出以进行调试
upx -d suspect.exe -o unpacked.exe -v 2>&1

# 验证解包后的文件
file unpacked.exe
diec unpacked.exe

第 3 步:修复被修改的 UPX 头部

如果标准解压缩失败,则修复被篡改的魔数:

# 修复被修改的 UPX 头部
import struct

with open("suspect.exe", "rb") as f:
    data = bytearray(f.read())

# UPX 魔数: "UPX!" (0x55505821)
# 恶意软件作者通常会修改这些内容以防止自动解包

# 搜索被修改的 UPX 签名
upx_magic = b"UPX!"
modified_patterns = [b"UPX0", b"UPX\x00", b"\x00PX!", b"UPx!"]

# 查找并恢复节名称
pe_offset = struct.unpack_from("<I", data, 0x3C)[0]
num_sections = struct.unpack_from("<H", data, pe_offset + 6)[0]
section_table_offset = pe_offset + 0x18 + struct.unpack_from("<H", data, pe_offset + 0x14)[0]

print(f"PE 偏移: 0x{pe_offset:X}")
print(f"节数量: {num_sections}")
print(f"节表偏移: 0x{section_table_offset:X}")

for i in range(num_sections):
    offset = section_table_offset + (i * 40)
    name = data[offset:offset+8]
    print(f"节 {i}: {name}")

# 恢复二进制文件中的 UPX 魔数
# 搜索 UPX 头部签名位置(通常在加壳数据末尾附近)
for i in range(len(data) - 4):
    if data[i:i+3] == b"UPX" and data[i+3] != ord("!"):
        print(f"在偏移 0x{i:X} 处发现被修改的 UPX 魔数: {data[i:i+4]}")
        data[i:i+4] = b"UPX!"
        print(f"已恢复为: UPX!")

# 如果被修改,也恢复节名称
for i in range(num_sections):
    offset = section_table_offset + (i * 40)
    name = data[offset:offset+8].rstrip(b'\x00')
    if name in [b"UPX0", b"UPX1", b"UPX2"]:
        continue  # 已正确
    # 检查常见修改
    if name.startswith(b"UP") or name.startswith(b"ux"):
        original = f"UPX{i}".encode().ljust(8, b'\x00')
        data[offset:offset+8] = original
        print(f"已将 0x{offset:X} 处的节名称恢复为 {original}")

with open("suspect_fixed.exe", "wb") as f:
    f.write(data)

print("\n已写入修复后的文件。重试: upx -d suspect_fixed.exe -o unpacked.exe")

第 4 步:使用调试器手动脱壳

当自动化解包完全失败时,使用动态脱壳:

使用 x64dbg 手动 UPX 脱壳:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 在 x64dbg 中加载加壳样本
2. 运行到入口点(系统断点,然后按 F9)
3. UPX 脱壳存根模式:
   a. PUSHAD(保存所有寄存器)
   b. 解压缩循环(处理加壳节)
   c. 解析导入(LoadLibrary/GetProcAddress 调用)
   d. POPAD(恢复寄存器)
   e. JMP 到 OEP(原始入口点)
4. 在 PUSHAD 后对 ESP 设置硬件断点:
   - PUSHAD 后,右键单击寄存器中的 ESP -> 在转储中跟随
   - 在 [ESP] 地址处设置硬件访问断点
   - 运行 (F9) - 将在 JMP 到 OEP 之前的 POPAD 处中断
5. 单步向前 (F7/F8) 直到到达 JMP 到 OEP
6. 在 OEP 处:使用 Scylla 插件转储并修复导入:
   - 插件 -> Scylla -> OEP = 当前 EIP
   - 点击 "IAT Autosearch" -> "Get Imports"
   - 点击 "Dump" 保存解包后的二进制文件
   - 点击 "Fix Dump" 修复导入表

第 5 步:验证解包后的二进制文件

验证解包后的样本是否有效且完整:

# 验证解包后的 PE 文件是否有效
python3 << 'PYEOF'
import pefile

pe = pefile.PE("unpacked.exe")

# 检查节是否正常
print("解包后的节分析:")
for section in pe.sections:
    name = section.Name.decode().rstrip('\x00')
    entropy = section.get_entropy()
    print(f"  {name:8s} 熵: {entropy:.2f}")

# 验证导入是否已解析
print(f"\n导入数量:")
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
    for entry in pe.DIRECTORY_ENTRY_IMPORT:
        dll = entry.dll.decode()
        count = len(entry.imports)
        print(f"  {dll}: {count} 个函数")
    total = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT)
    print(f"  总数: {total} 个导入")

# 比较文件大小
import os
packed_size = os.path.getsize("suspect.exe")
unpacked_size = os.path.getsize("unpacked.exe")
print(f"\n加壳后:   {packed_size:>10} 字节")
print(f"解包后: {unpacked_size:>10} 字节")
print(f"比例:    {unpacked_size/packed_size:.1f}x")
PYEOF

关键概念

术语定义
加壳压缩或加密可执行代码以减小文件大小并阻碍静态分析;二进制文件包含一个在运行时恢复代码的脱壳存根
UPX可执行文件终极打包工具;开源可执行文件加壳器,由于免费且有效,常被恶意软件作者滥用
原始入口点 (OEP)加壳前恶意软件代码的真实起始地址;脱壳存根解压代码后跳转到 OEP
导入重建在将脱壳后的进程从内存中转储后,使用 Scylla 或 ImpRec 等工具重建导入地址表的过程
PUSHAD/POPAD用于保存/恢复所有通用寄存器的 x86 指令;UPX 使用此模式在脱壳期间保持寄存器状态
节熵PE 节数据的随机性度量;加壳节的熵 > 7.0,而普通代码节平均为 5.0-6.5
魔数文件内标识其格式的签名字节;UPX 使用 “UPX!”,恶意软件作者会修改它以阻止自动解压缩

工具与系统

  • UPX:开源可执行文件加壳器,具有内建的解压缩能力,用于正确处理加壳的文件
  • Detect It Easy (DIE):加壳器、编译器和链接器检测工具,可识别 PE、ELF 和 Mach-O 文件上的保护
  • x64dbg/x32dbg:开源 Windows 调试器,通过动态执行和基于断点的 OEP 查找,用于手动脱壳
  • Scylla:与 x64dbg 集成的导入重建工具,用于在内存转储后重建 IAT
  • PE-bear:PE 文件查看器和编辑器,用于在脱壳后检查和修复 PE 头部

常见场景

场景:解包具有被修改 UPX 头部的恶意软件

上下文:某个恶意软件样本被节名称(UPX0、UPX1)识别为 UPX 加壳,但 upx -d 失败并显示 “CantUnpackException: header corrupted”。恶意软件作者修改了 UPX 魔数以防止自动解压缩。

方法:

  1. 在十六进制编辑器中打开二进制文件,搜索 UPX 头部区域(通常在加壳数据的末尾)
  2. 识别被修改的魔数(例如,“UPX!” 更改为 “UPX\x00” 或完全归零)
  3. 使用 Python 修复脚本恢复 “UPX!” 魔数并更正节名称
  4. 在修复后的二进制文件上重试 upx -d
  5. 如果修复失败,则回退到使用 x64dbg 进行手动脱壳(PUSHAD -> 对 ESP 设置硬件断点 -> POPAD -> JMP OEP)
  6. 验证解包后的二进制文件具有正确的导入和合理的熵值
  7. 导入到 Ghidra 或 IDA 进行完整的静态分析

陷阱:

  • 假设 UPX 是唯一的加壳器;二进制文件可能是双加壳的(UPX + 自定义层)
  • 修改原始加壳样本而不是对副本进行操作
  • 手动内存转储后未重建导入(转储后的二进制文件如果没有 IAT 修复将会崩溃)
  • 忘记检查附加在 UPX 加壳 PE 节之后的覆盖数据

输出格式

脱壳分析报告
===========================
样本:           suspect.exe
SHA-256:          e3b0c44298fc1c149afbf4c8996fb924...
加壳器:           UPX 3.96 (已修改头部)

加壳后二进制文件
节:             UPX0 (熵: 0.00) UPX1 (熵: 7.89) .rsrc (熵: 3.45)
导入:          2 (kernel32.dll: LoadLibraryA, GetProcAddress)
文件大小:        98,304 字节

脱壳方法
方法:           头部修复 + UPX -d
头部修复:       在偏移 0x1F000 处恢复 UPX! 魔数
命令:           upx -d suspect_fixed.exe -o unpacked.exe
结果:           成功

解包后二进制文件
节:             .text (熵: 6.21) .rdata (熵: 4.56) .data (熵: 3.12) .rsrc (熵: 3.45)
导入:          147 (kernel32, user32, advapi32, wininet, ws2_32)
文件大小:        245,760 字节 (2.5x 扩展)
OEP:              0x00401000

验证
PE 有效:         是
导入已解析:       是 (跨 8 个 DLL 的 147 个函数)
可执行:          是 (在沙箱中运行不会崩溃)

下一步
- 将 unpacked.exe 导入到 Ghidra 进行完整反汇编
- 针对解包后的二进制文件运行 YARA 规则
- 将解包后的二进制文件提交到 VirusTotal 以获得改进的检测

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

abusing-dpapi-for-credential-access

Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys) online or offline using SharpDPAPI, SharpChrome, Mimikatz, or Impacket

abusing-shadow-credentials-for-privesc

Take over Active Directory accounts by writing attacker-controlled public keys to msDS-KeyCredentialLink (Shadow Credentials) with pyWhisker, Whisker, or Certipy, then authenticate via PKINIT to recover the target

achieving-cmmc-level-2-compliance

>-

acquiring-disk-image-with-dd-and-dcfldd

Create forensically sound bit-for-bit disk images with dd or dcfldd on a Linux forensic workstation, preserving evidence integrity through hash verification (MD5/SHA) during acquisition. Use when imaging a suspect drive, USB device, or memory card for investigation, preserving volatile disk evidence during incident response, or producing a verified copy for legal or law-enforcement proceedings before any destructive analysis.

analyzing-active-directory-acl-abuse

Detect dangerous ACL misconfigurations in Active Directory using ldap3

analyzing-android-malware-with-apktool

Perform static analysis of Android APK malware using apktool for resource decompilation, jadx for Java source recovery, and androguard for manifest inspection, dangerous permission-combination detection, and identification of obfuscated code, dynamic code loading, and reflection-based API calls. Use to statically triage a suspicious APK without executing it or to build mobile malware detection rules.

analyzing-api-gateway-access-logs

Parses API Gateway access logs (AWS API Gateway, Kong, Nginx) to detect

analyzing-apt-group-with-mitre-navigator

Query ATT&CK data with attackcti, mitreattack-python, and stix2, then build MITRE ATT&CK Navigator layers and multi-layer heatmap overlays mapping one or more APT groups

analyzing-azure-activity-logs-for-threats

Queries Azure Monitor activity logs and sign-in logs via azure-monitor-query

analyzing-bootkit-and-rootkit-samples

Analyzes bootkit and advanced rootkit malware infecting the Master

analyzing-browser-forensics-with-hindsight

Parse Chromium-based browser databases with Hindsight to extract and correlate browsing history, downloads, cookies, cached content, autofill data, saved passwords, and extensions from Chrome, Edge, Brave, Opera, and Vivaldi into a unified timeline (XLSX, JSON, or SQLite output). Use during incident response, insider-threat investigations, or criminal cases when you need to reconstruct a user

analyzing-campaign-attribution-evidence

Systematically evaluate cyber-campaign evidence to attribute an operation to a threat actor, using the Diamond Model and Analysis of Competing Hypotheses (ACH) to weigh infrastructure overlaps, TTP consistency, malware code similarity, and timing/language artifacts into confidence-weighted attribution assessments. Use when an incident investigation needs a defensible attribution confidence level.

analyzing-certificate-transparency-for-phishing

Monitor Certificate Transparency logs using crt.sh and Certstream to

analyzing-cloud-storage-access-patterns

Detect abnormal access in AWS S3, GCS, and Azure Blob Storage by analyzing CloudTrail Data Events, GCS audit logs, and Azure Storage Analytics for after-hours bulk downloads, new-IP access, and API-call spikes (e.g. GetObject) via statistical baselines and time-series anomaly detection. Use when investigating suspected cloud data exfiltration or building related detection rules.

analyzing-cobalt-strike-beacon-configuration

Extract and analyze Cobalt Strike beacon configuration from PE files

analyzing-cobaltstrike-malleable-c2-profiles

Parse and analyze Cobalt Strike Malleable C2 profiles with dissect.cobaltstrike (profiles and beacon-payload configs) and pyMalleableC2 (AST parsing) to extract HTTP/DNS transforms, URIs, headers, sleep/jitter, and injection behavior, then generate network detection signatures. Use when reverse-engineering a captured malleable profile or building detections against Cobalt Strike Beacon traffic.

analyzing-command-and-control-communication

Analyzes malware C2 communication over HTTP, HTTPS, DNS, and custom

analyzing-cyber-kill-chain

Analyzes intrusion activity against the Lockheed Martin Cyber Kill Chain

analyzing-disk-image-with-autopsy

Perform comprehensive forensic analysis of raw (dd), E01, or AFF disk images with Autopsy and The Sleuth Kit, recovering deleted files, examining metadata and embedded artifacts, keyword searching, and building investigation timelines with visual reports. Use for structured analysis of a forensic disk image or when stakeholders need visual reports from evidence.

analyzing-dns-logs-for-exfiltration

Analyzes DNS query logs to detect data exfiltration via DNS tunneling,

相关技能