Communitygithub.com

UPXアンパッカーによるパックドマルウェア解析

UPXでパックされたマルウェアサンプルを特定し、改変されたUPXマジックバイトやヘッダーを持つバイナリを含めて自動展開を阻むサンプルから元の実行可能ファイルを復元し、静的解析を可能にします。高いエントロピー、最小限のインポート、インポートテーブルにLoadLibrary/GetProcAddressのみが見られるサンプルや、GhidraやIDAで逆アセンブルする前にパックドバイナリを準備する場合に使用します。

UPXアンパッカーによるパックドマルウェア解析 とは?

このスキルは、UPX(Ultimate Packer for eXecutables)でパックされたマルウェアサンプルを解析・展開するための包括的なワークフローを提供します。UPXはマルウェア作者によく悪用されるオープンソースの実行ファイルパッカーで、このスキルは標準的な展開、ヘッダー修復、デバッガを使った手動展開といった複数の手法をカバーしています。 主な機能として、pefileライブラリを使ったエントロピー解析によるパッカー識別、Pythonスクリプトによる改変UPXマジックバイト(「UPX!」)の修復、x64dbgデバッガでのハードウェアブレークポイントを使用した手動展開(PUSHAD/POPAD/JMP OEPパターン)、そしてScyllaプラグインによるインポート再構築があります。 このスキルは、UPXの自動展開が失敗するケース(マジックバイトの改変やセクション名の変更など)で特に有効です。また、カスタムパッカーやVMベースのプロテクター(Themida、VMProtectなど)には使用すべきでないという注意点も明記されています。 検証手順では、展開後のバイナリのセクションエントロピー、インポート数、ファイルサイズの変化を確認し、GhidraやIDAでの完全な静的解析に備えます。出力はUNPACKING ANALYSIS REPORTとして構造化され、サンプル情報、展開結果、検証結果、次のステップが整理されます。

対応~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に質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

UPXアンパッカーによるパックドマルウェア解析 は何をしますか?

使用するタイミング

  • 静的解析で高いエントロピーと最小限のインポートが確認され、バイナリがパックされていることを示す場合
  • PEiD、Detect It Easy、PEStudioがUPXまたは他の既知のパッカーを特定した場合
  • インポートテーブルにLoadLibraryとGetProcAddressのみが含まれている場合(パックドバイナリに典型的なランタイムインポート解決)
  • GhidraやIDAで適切な逆アセンブルや逆コンパイルを行うために元のバイナリを復元する必要がある場合
  • マルウェア作者がUPXマジックバイトやヘッダーを改変したため、自動UPX展開が失敗する場合

使用しない場合: カスタムパッカー、VMベースのプロテクター(Themida、VMProtect)、またはデバッグによる動的展開がより適切なサンプルを扱う場合。

前提条件

  • UPX(Ultimate Packer for eXecutables)がインストールされていること(apt install upx-ucl または https://upx.github.io/ からダウンロード)
  • パッカー識別用のDetect It Easy (DIE)
  • Python 3.8以上と手動ヘッダー修復用のpefileライブラリ
  • 自動ツールが失敗した場合の手動展開用のx64dbgまたはx32dbg
  • PEヘッダーの検査と修復用のPE-bearまたはCFF Explorer
  • ネットワーク接続のない隔離された解析用VM

ワークフロー

ステップ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"改変されたUPXマジックをオフセット 0x{i:X} で発見: {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: デバッガによる手動展開

自動展開が完全に失敗した場合、動的展開を使用します:

Manual UPX Unpacking with x64dbg:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. パックされたサンプルをx64dbgにロード
2. エントリポイントまで実行(システムブレークポイント後F9)
3. UPX展開スタブのパターン:
   a. PUSHAD(すべてのレジスタを保存)
   b. 展開ループ(パックされたセクションを処理)
   c. インポート解決(LoadLibrary/GetProcAddress呼び出し)
   d. POPAD(レジスタを復元)
   e. JMP to OEP(オリジナルエントリポイントへジャンプ)
4. PUSHAD後にESPにハードウェアブレークポイントを設定:
   - PUSHAD後、ESPを右クリック -> ダンプで追跡
   - [ESP]アドレスにアクセス時にハードウェアブレークポイントを設定
   - 実行(F9)- OEPへのJMP前のPOPADで停止
5. OEPへのJMPに到達するまで前方にステップ(F7/F8)
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

主要概念

用語定義
パッキング実行可能コードを圧縮または暗号化してファイルサイズを減らし静的解析を妨げること。バイナリには実行時にコードを復元する展開スタブが含まれる
UPXUltimate Packer for eXecutables。マルウェア作者によく悪用されるオープンソースの実行ファイルパッカー。無料で効果的であるため
オリジナルエントリポイント (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: 動的実行とブレークポイントベースのOEP検出による手動展開に使用されるオープンソースのWindowsデバッガ
  • Scylla: メモリダンプ後のIAT再構築のためにx64dbgに統合されたインポート再構築ツール
  • PE-bear: 展開後のPEヘッダーの検査と修復のためのPEファイルビューア兼エディタ

よくあるシナリオ

シナリオ: 改変されたUPXヘッダーを持つマルウェアの展開

コンテキスト: セクション名(UPX0、UPX1)からUPXパックと識別されたマルウェアサンプルだが、upx -d が「CantUnpackException: header corrupted」で失敗する。マルウェア作者がUPXマジックバイトを改変して自動展開を妨害している。

アプローチ:

  1. バイナリをhexエディタで開き、UPXヘッダー領域(通常はパックデータの末尾)を検索
  2. 改変されたマジックバイトを特定(例: 「UPX!」が「UPX\x00」に変更、または完全にゼロ化)
  3. Python修復スクリプトを使用して「UPX!」マジックを復元し、セクション名を修正
  4. 修復されたバイナリで upx -d を再試行
  5. 修復が失敗した場合、x64dbgを使用した手動展開にフォールバック(PUSHAD -> ESPにHW BP -> POPAD -> JMP OEP)
  6. 展開されたバイナリが適切なインポートと妥当なエントロピー値を持つことを検証
  7. GhidraまたはIDAにインポートして完全な静的解析を実施

落とし穴:

  • UPXが唯一のパッカーであると想定すること。バイナリは二重パック(UPX + カスタムレイヤー)されている可能性がある
  • コピーではなく元のパックサンプルを改変してしまうこと
  • 手動メモリダンプ後にインポートを再構築しないこと(IAT修正なしではダンプされたバイナリはクラッシュする)
  • UPXパックされたPEセクションの後に追加されたオーバーレイデータをチェックし忘れること

出力形式

UNPACKING ANALYSIS REPORT
===========================
サンプル:           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.5倍に拡大)
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,

関連スキル