unpacking-protected-binaries について
unpacking-protected-binariesは、マルウェアやバイナリの分析者向けに、隔離環境で保護された実行ファイルを動的にアンパックする方法を示すスキルです。メモリからのダンプとインポート修復を中心に、商用プロテクターや一括ダンプできないサンプルへの対処も説明します。
主な機能
- 01プロテクターとパッキングの特徴を識別
- 02動的アンパックとOEP特定の手順
- 03プロセスのダンプとインポート修復
- 04TLSコールバックとアンチデバッグへの対処
- 05一括ダンプできない場合のコード復元
活用シーン
- 01高エントロピーでコードが見えにくい実行ファイルの分析
- 02実行中のサンプルから解析可能なプログラムを復元
- 03ThemidaやVMProtectで保護されたプログラムの調査
- 04一度にダンプできない場合の復号コードの追跡
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trilwu/ secskills --skill unpacking-protected-binariesインストール後、Claude Code で/unpacking-protected-binariesを入力して読み込まれたか確認します。
詳細
保護されたバイナリのアンパック
UPX 以外の場合、静的アンパックは罠です。確実な方法は、プログラム自身にアンパックさせてから、結果をメモリから取り出すことです。どれほど高度なプロテクターでも、最終的には実行可能なコードを読み取り可能なページに生成する必要があります。その瞬間を待ちます。
保護されたサンプルは、隔離された環境でのみ実行してください。analyzing-malware を参照してください。
使用する場合
binwalk -Eで、ファイルの大部分にわたって一様に高いエントロピーが示される- インポートテーブルのエントリーが少数(
LoadLibrary、GetProcAddress) - セクション名がない、ランダム、または
UPX0/.themida/.vmp0 - 逆アセンブル結果に、小さなスタブと大きなデータブロブが 1 つ表示される
- ツールがファイルをパック済みと報告する、または解析しても実質的にコードが見つからない
使用しない場合
- より広範なマルウェア解析ワークフロー — 隔離、トリアージ、IOC の出力には
analyzing-malwareを使用し、アンパックの段階でここに戻ってください - .NET アセンブリ — .NET パッカーと、マネージドメモリのダンプに特化した
analyzing-dotnet-assembliesを使用してください - パッキングを伴わない難読化(読み取り可能なインポート、通常のエントロピー、複雑な制御フロー)—
analyzing-binariesを使用してください - ファームウェアイメージ —
binwalk -Meによる抽出は別の作業です。analyzing-binariesを参照してください
まずプロテクターを特定する
一般的なパッカーと商用プロテクターでは対応が大きく異なるため、ここで少し時間をかけてください。
diec target.exe # Detect It Easy — the best single identifier
rg -a -o 'UPX|MPRESS|Themida|VMProtect|ASPack|Enigma|Obsidium|PECompact' target.exe
binwalk -E target.exe # entropy profile
# Structural tells
readpe target.exe # or: rabin2 -S target.exe
# raw size ≈ 0 with large virtual size → section unpacked at runtime
# section marked writable AND executable → self-modifying
# entry point outside the first section → stub in a later section
# TLS callbacks present → code runs BEFORE the entry point
TLS コールバックは重要です。 エントリーポイントより前に実行されるため、EP でブレークするようデバッガーを設定すると、プロテクターのアンチデバッグチェックはすでに実行済みです。エントリーポイントではなく、TLS コールバックでブレークするようデバッガーを設定してください。
| 特定結果 | 対応方法 |
|---|---|
| UPX(未改変) | upx -d — 数秒で完了します |
| UPX(ヘッダー改変済み) | マジック値を修復するか、動的にアンパックします |
| 一般的なクリプター、カスタムスタブ | OEP で動的にダンプします |
| Themida、VMProtect、Enigma | ダンプと大規模なインポート修復が必要です。仮想化された関数は仮想化されたままになると見込んでください |
| .NET パッカー | analyzing-dotnet-assemblies |
upx -d target.exe -o unpacked.exe # try first, costs nothing
動的アンパックの手順
1. Break before the stub runs (TLS callbacks, or the EP if none)
2. Run until the unpacked code exists in memory
3. Find the OEP — the original entry point of the real program
4. Dump the process image
5. Rebuild the import table
6. Fix the PE headers and verify the dump loads
OEP の特定には判断力が必要です。信頼できる手がかりは次のとおりです。
- メモリへの書き込み後に実行。 スタブが書き込みを行っているセクションに対し、実行時にハードウェアブレークポイントを設定します。そのセクションでの最初の実行は、通常、OEP 上またはその近くで発生します。x64dbg では、対象セクションにページガードを設定します。
- 末尾のジャンプ。 パッカースタブは、スタブ自身のセクションから大きく離れた場所へのジャンプで終わります。スタブの末尾までステップ実行し、遠くへのジャンプを確認してください。
- コンパイラーのエントリーシグネチャ。 実際のエントリーポイントは、コンパイラーの CRT 起動コードに似ています。たとえば、
security_init_cookie、__scrt_common_mainへの呼び出し、または標準的なプロローグです。難読化されたスタブコードではなく通常のコンパイル済みコードのように見える場所で実行が始まったら、そこが到達点です。 - 実際のプログラムの早い段階での
GetCommandLine/GetModuleHandle呼び出し。
x64dbg workflow:
Options → Events → break on TLS callbacks and on system breakpoint
Run, then in the Memory Map set "Break on execute" for the target section
When it breaks, confirm the code looks compiler-generated → that is the OEP
ダンプとインポートの修復
# Dump from the debugger at OEP: Scylla (built into x64dbg)
# 1. Attach / already broken at OEP
# 2. Scylla → set OEP → IAT Autosearch → Get Imports
# 3. Fix invalid/unresolved entries, then Dump + Fix Dump
# Or dump externally
pe-sieve /pid <pid> /dmode 3 # dumps and repairs; good for automation
# hollows_hunter for scanning a whole system for unpacked/injected modules
ほとんどのダンプで失敗するのはインポートの修復です。 パッカーはインポートテーブルを実行時に解決されるスタブに置き換えるため、生のダンプでは API 呼び出しがパッカー独自のサンク領域を指しています。Scylla の IAT 検索で解決済みのテーブルを見つけられます。未解決のエントリーが返される場合、通常は次のいずれかです。
- インポートが完全に解決される前にダンプを取得しています — さらに実行してください
- プロテクターが API リダイレクトを使用しています。各呼び出しが、実際のアドレスを計算する難読化スタブを経由します — 手動での解決、またはエミュレーションベースのアンスタッバーが必要です
- API が初回呼び出し時に遅延解決されます — 該当機能を実行してからダンプしてください
解析する前にダンプを検証してください。
readpe dumped.exe | head -30 # sane headers, correct EP
rabin2 -i dumped.exe | head -20 # imports resolve to real API names
# The strongest test: does it run, or does a decompiler produce sane output?
商用プロテクター
Themida、VMProtect、Enigma などは、単にパックするだけではありません。次の点に注意してください。
- 仮想化された関数。 選択された関数は、カスタム VM のバイトコードに変換されます。ダンプすると、その関数の「周囲」にあるプログラムは復元できますが、仮想化された関数は VM インタープリターループのままです。デバーチャル化は、プロテクターのバージョンごとに研究規模の取り組みが必要です。
- 強力なアンチデバッグおよびアンチ VM。 まず検出を回避してください。ScyllaHide、TitanHide、またはハイパーバイザーレベルのデバッガーを使わないと、OEP に到達する前にプロセスが終了するか、自身を破損させます。
- 先行するステージを再暗号化する複数のアンパック段階。
実務上の判断として、仮想化された関数が数個だけなら、ほかのすべてをダンプして解析し、それらの関数は動的に処理します。ロジックを読み取る代わりに、入力と出力をフックします。これなら VM を打ち破らずに「何をするのか」が分かります。
ダンプできない場合
一部のサンプルは、ひとつの場所ですべてをアンパックしません。個々の関数を必要に応じて復号して使用後に再暗号化するか、JIT 形式のバッファーから完全に実行します。
- トレースベースの復元。 インストルメンテーションフレームワークで実行を記録し、トレースから実行されたコードパスを再構築します。
- 復号ルーチンをフックして、生成されるすべての平文ブロックを記録します。コードを断片ごとに取得できますが、すべてそろいます。
- インストルメンテーションにはFrida/Pin/DynamoRIOを使用します。
受け入れてはいけない言い訳
- 「
upx -dに失敗したので、UPX ではありません。」 改変された UPX ヘッダーは、最もよくある一般的な回避手法です。セクション名とスタブのパターンを確認してください。 - 「静的アンパッカーを書きます。」 何度も遭遇するひとつのファミリーなら、作る価値があります。それ以外の場合、ダンプするほうが桁違いに低コストです。
- 「ダンプが実行できないので、間違っています。」 本当に必要なものを確認してください。実行できないダンプでも、完全に解析可能なものは多くあります。
- 「インポートが壊れているので、ダンプは役に立ちません。」 実行を進めてから再度ダンプするか、手動で解決してください。通常、問題はタイミングです。
- 「VMProtect なので不可能です。」 不可能なのは、仮想化された関数だけです。それ以外をすべてダンプし、観測可能な入出力を持つブラックボックスとして扱ってください。
- 「エントリーポイントにブレークポイントを設定します。」 TLS コールバックはすでに実行済みです。
- 「実行しても何も起きませんでした。」 アンチ VM またはアンチデバッグが作動しています。アンパックする前に検出を回避してください。
参考資料
analyzing-malware— 封じ込め、機能モデル、IOC。このワークフローが組み込まれる先ですanalyzing-binaries— アンパック後の解析とアンチ解析への対処analyzing-dotnet-assemblies— .NET パッカーとマネージドダンプ- Detect It Easy、x64dbg + Scylla + ScyllaHide、pe-sieve、hollows_hunter、UPX