performing-static-malware-analysis-with-pe-studio について
PEStudioなどを使ってWindows PEファイルを静的解析するセキュリティ分析者向けのスキルガイドです。ヘッダー、インポート、文字列、リソース、パッキングの確認を通じ、実行前の初期トリアージを支援します。
主な機能
- 01PEヘッダーとセクションの確認
- 02機能別のインポート分析
- 03通常文字列と難読化文字列の抽出
- 04リソースと埋め込みデータの調査
- 05パッキングと保護の特定
- 06静的解析レポートの作成
活用シーン
- 01不審なメール添付ファイルのトリアージ
- 02ファイルからネットワーク指標を抽出
- 03サンプルのパッキング有無を確認
- 04後続のサンドボックス解析に備える
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill performing-static-malware-analysis-with-pe-studioインストール後、Claude Code で/performing-static-malware-analysis-with-pe-studioを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
PEStudio を使った静的マルウェア解析の実施
使用するタイミング
- 不審な Windows 実行可能ファイルを収集し、サンドボックスで実行する前に初期トリアージが必要な場合
- サンプルを実行せずに、マルウェアの機能を明らかにするインポート、文字列、リソースを特定する必要がある場合
- PE ファイルがパック、難読化、またはアンチ解析技術を含んでいるかどうかを判断する場合
- バイナリに埋め込まれた侵害指標(ハッシュ、URL、IP、レジストリキー)を抽出する場合
- インポートテーブルとセクションの特性に基づいてサンプルの機能を分類する場合
使用しないケース: 実行を伴う動的な挙動解析には使用しないでください。実行時の挙動を観察するには、サンドボックス(Cuckoo、ANY.RUN)を使用してください。
前提条件
- 分離された解析用ワークステーションにインストールされた PEStudio(無料版、https://www.winitor.com/ から入手可能)
- スクリプトによる PE 解析用の
pefileライブラリを含む Python 3.8 以降(pip install pefile) - 補助的な PE 解析ツールとしての CFF Explorer または PE-bear
- ハッシュ検索およびコミュニティのインテリジェンス取得用の VirusTotal API へのアクセス
- 本番システムへのネットワーク接続がない、分離された解析用 VM
- 難読化された文字列を抽出するための FLOSS(FireEye Labs Obfuscated String Solver)
ワークフロー
ステップ 1: ファイルハッシュの計算とサンプルの整合性の検証
識別およびインテリジェンス検索のために、暗号学的ハッシュを生成します:
# Generate MD5, SHA-1, and SHA-256 hashes
md5sum suspect.exe
sha1sum suspect.exe
sha256sum suspect.exe
# Check hash against VirusTotal
curl -s -X GET "https://www.virustotal.com/api/v3/files/$(sha256sum suspect.exe | cut -d' ' -f1)" \
-H "x-apikey: $VT_API_KEY" | jq '.data.attributes.last_analysis_stats'
# Get file type with magic bytes verification
file suspect.exe
ステップ 2: PE ヘッダーとセクションテーブルの検査
PEStudio でサンプルを開き、構造的な特性を確認します:
PEStudio Analysis Points:
━━━━━━━━━━━━━━━━━━━━━━━━━
File Header: Compilation timestamp, target architecture (x86/x64)
Optional Header: Entry point address, image base, subsystem (GUI/console)
Section Table: Section names, virtual/raw sizes, entropy values
High entropy (>7.0) in .text/.rsrc suggests packing
Signatures: Authenticode signature presence and validity
pefile によるスクリプトを使った PE ヘッダー解析:
import pefile
import hashlib
import math
pe = pefile.PE("suspect.exe")
# Compilation timestamp
import datetime
timestamp = pe.FILE_HEADER.TimeDateStamp
compile_time = datetime.datetime.utcfromtimestamp(timestamp)
print(f"Compile Time: {compile_time} UTC")
# Section analysis with entropy calculation
for section in pe.sections:
name = section.Name.decode().rstrip('\x00')
entropy = section.get_entropy()
raw_size = section.SizeOfRawData
virtual_size = section.Misc_VirtualSize
ratio = virtual_size / raw_size if raw_size > 0 else 0
print(f"Section: {name:8s} Entropy: {entropy:.2f} Raw: {raw_size:>10} Virtual: {virtual_size:>10} Ratio: {ratio:.2f}")
if entropy > 7.0:
print(f" [!] HIGH ENTROPY - likely packed or encrypted")
if ratio > 10:
print(f" [!] HIGH V/R RATIO - unpacking stub likely present")
ステップ 3: インポートアドレステーブル(IAT)の解析
マルウェアの機能を示す不審な API インポートを特定します:
# Extract and categorize imports
suspicious_imports = {
"Process Injection": ["VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread", "NtCreateThreadEx"],
"Keylogging": ["GetAsyncKeyState", "SetWindowsHookExA", "GetKeyState"],
"Persistence": ["RegSetValueExA", "CreateServiceA", "SchTasksCreate"],
"Evasion": ["IsDebuggerPresent", "CheckRemoteDebuggerPresent", "NtQueryInformationProcess"],
"Network": ["InternetOpenA", "HttpSendRequestA", "URLDownloadToFileA", "WSAStartup"],
"File Operations": ["CreateFileA", "WriteFile", "DeleteFileA", "MoveFileA"],
"Crypto": ["CryptEncrypt", "CryptDecrypt", "CryptAcquireContextA"],
}
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll_name = entry.dll.decode()
for imp in entry.imports:
if imp.name:
func_name = imp.name.decode()
for category, funcs in suspicious_imports.items():
if func_name in funcs:
print(f"[!] {category}: {dll_name} -> {func_name}")
ステップ 4: 文字列の抽出と解析
難読化された文字列には FLOSS を、標準的な文字列抽出には通常の方法を使用します:
# Standard strings extraction (ASCII and Unicode)
strings -a suspect.exe > strings_ascii.txt
strings -el suspect.exe > strings_unicode.txt
# FLOSS for decoded/deobfuscated strings
floss suspect.exe --output-json floss_output.json
# Search for network indicators in strings
grep -iE "(http|https|ftp)://" strings_ascii.txt
grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_ascii.txt
grep -iE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" strings_ascii.txt
# Search for registry keys
grep -i "HKLM\\|HKCU\\|SOFTWARE\\|CurrentVersion\\Run" strings_ascii.txt
# Search for file paths and extensions
grep -iE "\.(exe|dll|bat|ps1|vbs|tmp)" strings_ascii.txt
ステップ 5: リソースと埋め込みデータの検査
埋め込まれたペイロードや設定情報がないか、PE のリソースセクションを調べます:
# Extract resources from PE file
if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if hasattr(resource_type, 'directory'):
for resource_id in resource_type.directory.entries:
if hasattr(resource_id, 'directory'):
for resource_lang in resource_id.directory.entries:
data = pe.get_data(resource_lang.data.struct.OffsetToData,
resource_lang.data.struct.Size)
entropy = calculate_entropy(data)
print(f"Resource Type: {resource_type.id} Size: {len(data)} Entropy: {entropy:.2f}")
if entropy > 7.0:
print(f" [!] High entropy resource - possible embedded payload")
# Check for PE signature in resource (embedded executable)
if data[:2] == b'MZ':
print(f" [!] Embedded PE detected in resource")
with open(f"extracted_resource_{resource_type.id}.bin", "wb") as f:
f.write(data)
ステップ 6: パッキングと保護の有無の確認
バイナリがパックまたは保護されているかどうかを判断します:
# Detect packer with Detect It Easy (DIE)
diec suspect.exe
# Check with PEiD signatures (command-line version)
python3 -c "
import pefile
pe = pefile.PE('suspect.exe')
# Check for common packer section names
packer_sections = {'.upx0': 'UPX', '.aspack': 'ASPack', '.adata': 'ASPack',
'.nsp0': 'NsPack', '.vmprotect': 'VMProtect', '.themida': 'Themida'}
for section in pe.sections:
name = section.Name.decode().rstrip('\x00').lower()
if name in packer_sections:
print(f'[!] Packer detected: {packer_sections[name]} (section: {name})')
# Check import table size (very few imports suggest packing)
import_count = sum(len(entry.imports) for entry in pe.DIRECTORY_ENTRY_IMPORT)
if import_count < 10:
print(f'[!] Only {import_count} imports - likely packed')
"
ステップ 7: 静的解析レポートの作成
すべての調査結果を構造化されたトリアージレポートにまとめます:
Document the following for each analyzed sample:
- File identification (hashes, file type, size, compile timestamp)
- Packing/protection status and identified packer
- Suspicious imports categorized by capability
- Network indicators extracted from strings (IPs, domains, URLs)
- Embedded resources and their characteristics
- Overall threat assessment and recommended next steps (sandbox execution, YARA rule creation)
主要な概念
| 用語 | 定義 |
|---|---|
| PE (Portable Executable) | Windows の実行可能ファイル(.exe、.dll、.sys)のファイル形式。ヘッダー、セクション、インポート、リソースを含み、OS がバイナリをどのように読み込むかを定義する |
| インポートアドレステーブル(IAT) | 実行時に実行ファイルが呼び出す外部 DLL 関数を列挙した PE 構造。プログラムの機能と意図を明らかにする |
| セクションエントロピー | PE セクション内のランダム性を示す統計的指標。7.0(8.0 中)を超える値は、圧縮、暗号化、またはパッキングを示す |
| FLOSS | FireEye Labs Obfuscated String Solver。標準の strings では検出できない難読化された文字列を自動的に抽出・復号する |
| パッキング | 静的解析を妨げるために PE ファイルのコードセクションを圧縮または暗号化すること。実行するには実行時にアンパックするスタブが必要となる |
| PE リソース | アイコン、ダイアログ、バージョン情報、または攻撃者が埋め込んだペイロードや設定データを含みうる、PE ファイル内のデータセクション |
| コンパイルタイムスタンプ | バイナリがコンパイルされた時期を示す PE ヘッダー内のタイムスタンプ。偽装されうるが、開発のタイムラインを示すことが多い |
ツールとシステム
- PEStudio: 指標、インポート、文字列、リソース検査を単一のインターフェースで提供する、PE ファイルの静的解析用の無料 Windows ツール
- pefile (Python): 自動化された解析パイプライン向けに、PE ファイル構造をプログラムから解析するための Python ライブラリ
- FLOSS: スタック文字列の復号を含む静的解析技術を用いて、マルウェアから難読化された文字列を抽出する FireEye のツール
- Detect It Easy (DIE): PE ファイルのビルドに使用されたプロテクタ、コンパイラ、リンカーを識別する、パッカーおよびコンパイラ検出ツール
- CFF Explorer: PE ヘッダー、セクション、インポート、リソースディレクトリを詳細に検査するための高機能 PE エディター兼ビューアー
よくあるシナリオ
シナリオ:不審なメール添付ファイルのトリアージ
状況:SOC がフィッシングメールに添付された不審な実行ファイルについてアラートを受信しました。サンドボックスのリソースを使う前に、そのファイルが悪意のあるものかどうかを判断するため、迅速なトリアージが必要です。
アプローチ:
- SHA-256 ハッシュを計算し、VirusTotal で既存の検出結果とコミュニティのコメントを確認します
- PEStudio で開き、インジケータータブで赤または黄色にフラグ付けされた項目を確認します
- コンパイル日時を検証します(未来の日付や 1970 年の日付は、タイムスタンプの改ざんを示しています)
- インポートを確認して、VirtualAllocEx、CreateRemoteThread(インジェクション)、URLDownloadToFileA(ダウンローダー)を探します
- 文字列を抽出し、C2 の URL、IP アドレス、ファイルパスを検索します
- リソースを確認して、埋め込み PE ファイルや高エントロピーのデータブロブを探します
- パッキングの状態を評価します。パックされている場合は、パッカーを記録し、詳細な分析の前にアンパックする計画を立てます
注意点:
- 裏付ける証拠がないまま、PE のコンパイル日時を信頼すること(タイムスタンプは簡単に偽造できます)
- 不審なインポートが少ないことを理由に、ファイルが無害だと結論付けること(パックされたマルウェアは実際のインポートを隠します)
- ASCII 文字列の抽出だけを実行し、Unicode 文字列を見落とすこと
- 最後の PE セクションの後に追加されたオーバーレイデータを確認しないこと(設定データを隠す場所としてよく使われます)
出力形式
STATIC MALWARE ANALYSIS REPORT
=================================
Sample: suspect.exe
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
File Size: 245,760 bytes
File Type: PE32 executable (GUI) Intel 80386
Compile Time: 2025-09-14 08:23:15 UTC
PACKING STATUS
Packer Detected: None (native binary)
Section Entropy: .text=6.42 .rdata=4.89 .data=3.21 .rsrc=7.81
Note: .rsrc section entropy elevated - check resources
SUSPICIOUS IMPORTS
[INJECTION] kernel32.dll -> VirtualAllocEx
[INJECTION] kernel32.dll -> WriteProcessMemory
[INJECTION] kernel32.dll -> CreateRemoteThread
[EVASION] kernel32.dll -> IsDebuggerPresent
[NETWORK] wininet.dll -> InternetOpenA
[NETWORK] wininet.dll -> HttpSendRequestA
[PERSISTENCE] advapi32.dll -> RegSetValueExA
EXTRACTED INDICATORS
URLs: hxxps://update.malicious[.]com/gate.php
IPs: 185.220.101[.]42, 91.215.85[.]17
Registry Keys: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\svchost
File Paths: C:\Users\Public\svchost.exe
EMBEDDED RESOURCES
Resource 101: Size=98304 Entropy=7.89 [!] Embedded PE detected
Resource 102: Size=4096 Entropy=2.14 (configuration XML)
ASSESSMENT
Threat Level: HIGH
Classification: Dropper with process injection capabilities
Recommended: Execute in sandbox, extract embedded PE for separate analysis
コメント
Markdown 対応