Prerequisites
- Target system, dependencies and environment configured.
Usage
Purpose
When behaviour and strings aren't enough — you need to understand how a sample works, its exact logic, a decryption routine, or a capability that only runs under specific conditions — you read the code. Ghidra (NSA's free reverse-engineering suite) disassembles and decompiles compiled binaries into something readable. This skill covers using Ghidra effectively on malware, with the crucial discipline of knowing what to read, because reading a whole binary instruction-by-instruction is a losing game.
When to use it
Deep analysis, after triage/unpacking, when you need code-level understanding: to confirm capability, extract a hardcoded key or C2 config, understand an algorithm, or analyse logic that dynamic analysis won't trigger. It's the most time-intensive skill in the domain, so reserve it for when you genuinely need code-level answers.
Procedure
- Load the (unpacked) sample into Ghidra and let its auto-analysis run — it disassembles, identifies functions, and produces decompiled C-like pseudocode. Analyse the unpacked payload, not a packed stub (unpacking-basics skill).
- Don't read linearly — navigate to what matters. The skill is targeting your reading, not reading everything. Use anchors to jump to the interesting code:
- Strings — find an interesting string (a URL, a command, an error), then find where it's referenced in code; that's often the function that matters.
- Imports/API calls — cross-reference calls to interesting APIs (network, crypto, process injection, registry) to find the code that uses them.
- Entry point / main — orient from the top-level flow.
- Use the decompiler as your primary view. Ghidra's decompiled pseudocode is far faster to read than raw assembly; use the disassembly to confirm details the decompiler gets wrong. Read the pseudocode to understand logic, drop to assembly when precision matters.
- Rename and annotate as you go. Malware functions have no names; as you understand a function, rename it (
decrypt_config, send_beacon) and add comments. This turns an unreadable mess into a map and is how you make progress on anything non-trivial.
- Focus on the analysis goal, not completeness. You rarely need to understand every function — you need the specific thing (the C2 config, the decryption routine, the trigger condition, the capability). Follow the code toward that goal and stop when you have the answer.
- Extract what you came for — a hardcoded key/config, an algorithm, a decision point — and feed it into IoC extraction and reporting. Sometimes reversing a decryption routine lets you decode config that yields the real indicators.
Cheatsheet
load the UNPACKED payload (not the packer stub) -> let auto-analysis run
primary view = the DECOMPILER (C-like pseudocode) ; drop to asm for precision
navigate to what matters (don't read linearly)
interesting STRING -> find its XREF -> the function using it
interesting API -> XREF network/crypto/injection/registry calls -> the code
entry point / main -> top-level flow
work the code
RENAME functions/variables as you understand them (decrypt_config, send_beacon)
COMMENT your findings -> build a map out of the mess
focus on the GOAL, not completeness
need: C2 config? decryption routine? trigger condition? a specific capability?
follow code toward it, STOP when answered (you don't need every function)
extract: hardcoded keys/config, algorithms, decision points -> IoCs + report
Reading the code
- A string's cross-reference leading to a key function = the fast path; interesting strings and their XREFs are usually the shortest route to the code that matters. Start here rather than at the top.
- Calls to crypto/network/injection APIs = the capability-bearing code; cross-referencing them jumps you to what the malware actually does.
- A decryption/decoding routine = high value — reversing it often reveals a hardcoded C2 config, key, or encoded strings that yield the real indicators. Worth the effort.
- A trigger/condition check (date, environment, target check) = why dynamic analysis "did nothing"; the code reveals conditions the sandbox didn't meet.
- Decompiler output that looks wrong (odd casts, missing logic) = drop to the disassembly to confirm; the decompiler is a fast approximation, not gospel.
- A renamed, annotated function graph = your progress made visible; on anything non-trivial this is what makes the analysis tractable.
Pitfalls
- Reading linearly / trying to understand everything. Binaries are huge; instruction-by-instruction from the top never finishes. Navigate from strings and APIs to the code that matters, and target the analysis goal.
- Analysing a packed stub. You'll reverse the packer, not the malware. Unpack first (unpacking-basics).
- Not renaming/annotating. Malware code is nameless; without building a map as you go, you lose track and re-derive the same things. Rename relentlessly.
- Trusting the decompiler blindly. It's a fast approximation and can misrepresent logic; confirm critical details in the disassembly.
- Reversing when you don't need to. Disassembly is expensive; if dynamic analysis or strings answer the question, don't reverse. Reserve it for genuine code-level needs.
References
- Ghidra documentation and the official Ghidra course/book
- Practical Malware Analysis (disassembly/IDA chapters — concepts transfer to Ghidra)
- The unpacking-basics, static-triage, and extracting-iocs skills
- MITRE ATT&CK (map discovered capabilities)
Inputs
- Relevant source code, logs, network traces, or system specifications.
Outputs
- Analysis findings, security audit report, or generated code artifacts.
1---2name: disassembly-with-ghidra3description: Use when you need to read a malware sample's compiled code — using Ghidra to disassemble and decompile, and knowing what to look for instead of reading everything.4---5678## Prerequisites9- Target system, dependencies and environment configured.1011## Usage12### Purpose1314When behaviour and strings aren't enough — you need to understand *how* a sample works, its exact logic, a decryption routine, or a capability that only runs under specific conditions — you read the code. Ghidra (NSA's free reverse-engineering suite) disassembles and decompiles compiled binaries into something readable. This skill covers using Ghidra effectively on malware, with the crucial discipline of knowing *what* to read, because reading a whole binary instruction-by-instruction is a losing game.1516### When to use it1718Deep analysis, after triage/unpacking, when you need code-level understanding: to confirm capability, extract a hardcoded key or C2 config, understand an algorithm, or analyse logic that dynamic analysis won't trigger. It's the most time-intensive skill in the domain, so reserve it for when you genuinely need code-level answers.1920### Procedure21221. **Load the (unpacked) sample into Ghidra** and let its auto-analysis run — it disassembles, identifies functions, and produces decompiled C-like pseudocode. Analyse the *unpacked* payload, not a packed stub (unpacking-basics skill).232. **Don't read linearly — navigate to what matters.** The skill is targeting your reading, not reading everything. Use anchors to jump to the interesting code:24 - **Strings** — find an interesting string (a URL, a command, an error), then find where it's referenced in code; that's often the function that matters.25 - **Imports/API calls** — cross-reference calls to interesting APIs (network, crypto, process injection, registry) to find the code that uses them.26 - **Entry point / main** — orient from the top-level flow.273. **Use the decompiler as your primary view.** Ghidra's decompiled pseudocode is far faster to read than raw assembly; use the disassembly to confirm details the decompiler gets wrong. Read the pseudocode to understand logic, drop to assembly when precision matters.284. **Rename and annotate as you go.** Malware functions have no names; as you understand a function, rename it (`decrypt_config`, `send_beacon`) and add comments. This turns an unreadable mess into a map and is how you make progress on anything non-trivial.295. **Focus on the analysis goal**, not completeness. You rarely need to understand every function — you need the specific thing (the C2 config, the decryption routine, the trigger condition, the capability). Follow the code toward that goal and stop when you have the answer.306. **Extract what you came for** — a hardcoded key/config, an algorithm, a decision point — and feed it into IoC extraction and reporting. Sometimes reversing a decryption routine lets you decode config that yields the real indicators.3132### Cheatsheet3334```35load the UNPACKED payload (not the packer stub) -> let auto-analysis run36primary view = the DECOMPILER (C-like pseudocode) ; drop to asm for precision3738navigate to what matters (don't read linearly)39 interesting STRING -> find its XREF -> the function using it40 interesting API -> XREF network/crypto/injection/registry calls -> the code41 entry point / main -> top-level flow4243work the code44 RENAME functions/variables as you understand them (decrypt_config, send_beacon)45 COMMENT your findings -> build a map out of the mess4647focus on the GOAL, not completeness48 need: C2 config? decryption routine? trigger condition? a specific capability?49 follow code toward it, STOP when answered (you don't need every function)5051extract: hardcoded keys/config, algorithms, decision points -> IoCs + report52```5354### Reading the code5556- **A string's cross-reference leading to a key function** = the fast path; interesting strings and their XREFs are usually the shortest route to the code that matters. Start here rather than at the top.57- **Calls to crypto/network/injection APIs** = the capability-bearing code; cross-referencing them jumps you to what the malware actually does.58- **A decryption/decoding routine** = high value — reversing it often reveals a hardcoded C2 config, key, or encoded strings that yield the real indicators. Worth the effort.59- **A trigger/condition check** (date, environment, target check) = why dynamic analysis "did nothing"; the code reveals conditions the sandbox didn't meet.60- **Decompiler output that looks wrong** (odd casts, missing logic) = drop to the disassembly to confirm; the decompiler is a fast approximation, not gospel.61- **A renamed, annotated function graph** = your progress made visible; on anything non-trivial this is what makes the analysis tractable.6263### Pitfalls6465- **Reading linearly / trying to understand everything.** Binaries are huge; instruction-by-instruction from the top never finishes. Navigate from strings and APIs to the code that matters, and target the analysis goal.66- **Analysing a packed stub.** You'll reverse the packer, not the malware. Unpack first (unpacking-basics).67- **Not renaming/annotating.** Malware code is nameless; without building a map as you go, you lose track and re-derive the same things. Rename relentlessly.68- **Trusting the decompiler blindly.** It's a fast approximation and can misrepresent logic; confirm critical details in the disassembly.69- **Reversing when you don't need to.** Disassembly is expensive; if dynamic analysis or strings answer the question, don't reverse. Reserve it for genuine code-level needs.7071### References7273- Ghidra documentation and the official Ghidra course/book74- Practical Malware Analysis (disassembly/IDA chapters — concepts transfer to Ghidra)75- The unpacking-basics, static-triage, and extracting-iocs skills76- MITRE ATT&CK (map discovered capabilities)7778## Inputs79- Relevant source code, logs, network traces, or system specifications.8081## Outputs82- Analysis findings, security audit report, or generated code artifacts.