恶意代码脱壳与去混淆
用于处理加壳、编码、字符串加密和控制流混淆等常见恶意程序保护手段,识别UPX等打包方式,并通过解包、解密、脚本辅助和静态特征恢复可分析内容。适合样本字符串几乎不可读、熵值异常、真实入口被隐藏或配置被多层编码的场景,为后续逆向、IOC提取和配置恢复提供干净输入。
在 AI 中使用此 Skill将本页链接复制给 AI,即可让 AI 获取完整 Skill 内容并按此执行
安全提示: 本站 Skill 均经 ChatGPT 最新模型扫描,未发现恶意脚本及危险指令、未检出已知恶意行为特征,但不保证绝对安全,使用即表示接受此风险
Skill 文件
版本 20260301 · a13be3d5b1d584967d7450611318f6c7
SKILL.md
---
name: malware-deobfuscation
description: >
Defeat obfuscation, packing, and encryption used to hide malware functionality.
Use when a sample is packed, encrypted, or obfuscated and you need to recover the
original code for analysis. Covers automated and manual unpacking, string decryption,
control flow deobfuscation, import table reconstruction, and multi-layer packing.
Supports both offline (local tools) and online (API-enriched) modes on Linux and Windows.
---
# Malware Deobfuscation
Identify and defeat obfuscation, packing, and encryption techniques used by malware
to hide its true functionality. Recover the original code, strings, and imports for
further static and dynamic analysis.
## Prerequisites
- **Linux**: `file`, `strings`, `upx`, `binwalk`, `python3`, `objdump`, `readelf`
- **Windows**: `upx.exe`, Python 3, PE analysis tools (pestudio, CFF Explorer)
- **Python packages**: `pefile`, `yara-python`, `capstone`, `unicorn` (optional for emulation)
- **Optional**: IDA Pro / Ghidra / Binary Ninja for manual analysis
## Step-by-Step Instructions
### Step 1: Identify Packing and Obfuscation Type
Determine whether the sample is packed, and if so, identify the packer.
**Entropy analysis (high entropy = likely packed/encrypted):**
```bash
python3 scripts/packer_detector.py --file sample.exe
```
This script performs:
- Section-level entropy analysis (entropy > 7.0 suggests packing)
- Packer signature matching against a database of known packers
- PE header anomaly detection (small code section, large data sections)
- Import table analysis (very few imports suggests packed binary)
**Manual entropy check:**
```bash
python3 -c "
import math, sys
data = open(sys.argv[1], 'rb').read()
entropy = -sum((c/len(data)) * math.log2(c/len(data)) for c in [data.count(bytes([b])) for b in range(256)] if c > 0)
print(f'Overall entropy: {entropy:.4f}')
print('Likely packed' if entropy > 7.0 else 'Likely not packed')
" sample.exe
```
**Check for known packer strings:**
```bash
strings sample.exe | grep -iE "(UPX|ASPack|Themida|VMProtect|Enigma|PECompact|MPRESS|Armadillo|Obsidium)"
```
See `references/packer-identification.md` for a comprehensive guide to identifying
packers by entropy patterns, section names, and signature bytes.
### Step 2: Attempt Automated Unpacking
For known packers, try automated unpacking first.
**UPX (most common):**
```bash
bash scripts/upx_unpack.sh sample.exe unpacked_sample.exe
```
Or manually:
```bash
# Linux
upx -d sample.exe -o unpacked_sample.exe
# Windows
upx.exe -d sample.exe -o unpacked_sample.exe
```
**Verify unpacking succeeded:**
```bash
file unpacked_sample.exe
python3 scripts/packer_detector.py --file unpacked_sample.exe
```
A successful unpack should show:
- Lower entropy (below 7.0)
- More readable strings
- Complete import table
- Standard section names (.text, .data, .rdata)
**Other automated unpackers:**
| Packer | Tool |
|--------|------|
| UPX | `upx -d` |
| ASPack | `AspackDie`, manual OEP finding |
| PECompact | `PECompact unpacker` |
| MPRESS | `upx -d` (sometimes works) |
| .NET obfuscators | `de4dot`, `dnSpy` |
### Step 3: Manual Unpacking (When Automated Fails)
If automated unpacking fails, perform manual unpacking:
1. **Find the Original Entry Point (OEP):**
- Load in debugger (x64dbg, OllyDbg, or GDB)
- Set breakpoint on common OEP patterns:
- `VirtualAlloc` / `VirtualProtect` (memory allocation for unpacking)
- `WriteProcessMemory` (self-modifying code)
- Tail jump after unpacking stub
- Run until the unpacking stub completes
- The OEP is typically reached via a far jump after decompression
2. **Dump the unpacked process:**
```
# In x64dbg: use Scylla plugin
# In OllyDbg: use OllyDumpEx
# On Linux with GDB:
gdb -p <PID>
(gdb) dump binary memory dumped.bin 0x400000 0x500000
```
3. **Fix the import table** (see Step 7)
### Step 4: Decrypt Encrypted Strings
Malware frequently encrypts strings to hide IOCs, C2 addresses, and API names.
**Using the string decryptor framework:**
```bash
# Single-byte XOR
python3 scripts/string_decryptor.py --method xor-single --key 0x5A --input encrypted.bin
# Multi-byte XOR
python3 scripts/string_decryptor.py --method xor-multi --key "secret" --input encrypted.bin
# Rolling XOR
python3 scripts/string_decryptor.py --method xor-rolling --key 0x41 --input encrypted.bin
# Base64
python3 scripts/string_decryptor.py --method base64 --input encoded_strings.txt
# Custom alphabet Base64
python3 scripts/string_decryptor.py --method base64-custom --alphabet "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/" --input encoded.bin
# RC4
python3 scripts/string_decryptor.py --method rc4 --key "malwarekey" --input encrypted.bin
# AES-CBC
python3 scripts/string_decryptor.py --method aes-cbc --key 0102030405060708090a0b0c0d0e0f10 --iv 00000000000000000000000000000000 --input encrypted.bin
# Brute-force single-byte XOR
python3 scripts/string_decryptor.py --method xor-brute --input encrypted.bin
```
See `references/common-encryption.md` for identifying which encryption scheme
a sample uses and approaches for each.
**Identifying encryption in disassembly:**
- XOR loops with a constant or key array
- Calls to `CryptDecrypt`, `BCryptDecrypt` (Windows CryptoAPI)
- AES S-box constants (`0x63, 0x7c, 0x77, 0x7b...`)
- RC4 key scheduling (256-byte array initialization loop)
### Step 5: Deobfuscate Control Flow
Obfuscated malware may use control flow flattening, opaque predicates,
and dead code insertion.
**Control flow flattening:**
- Look for a dispatcher loop with a state variable
- Map each state to its corresponding basic block
- Reconstruct the original control flow by tracing state transitions
- In Ghidra/IDA: use graph view to identify the dispatcher pattern
**Opaque predicates:**
- Identify conditional jumps that always take the same path
- Common patterns: `x * (x-1) % 2 == 0` (always true for integers)
- Replace with unconditional jumps or NOPs
- Use symbolic execution (angr) to prove predicates are constant
**Dead code elimination:**
- Identify code blocks that are never reached
- Look for computations whose results are never used
- Focus analysis on the reachable code paths
**Using angr for automated deobfuscation (Python):**
```python
import angr
proj = angr.Project("obfuscated_sample", auto_load_libs=False)
cfg = proj.analyses.CFGFast()
# Analyze control flow graph for dispatcher patterns
```
See `references/deobfuscation-techniques.md` for detailed manual techniques.
### Step 6: Handle Multi-Layer Packing
Some malware uses multiple layers of packing/encryption.
**Approach:**
1. Unpack the outermost layer first
2. Analyze the result to determine if another layer exists
3. Repeat until you reach the final payload
4. Document each layer for the analysis report
**Detection of remaining layers:**
```bash
# After each unpack, re-check entropy and packer signatures
python3 scripts/packer_detector.py --file partially_unpacked.exe
```
**Common multi-layer patterns:**
- Crypter (outer) -> Packer (inner) -> Original binary
- Custom stub -> UPX -> Original binary
- .NET packer -> Native loader -> Shellcode -> Final payload
- Script dropper -> Encoded PE -> Packed PE -> Original binary
### Step 7: Reconstruct Import Tables
Packed binaries often have destroyed or minimal import tables.
**Using Scylla (Windows, with x64dbg):**
1. Run the sample to OEP in x64dbg
2. Open Scylla plugin
3. Set OEP address
4. Click "IAT Autosearch" then "Get Imports"
5. Fix any unresolved imports manually
6. Click "Fix Dump" on the memory dump
**Using ImpREC:**
1. Run the packed executable
2. Attach ImpREC to the process
3. Set the OEP value
4. Click "AutoSearch" for IAT
5. Click "Get Imports"
6. Fix the dump file
**Manual import reconstruction on Linux:**
```bash
# Examine the unpacked binary for import patterns
objdump -d unpacked.bin | grep -E "call.*\[" | head -20
readelf -d unpacked.bin
```
### Step 8: Validate Unpacked Binary
Confirm the unpacking was successful:
```bash
# Compare entropy before and after
python3 scripts/packer_detector.py --file original_packed.exe
python3 scripts/packer_detector.py --file unpacked.exe
# Check strings are readable
strings unpacked.exe | wc -l
strings unpacked.exe | grep -iE "(http|\.dll|\.exe|cmd|powershell)" | head -20
# Verify PE structure (Windows PE)
python3 -c "
import pefile
pe = pefile.PE('unpacked.exe')
print(f'Entry point: 0x{pe.OPTIONAL_HEADER.AddressOfEntryPoint:08x}')
print(f'Sections: {len(pe.sections)}')
for s in pe.sections:
print(f' {s.Name.decode().strip(chr(0)):8s} entropy={s.get_entropy():.2f} size={s.SizeOfRawData}')
print(f'Imports: {len(pe.DIRECTORY_ENTRY_IMPORT)}')
for entry in pe.DIRECTORY_ENTRY_IMPORT:
print(f' {entry.dll.decode()}: {len(entry.imports)} functions')
"
# Verify the unpacked binary runs (in sandbox only!)
# Compare dynamic behavior with the packed version
```
## Output Format
The packer detector produces JSON output:
```json
{
"file": "sample.exe",
"overall_entropy": 7.82,
"likely_packed": true,
"packer_signatures": ["UPX"],
"sections": [
{"name": "UPX0", "entropy": 0.0, "raw_size": 0},
{"name": "UPX1", "entropy": 7.95, "raw_size": 233472}
],
"import_count": 5,
"suspicious_indicators": [
"Very few imports (< 10)",
"High overall entropy",
"Known packer section names"
]
}
```
## Tips
- Always work on copies of samples, never modify the original
- Some packers detect tampering; use a VM snapshot you can revert
- If UPX unpacking fails, the sample may have a modified UPX header
- For .NET malware, try dnSpy or de4dot before manual approaches
- Emulation-based unpacking (QEMU, Unicorn) can handle custom packers
- Keep a log of each deobfuscation step for reproducibility
- Multi-layer packing is common in targeted attacks; be patient and systematic
此文件不提供内嵌文本预览
请使用左侧文件行末尾的外链图标打开原始文件。
