Depth-first RE investigation loop for a single binary or function cluster: decompile→rename→retype→comment→re-read, with context-rot guards and on-task checks. Use when triage has already identified the interesting area and the goal is full understanding: what does function X do, identify cryptographic primitives, locate C2 protocol, recover data structures. Triggers on: 'deep analysis', 'understand function', 'recover struct', 'crypto identification', 'C2 protocol', 'reverse this binary fully', 'what does this function do'.
76
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Depth-first RE for full understanding of a specific target area. Distinct from
breadth-first triage (reverser/triage) — here you don't stop at a signal,
you keep iterating until the function is fully understood.
Triage finds the surface; deep-analysis excavates one shaft. Commit to one question at a time. Context-rot (losing track of what you've already renamed or retyped) is the primary failure mode — guard against it explicitly.
Before decompiling anything, state the question in writing:
kg_add_node("hypothesis", "deep-analysis target",
props={"question": "<exact question, e.g. 'what does sub_401A20 do'>",
"binary": "/workspace/target",
"entry_function": "<hex addr or name>",
"key": "deep-analysis:entry"})Commit to one question. Do not pivot mid-session unless the current function is fully annotated and the answer is "it delegates to X".
For each function under analysis, follow this cycle exactly:
ghidra_decompile(binary="/workspace/target", function="<addr_or_name>")Read the full output before touching anything.
As soon as you understand a variable's purpose, rename it immediately:
# Via Ghidra MCP batch rename (preferred — one round trip)
# collect all your renames first, then batch:
ghidra_batch_rename(binary="/workspace/target", renames={
"sub_401A20": "decrypt_config_blob",
"local_18": "key_len",
"param_1": "encrypted_buf",
"param_2": "buf_len"
})Do not leave a decompiled function with placeholder names (param_1,
local_8, uVar1) if you know what they are.
Correct types catch bugs in decompiler reasoning:
# If param_1 is char* not int
ghidra_retype(binary="/workspace/target", symbol="decrypt_config_blob::param_1", type="char *")
ghidra_retype(binary="/workspace/target", symbol="decrypt_config_blob::local_18", type="uint32_t")Pay special attention to: size_t vs int (sign confusion), pointer-as-int patterns, struct pointer vs void*, callback function pointers.
At every branch point whose purpose is now understood:
ghidra_set_comment(binary="/workspace/target", address="0x401A3C",
comment="XOR-decrypts single byte: key[i % key_len] ^ buf[i]")After rename+retype, decompile again. The output will often look dramatically cleaner and reveal previously hidden logic.
Repeat 2a–2e until the function's purpose is unambiguous.
After each batch of tool calls, answer explicitly:
If you've called into a callee 3+ levels deep without updating the KG, that's context-rot — surface the findings upward before going deeper.
kg_add_node("note", "deep-analysis progress",
props={"function": "decrypt_config_blob",
"finding": "RC4 variant — XOR stream cipher, 16-byte key from .rdata:0x40D0C0",
"status": "complete",
"key": "deep-analysis:decrypt_config_blob"})ghidra_xrefs(binary=..., address=X).calls edge chain.High-entropy constants are the fastest path:
# Search for known crypto constants (AES S-box, RC4 init, ChaCha sigma, etc.)
grep -r "0x63636363\|0x6B617479\|0xE2280613\|0xDB3D18\|0x61707865\|0x3320646E" \
/workspace/target.bin 2>/dev/null || true
# Capa identifies crypto more reliably
capa /workspace/target --json > /workspace/capa_crypto.json
cat /workspace/capa_crypto.json | python3 -c "
import json, sys
d = json.load(sys.stdin)
for r in d.get('rules', {}).values():
if 'crypto' in r.get('rule',{}).get('namespace','').lower():
print(r['rule']['name'])
"Constants to recognize:
| Constant | Algorithm |
|---|---|
0x61707865 / expand 32-byte k | ChaCha20 / Salsa20 |
AES S-box start 0x63,0x7c,0x77,0x7b | AES |
0x67452301,0xEFCDAB89 | MD5 init |
0x6A09E667,0xBB67AE85 | SHA-256 init |
0x9E3779B9 | TEA / XTEA Δ |
0xB7E15163,0x9E3779B9 | RC5/RC6 magic |
| Byte-by-byte XOR loop with index-mod key | RC4 or custom XOR |
Once identified, rename the function accordingly and document the key schedule location if observable.
connect, WSAConnect,
send, write, curl_easy_perform..data or .rdata.# Find all large-ish .rdata blobs (>16 bytes, high entropy)
python3 -c "
import pefile, math
pe = pefile.PE('/workspace/target.exe')
for s in pe.sections:
if b'.rdata' in s.Name:
data = s.get_data()
# scan in 16-byte windows
for off in range(0, len(data)-16, 4):
chunk = data[off:off+16]
counts = [chunk.count(bytes([b])) for b in range(256)]
ent = -sum((c/16)*math.log2(c/16) for c in counts if c)
if ent > 7.0:
print(hex(s.VirtualAddress + off), 'entropy', round(ent,2))
" 2>/dev/null | head -20decrypt_c2_config. Document
algorithm + key in KG.When you see pointer arithmetic into a struct you don't have a definition for:
[param_1 + 0x28]).ghidra_create_struct(name="Config", size=0x30).ghidra_add_field(struct="Config", offset=0x00, type="char[16]", name="key")
ghidra_add_field(struct="Config", offset=0x10, type="char[64]", name="c2_host")
ghidra_add_field(struct="Config", offset=0x50, type="uint16_t", name="c2_port")status:blocked
and surface to orchestrator rather than spiraling.The deep-analysis session is done when:
kg_add_node("finding", "deep-analysis complete",
props={"question": "<original question>",
"answer": "<concise answer>",
"key_functions": ["decrypt_config_blob", "build_beacon_packet"],
"crypto": "ChaCha20 — key at .data:0x40E0A0",
"c2_format": "TLV over TCP port 4444",
"key": "deep-analysis:complete"})| Tool | Purpose |
|---|---|
ghidra_decompile | C pseudocode for a function |
ghidra_batch_rename | Rename multiple symbols in one call |
ghidra_retype | Fix type annotations |
ghidra_xrefs | Callers / callees of an address |
ghidra_create_struct | Define a data structure |
capa | High-level capability + crypto detection |
pefile / lief | PE/ELF structure access from Python |
e34afba
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.