
Ctf Malware
- 30 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
ctf-malware is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- ctf-malware
- AI & Agent Building
- AI-coding skill
Ctf Malware by the numbers
- 30 all-time installs (skills.sh)
- +2 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,316 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill ctf-malwareAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 30 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
CTF 恶意软件分析
深入参考
以下参考资料按需加载,根据识别出的具体方向选择对应文件:
- 脚本反混淆与动态分析(JS/PowerShell/YARA/Shellcode/内存取证) → references/scripts-and-obfuscation.md
- C2 流量与自定义协议(RC4 WebSocket/DNS C2/AES-CBC/Telegram Bot) → references/c2-and-protocols.md
- PE/.NET 分析(peframe/dnSpy/LimeRAT/PyInstaller+PyArmor) → references/pe-and-dotnet.md
---
分类决策树
恶意软件分析题?
├─ 脚本类
│ ├─ JS → eval 替换为 console.log → 解码 unescape/atob
│ ├─ PowerShell → -enc base64解码 → IEX 替换为输出
│ ├─ Bash → eval 替换为 echo → base64/hex 提取
│ └─ Debian包 → ar -x → 检查 postinst 脚本
├─ 二进制类
│ ├─ PE → peframe/pestudio 快速分类 → [references/pe-and-dotnet.md](references/pe-and-dotnet.md)
│ ├─ .NET → dnSpy 反编译 → AsmResolver 编程分析
│ ├─ PyInstaller → pyinstxtractor 提取 → PyArmor 脱壳
│ └─ 查加密常量: AES S-box(0x637c777b) / ChaCha20 / TEA(0x9E3779B9) / RC4
├─ 流量分析
│ ├─ PCAP → tshark 提取流 → 识别 C2 模式
│ ├─ 自定义加密 → 找密钥 → 按时间序拼接解密
│ ├─ DNS C2 → 域名编码 / DGA 模式
│ └─ RC4 WebSocket → tcprewrite 重映射端口 → 找RC4密钥
├─ 反分析检测
│ ├─ VM检测 → CPUID/MAC/注册表/磁盘大小
│ ├─ 调试器 → PEB/时间检测/API哈希
│ └─ 进程注入 → hollowing/APC/CreateRemoteThread
└─ 内存取证 → vol3 malfind + YARA 扫描快速分析命令
# 文件快速分类
file malware && strings -n 8 malware | head -50
# 提取网络指标
strings malware | grep -E '[0-9]{1,3}(\.[0-9]{1,3}){3}'
# PCAP 流量分析
tshark -r capture.pcap -Y "tcp.stream eq 0" -T fields -e tcp.payload
# PE 分析
peframe malware.exe
# 内存取证
vol3 -f memory.dmp windows.malfind
vol3 -f memory.dmp windows.pstree加密算法识别
| 特征 | 算法 |
|---|---|
S-box 0x637c777b | AES |
expand 32-byte k | ChaCha20 |
0x9E3779B9 | TEA/XTEA |
| 256字节 S-box 顺序初始化 | RC4 |
| MD5/SHA256(硬编码字符串) | AES-CBC 密钥派生 |
YARA 速查
rule XOR_Loop { strings: $xor = { 31 ?? 80 ?? ?? 4? 75 } condition: $xor }反混淆技巧
| 语言 | 方法 |
|---|---|
| JavaScript | eval → console.log |
| PowerShell | -enc base64解码 / IEX → 输出 |
| Bash | eval → echo |
| 垃圾代码 | 过滤 NOP/push-pop/死写 → 提取真实 call |
Shellcode 分析
objdump -b binary -m i386:x86-64 -D shellcode.bin # 反汇编
# Unicorn 模拟执行 / Capstone 编程反汇编PowerShell 混淆
- 多层嵌套编码,需递归解码(可能多层混淆)
C2 流量分析
- DNS C2:检查子域名(subdomain)、qname 查询域名中的编码数据
{
"skill_name": "ctf-malware",
"evals": [
{
"id": 1,
"name": "powershell-deobfuscation",
"prompt": "CTF 恶意软件分析题给了一段混淆的 PowerShell 脚本:powershell -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAuAC4ALgA=。请描述如何分析并还原其真实行为。",
"expected_output": "Base64 解码 -enc 参数(注意 UTF-16LE 编码),将 IEX 替换为输出来查看最终执行的代码",
"expectations": [
"-enc|base64|Base64解码|编码参数",
"UTF-16LE|Unicode|宽字符|UTF-16",
"IEX|Invoke-Expression|替换为输出|Write-Output",
"多层|嵌套|递归解码|可能多层混淆",
"下载|URL|C2|网络行为|回连"
],
"required_terms": [
"IEX",
"URL",
"-enc"
]
},
{
"id": 2,
"name": "pcap-c2-traffic",
"prompt": "CTF 题目给了一个 PCAP 文件,提示其中包含恶意软件的 C2 通信。流量中有大量 DNS 查询到 *.evil.com 的子域名,子域名看起来像 base32 编码的数据。请描述分析方法。",
"expected_output": "DNS 隐蔽通道:提取所有到 evil.com 的 DNS 查询子域名,base32 解码拼接后获取 C2 数据/flag",
"expectations": [
"DNS|隐蔽通道|DNS tunneling|DNS C2",
"子域名|subdomain|qname|查询域名",
"base32|base64|hex|解码子域名",
"tshark|dns.qry.name|提取查询|过滤DNS",
"拼接|按序|时间顺序|重组数据"
],
"required_terms": [
"dns.qry.name",
"DNS",
"DNS tunneling"
]
},
{
"id": 3,
"name": "pe-malware-analysis",
"prompt": "CTF 题目给了一个 Windows PE 文件 malware.exe。运行 strings 发现有 AES S-box 常量 0x637c777b 和一个硬编码的 base64 字符串。请描述分析思路。",
"expected_output": "识别 AES 加密 → 找密钥(可能从硬编码字符串派生)→ 解密 base64 数据获取 flag",
"expectations": [
"AES|S-box|0x637c777b|加密算法识别",
"peframe|pestudio|IDA|Ghidra|静态分析",
"密钥|key|硬编码|派生|密钥提取",
"base64|解码|密文|加密数据",
"解密|decrypt|CyberChef|pycryptodome"
],
"required_terms": [
"AES",
"IDA",
"CyberChef"
]
},
{
"id": 4,
"name": "yara-rule-writing",
"prompt": "CTF 题目要求编写 YARA 规则检测一类使用 XOR 循环加密的恶意软件。已知特征:包含 XOR 循环指令序列(31 ?? 80 ?? ?? 4? 75),且文件大小小于 1MB。请编写规则。",
"expected_output": "编写包含 hex pattern 的 YARA 规则,匹配 XOR 循环特征字节序列,加文件大小条件",
"expectations": [
"YARA|rule|规则|yara规则",
"strings|$xor|十六进制|hex pattern",
"31 ??|XOR指令|80 ??|循环特征",
"condition|filesize|文件大小|1MB",
"通配符|??|4?|75|跳转指令"
],
"required_terms": [
"YARA",
"rule",
"yara规则"
]
}
]
}
{
"skill_id": "ctf-malware",
"recall_tests": [
{
"id": 1,
"type": "keyword_positive",
"description": "核心关键词",
"keywords": [
"malware",
"恶意软件",
"c2",
"yara"
]
},
{
"id": 2,
"type": "keyword_positive",
"description": "分析搜索",
"keywords": [
"pe",
"shellcode",
"混淆",
"流量分析"
]
},
{
"id": 3,
"type": "keyword_negative",
"description": "不应被OSINT召回",
"keywords": [
"geolocation",
"社交媒体"
]
}
],
"llm_tests": [
{
"id": 1,
"name": "ctf-malware-scenario",
"scenario": "CTF 恶意软件分析题给了一个 PE 可执行文件,需要找到隐藏的 C2 地址。请搜索恶意软件分析方法论。",
"max_rounds": 2,
"expect_tool_calls": [
{
"tool": "list_skills",
"keyword_contains": "malware|恶意软件|逆向|pe"
},
{
"tool": "read_skill",
"id": "ctf-malware"
}
]
}
]
}
C2 Traffic and Protocol Analysis
Table of Contents
- PCAP Analysis
- Custom Crypto Protocols
- C2 Traffic Patterns
- Network Indicators
- RC4-Encrypted WebSocket C2 Traffic
- Password Rotation in C2
- AES-CBC in Malware
- Identifying Encryption Algorithms
- Telegram Bot API for Evidence Recovery
- Poison Ivy RAT Traffic Decryption (Trend Micro CTF 2015)
---
PCAP Analysis
tshark -r file.pcap -Y "tcp.stream eq X" -T fields -e tcp.payloadLook for C2 communication patterns on unusual ports (e.g., port 21 not for FTP).
Custom Crypto Protocols
- Stream ciphers may share keystream state for both directions
- Concatenate ALL payloads chronologically before decryption
- Look for hardcoded keys in
.rodata - ChaCha20 keystream extraction: Send large nullbytes payload (0 XOR anything = anything)
- Alternative: Pipe ciphertext from pcap directly into the binary
C2 Traffic Patterns
- Beaconing: regular intervals
- Domain generation algorithms (DGA)
- Encoded/encrypted payloads
- HTTP(S) with custom headers
- DNS tunneling
Network Indicators
# Extract IPs/domains
strings malware | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
strings malware | grep -E '[a-zA-Z0-9.-]+\.(com|net|org|io)'
# DNS queries
tshark -r capture.pcap -Y "dns.qry.name" -T fields -e dns.qry.name | sort -uRC4-Encrypted WebSocket C2 Traffic
Pattern (Tampered Seal): Malware uses WSS over non-standard port with RC4 encryption.
Decryption workflow: 1. Identify C2 port from malware source (not standard 443) 2. Remap port with tcprewrite so Wireshark decodes TLS 3. Add RSA key for TLS decryption -> reveals WebSocket frames 4. Find RC4 key hardcoded in malware binary 5. Decrypt each WebSocket payload with RC4 via CyberChef
Malware communication patterns:
- Registration message: hostname, OS, username, privileges
- Exfiltration: screenshots, keylog data, file contents
- Commands: reverse shell, file download, process list
Password Rotation in C2
Pattern: C2 uses rotating passwords based on time/sequence
Analysis: 1. Find password generation function 2. Identify rotation trigger (time-based, message count) 3. Sync your decryptor with the rotation
def get_current_password(timestamp):
# Password changes every hour
hour_bucket = timestamp // 3600
return hashlib.sha256(f"seed_{hour_bucket}".encode()).digest()AES-CBC in Malware
Common key derivation:
- MD5/SHA256 of hardcoded string
- Derived from timestamp or PID
- Password-based (PBKDF2)
Analysis approach:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib
# Common pattern: key = MD5(password)
password = b"hardcoded_password"
key = hashlib.md5(password).digest()
# IV often first 16 bytes of ciphertext
iv = ciphertext[:16]
ct = ciphertext[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ct), 16)Identifying Encryption Algorithms
By constants:
- AES:
0x637c777b,0x63636363(S-box) - ChaCha20:
expand 32-byte kor0x61707865 - RC4: Sequential S-box initialization
- TEA/XTEA:
0x9E3779B9(golden ratio)
By structure:
- Block cipher: Fixed-size blocks, padding
- Stream cipher: Byte-by-byte, no padding
- Hash: Mixing functions, rounds, constants
Telegram Bot API for Evidence Recovery
Pattern (Stomaker): Malware uses Telegram bot to exfiltrate stolen data.
Recover exfiltrated data via bot token:
# If you have the bot API token from malware source:
import requests
TOKEN = "bot_token_here"
# Get updates (message history)
r = requests.get(f"https://api.telegram.org/bot{TOKEN}/getUpdates")
# Download files sent to bot
file_id = "..."
r = requests.get(f"https://api.telegram.org/bot{TOKEN}/getFile?file_id={file_id}")
file_path = r.json()['result']['file_path']
requests.get(f"https://api.telegram.org/file/bot{TOKEN}/{file_path}")---
Poison Ivy RAT Traffic Decryption (Trend Micro CTF 2015)
Pattern: PCAP contains Poison Ivy RAT (Remote Access Trojan) traffic. Poison Ivy uses Camellia cipher with the key derived from an attacker-supplied password (null-padded to key length). The default password is "admin".
# Decrypt using MITRE's ChopShop framework + FireEye Poison Ivy module
chopshop -f capture.pcap -s ./output/ "poisonivy_23x -c -w admin"Identification:
- Traffic to non-standard ports (often 3460, 65535)
- Initial handshake with 256-byte key exchange
- Encrypted data blocks with 8-byte aligned lengths
Alternative decryption (Python):
from Crypto.Cipher import Camellia
password = b"admin"
key = password.ljust(32, b'\x00')[:32] # null-pad to 256 bits
cipher = Camellia.new(key, Camellia.MODE_ECB)
plaintext = cipher.decrypt(encrypted_data)Key insight: Poison Ivy's encryption key is derived solely from the attacker password with null-byte padding — no key derivation function. The default password "admin" is commonly left unchanged. ChopShop with poisonivy_23x module automates full session reconstruction (screenshots, file listings, keystrokes). Also try common passwords: "password", "p0ison", or challenge-provided hints.
PE, .NET, and Binary Malware Analysis
Table of Contents
- PE Analysis
- Sandbox Evasion Checks
- Malware Configuration Extraction
- .NET DNS-based C2
- .NET Malware Analysis (C2 Extraction)
- PyInstaller + PyArmor Unpacking
---
PE Analysis
peframe malware.exe # Quick triage
pe-sieve # Runtime analysis
pestudio # Static analysis (Windows)Sandbox Evasion Checks
Look for:
- VM detection (VMware, VirtualBox artifacts)
- Debugger detection (IsDebuggerPresent)
- Timing checks (sleep acceleration)
- Environment checks (username, computername)
- File/registry checks for analysis tools
Malware Configuration Extraction
Common storage locations:
- .data section (hardcoded)
- Resources (PE resources, .NET resources)
- Registry keys written at install
- Encrypted config file dropped to disk
Extraction tools:
# PE resources
wrestool -x -t 10 malware.exe -o config.bin
# .NET resources
monodis --mresources malware.exe
# Strings in .rdata/.data
objdump -s -j .rdata malware.exe.NET DNS-based C2
Pattern: Deobfuscated .NET malware with DNS C2
Analysis with dnSpy: 1. Find network functions (TcpClient, DnsClient, etc.) 2. Identify encoding/encryption wrappers 3. Look for command dispatch (switch on opcode)
AsmResolver for programmatic analysis:
using AsmResolver.DotNet;
var module = ModuleDefinition.FromFile("malware.dll");
foreach (var type in module.GetAllTypes()) {
foreach (var method in type.Methods) {
// Analyze method body
}
}.NET Malware Analysis (C2 Extraction)
Tools: ILSpy, dnSpy, dotPeek
LimeRAT C2 extraction (Whisper Of The Pain): 1. Open .NET binary in dnSpy 2. Find configuration class with Base64 encoded string 3. Identify decryption method (typically AES-256-ECB with derived key) 4. Key derivation: MD5 of hardcoded string -> first 15 + full 16 bytes + null = 32-byte key 5. Decrypt: Base64 decode -> AES-ECB decrypt -> reveals C2 IP/domain
from Crypto.Cipher import AES
import hashlib, base64
key_source = '${8\',`d0}n,~@J;oZ"9a'
md5 = hashlib.md5(key_source.encode()).hexdigest()
# Key = first 15 bytes of MD5 + full 16 bytes + null (64 hex chars -> 32 bytes)
key = bytes.fromhex(md5[:30] + md5 + '00')[:32]
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(base64.b64decode(encrypted_b64))PyInstaller + PyArmor Unpacking
# Step 1: Extract PyInstaller archive
python pyinstxtractor.py malware.exe
# Look for main .pyc file in extracted directory
# Step 2: If PyArmor-protected, use unpacker
# github.com/Svenskithesource/PyArmor-Unpacker
# Three methods available; choose based on PyArmor version
# Step 3: Clean up deobfuscated source
# Remove fake/dead-code functions (confusion code)
# Identify core encryption/exfiltration logicScripts and Obfuscation Analysis
Table of Contents
- Obfuscated Scripts (General)
- JavaScript Deobfuscation
- PowerShell Analysis
- Junk Code Detection
- Hex-Encoded Payloads
- Debian Package Analysis
- Dynamic Analysis Techniques
- YARA Rules for Malware Detection
- Shellcode Analysis
- Memory Forensics for Malware
- Anti-Analysis Techniques
- VM / Sandbox Detection
- Timing-Based Evasion
- API Hashing
- Process Injection Techniques
- Environment Variable / Hostname Checks
---
Obfuscated Scripts (General)
- Replace
eval/bashwithechoto print underlying code - Extract base64/hex blobs and analyze with
file - Common deobfuscation chain: base64 decode -> gzip decode -> reverse -> base64 decode
JavaScript Deobfuscation
// Replace eval with console.log
eval = console.log;
// Then run the obfuscated code
// Common patterns
unescape() // URL decoding
String.fromCharCode() // Char codes
atob() // Base64PowerShell Analysis
# Common obfuscation
-enc / -EncodedCommand # Base64 encoded
IEX / Invoke-Expression # Eval equivalent
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($encoded))Junk Code Detection
Pattern: Obfuscation adds meaningless instructions around real code
Identification:
- NOP sleds, push/pop pairs that cancel
- Arithmetic that results in zero/identity
- Dead writes (register written but never read before next write)
- Unconditional jumps to next instruction
Filtering technique:
# Identify real calls by looking for patterns
# junk, junk, junk, CALL target, junk, junk
# Extract call targets, ignore surrounding noise
def extract_real_calls(disassembly):
calls = []
for instr in disassembly:
if instr.mnemonic == 'call' and not is_junk_target(instr.operand):
calls.append(instr)
return callsHex-Encoded Payloads
- Convert hex to bytes, try common transformations: subtract 1, XOR with key
Debian Package Analysis
ar -x package.deb # Unpack debian package
tar -xf control.tar.xz # Check control files
# Look for postinst scripts that execute payloads---
Dynamic Analysis Techniques
# Behavioral monitoring with strace/ltrace
strace -f -e trace=network,file -o trace.log ./malware
ltrace -f -o ltrace.log ./malware
# Network monitoring during execution
# Terminal 1: capture traffic
sudo tcpdump -i any -w malware_traffic.pcap &
# Terminal 2: DNS monitoring
sudo tcpdump -i any port 53 -l | tee dns_queries.log &
# Terminal 3: run sample
timeout 60 ./malware
# File system monitoring (Linux)
inotifywait -m -r /tmp /var/tmp --format '%T %w%f %e' --timefmt '%H:%M:%S' &
./malware
# Process monitoring
watch -n 1 'ps aux | grep -v grep | grep malware'
# Memory string extraction during runtime
# Run malware, then dump strings from its memory
pid=$(pgrep malware)
strings /proc/$pid/maps
cat /proc/$pid/mem 2>/dev/null | strings | grep -i flag
# Or use gdb: gdb -p $pid -batch -ex 'dump memory dump.bin 0x400000 0x500000'# Automated sandbox execution with timeout
import subprocess, os, tempfile
def run_sample(path, timeout=30):
"""Run malware sample with monitoring"""
with tempfile.NamedTemporaryFile(suffix='.pcap', delete=False) as pcap:
# Start packet capture
tcpdump = subprocess.Popen(
['sudo', 'tcpdump', '-i', 'any', '-w', pcap.name],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
# Run with strace
result = subprocess.run(
['strace', '-f', '-e', 'trace=network,file', path],
capture_output=True, text=True, timeout=timeout)
print("STDOUT:", result.stdout[:500])
print("STDERR (syscalls):", result.stderr[:2000])
except subprocess.TimeoutExpired:
print(f"Sample ran for {timeout}s (killed)")
finally:
tcpdump.terminate()
print(f"PCAP saved: {pcap.name}")Key insight: Dynamic analysis reveals runtime behavior that static analysis misses: actual C2 domains resolved, encryption keys in memory, dropped files, and anti-analysis checks that were bypassed. Always run in an isolated environment (VM snapshot, Docker container) and monitor network, filesystem, and process activity simultaneously.
---
YARA Rules for Malware Detection
# Basic YARA rule structure
cat > detect_malware.yar << 'EOF'
rule SuspiciousStrings {
meta:
description = "Detect common malware indicators"
strings:
$s1 = "cmd.exe /c" nocase
$s2 = "powershell -enc" nocase
$s3 = {4D 5A 90 00} // MZ header (hex pattern)
$s4 = /https?:\/\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/ // IP-based URL
$xor_loop = {31 ?? 80 ?? ?? 4? 75} // XOR decode loop pattern
condition:
2 of ($s*) or $xor_loop
}
EOF
# Scan files
yara detect_malware.yar suspicious_file.exe
yara -r detect_malware.yar /path/to/directory/ # Recursive scan
# Scan memory dump
yara detect_malware.yar memory.dmpCommon YARA patterns for CTFs:
rule Base64_PowerShell {
strings:
$enc = "powershell" nocase
$b64 = /[A-Za-z0-9+\/]{50,}={0,2}/
condition:
$enc and $b64
}
rule XOR_Encrypted_PE {
strings:
$mz = {4D 5A}
condition:
not $mz at 0 and filesize < 1MB
// PE without MZ header = likely XOR encrypted
}Key insight: YARA rules match byte patterns, strings, and regex against files or memory. In CTFs, write rules to detect specific obfuscation patterns (XOR loops, base64 blobs, encoded PowerShell), then apply to memory dumps or malware samples. Use yarac to compile rules for faster scanning.
---
Shellcode Analysis
# Extract shellcode from binary
objdump -d shellcode.bin -b binary -m i386:x86-64 -M intel
# Emulate shellcode with unicorn engine
python3 << 'PYEOF'
from unicorn import *
from unicorn.x86_const import *
shellcode = open('shellcode.bin', 'rb').read()
mu = Uc(UC_ARCH_X86, UC_MODE_64)
BASE = 0x400000
STACK = 0x7fff0000
mu.mem_map(BASE, 0x1000)
mu.mem_map(STACK - 0x1000, 0x2000)
mu.mem_write(BASE, shellcode)
mu.reg_write(UC_X86_REG_RSP, STACK)
# Hook syscalls to trace behavior
def hook_syscall(mu, user_data):
rax = mu.reg_read(UC_X86_REG_RAX)
print(f"syscall: {rax}")
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL)
mu.emu_start(BASE, BASE + len(shellcode))
PYEOF
# Disassemble with capstone
python3 -c "
from capstone import *
md = Cs(CS_ARCH_X86, CS_MODE_64)
code = open('shellcode.bin','rb').read()
for i in md.disasm(code, 0x0):
print(f'{i.address:#x}: {i.mnemonic} {i.op_str}')
"
# Quick analysis with scdbg (Windows shellcode emulator)
scdbg /f shellcode.binKey insight: Shellcode in CTF malware challenges is often XOR-encoded or staged. Look for decoder stubs (short loops with XOR), then extract and decode the payload. Unicorn Engine emulation is safer than running shellcode — it intercepts syscalls without executing them.
---
Memory Forensics for Malware
# Volatility 3 — analyze memory dump for malware indicators
# List processes (look for suspicious names, unusual parents)
vol3 -f memory.dmp windows.pslist
vol3 -f memory.dmp windows.pstree
# Detect hidden/unlinked processes
vol3 -f memory.dmp windows.psscan
# Dump suspicious process memory
vol3 -f memory.dmp windows.memmap --pid PID --dump
# Extract injected code (process hollowing, DLL injection)
vol3 -f memory.dmp windows.malfind
# Network connections from malware
vol3 -f memory.dmp windows.netscan
# Command-line arguments (reveals malware parameters)
vol3 -f memory.dmp windows.cmdline
# DLL list per process (detect injected DLLs)
vol3 -f memory.dmp windows.dlllist --pid PID
# YARA scan on memory dump
vol3 -f memory.dmp yarascan.YaraScan --yara-rules "rule test { strings: $s = \"flag{\" condition: $s }"Key insight: windows.malfind detects injected code by finding memory regions with PAGE_EXECUTE_READWRITE protection and no corresponding mapped file — the hallmark of process injection. Combine with windows.pstree to find processes with unexpected parent-child relationships (e.g., svchost.exe spawned by cmd.exe).
---
Anti-Analysis Techniques
Malware uses runtime checks to detect analysis environments and alter behavior. Bypass these to reach the actual malicious functionality.
VM / Sandbox Detection
Pattern: Malware checks for virtualization artifacts before executing payload. In CTFs, the "real" flag logic is behind these checks.
Key insight: Identify the detection method, then patch the check or fake the environment.
# Common VM detection checks and bypasses:
# 1. CPUID check (hypervisor bit 31 of ECX after CPUID leaf 1)
# Bypass: patch JNZ after CPUID to JMP, or run in bare metal
# In GDB: set $ecx = $ecx & ~(1<<31)
# 2. MAC address prefix (VMware: 00:0C:29, 00:50:56; VBox: 08:00:27)
# Bypass: change VM NIC MAC to real hardware prefix
# 3. Registry keys (Windows)
# HKLM\SOFTWARE\VMware, Inc.\VMware Tools
# HKLM\SYSTEM\CurrentControlSet\Services\VBoxGuest
# Bypass: delete keys or patch registry check
# 4. File/process checks
VM_ARTIFACTS = [
'vmtoolsd.exe', 'vmwaretray.exe', 'VBoxService.exe',
'qemu-ga.exe', 'sandboxie', 'wireshark.exe',
'/sys/class/dmi/id/product_name', # "VMware Virtual Platform"
'C:\\windows\\system32\\drivers\\vmmouse.sys',
]
# 5. Disk size check (VMs often have small disks)
# if total_disk < 60GB: exit()
# Bypass: expand VM disk or patch comparison
# 6. CPU count / RAM check
# if cpu_count < 2 or ram < 2GB: exit()
# Bypass: allocate more resources to VMTiming-Based Evasion
Pattern: Malware uses sleep(), GetTickCount(), or RDTSC to detect accelerated execution in sandboxes.
# Detection: large sleep followed by time check
# import time
# start = time.time()
# time.sleep(300) # 5 minutes
# if time.time() - start < 290: sys.exit() # Sandbox fast-forwarded sleep
# Bypass approaches:
# 1. Patch sleep to NOP: elf.asm(elf.symbols['sleep'], 'ret')
# 2. Hook GetTickCount/time() to return expected values
# 3. In GDB: set breakpoint after sleep, manually advance
# 4. Binary patching: change sleep(300) to sleep(0)Key insight: Look for calls to sleep, time.sleep, NtDelayExecution, GetTickCount64, QueryPerformanceCounter. If the sample just sits there doing nothing, it's likely in a sleep-based anti-sandbox check.
API Hashing
Pattern: Instead of importing functions by name (visible in strings/imports), malware resolves API addresses at runtime by hashing function names and comparing to hardcoded hash values.
# Common hash algorithms for API resolution:
# ROR13 (rotate-right 13) — most common, used by Metasploit
def ror13_hash(name):
h = 0
for c in name:
h = ((h >> 13) | (h << 19)) & 0xFFFFFFFF
h = (h + ord(c)) & 0xFFFFFFFF
return h
# DJB2 hash
def djb2_hash(name):
h = 5381
for c in name:
h = ((h * 33) + ord(c)) & 0xFFFFFFFF
return h
# CRC32-based
import binascii
def crc32_hash(name):
return binascii.crc32(name.encode()) & 0xFFFFFFFF
# Reversing: build lookup table from Windows API names
# hashdb.openanalysis.net — online API hash lookup
# ShellcodeHasher — matches hashes against known Windows APIs
# In Ghidra: find the hash comparison constant, look up in hashdb
# Pattern: loop over PEB→Ldr→InMemoryOrderModuleList, hash each export nameKey insight: When strings output shows almost no readable API names but the binary clearly does complex operations, suspect API hashing. Look for the hash function (small loop with XOR/rotate/add), then use hashdb or build a rainbow table against kernel32.dll and ntdll.dll exports.
Process Injection Techniques
Pattern: Malware injects code into legitimate processes to evade detection. Understanding the injection method helps extract the actual payload.
# Classic injection chain:
# 1. OpenProcess(target_pid)
# 2. VirtualAllocEx(remote, ..., PAGE_EXECUTE_READWRITE)
# 3. WriteProcessMemory(remote, shellcode)
# 4. CreateRemoteThread(remote, shellcode_addr)
# Process hollowing:
# 1. CreateProcess(legitimate.exe, CREATE_SUSPENDED)
# 2. NtUnmapViewOfSection(hollow out the image)
# 3. VirtualAllocEx + WriteProcessMemory (write malicious PE)
# 4. SetThreadContext (point EIP/RIP to new entry)
# 5. ResumeThread
# Detection in memory dumps:
vol3 -f memory.dmp windows.malfind # PAGE_EXECUTE_READWRITE without file backing
vol3 -f memory.dmp windows.hollowfind # Hollowed processes (VAD vs PEB mismatch)
# APC injection (no new thread):
# QueueUserAPC(shellcode_addr, target_thread, ...)
# Thread executes shellcode on next alertable wait
# For CTF: dump the injected code region and analyze separately
vol3 -f memory.dmp windows.malfind --dump --pid <PID>Environment Variable / Hostname Checks
Pattern: Malware checks for specific environment conditions (hostname, username, domain, locale) to target specific victims or avoid analysis labs.
# Common checks:
# - Hostname matches target: if socket.gethostname() != 'TARGET-PC': exit()
# - Username: if os.getlogin() in ['admin', 'sandbox', 'malware']: exit()
# - Domain membership: if 'WORKGROUP' in os.environ.get('USERDOMAIN', ''): exit()
# - Locale/language: WinAPI GetUserDefaultLangID()
# - Specific file must exist: if not os.path.exists('C:\\Users\\victim\\document.xlsx'): exit()
# Bypass: set environment variables before running
# export COMPUTERNAME=TARGET-PC
# Or patch the comparison in the binaryKey insight: If a malware sample exits immediately or behaves differently than expected, trace its API calls with strace/ltrace or step through with a debugger. Look for string comparisons against environment values early in execution.