/TOOLS · 2026-07-22
The reverse-engineering desk: what each tool is for
Identify, decompile, confirm. The tools only make sense as a sequence.
People ask “IDA or Ghidra?” First: what is the file. Then: who is allowed to open it. Then: which view of it is a hypothesis, and which view is a measurement.
Everything here assumes an offline sample and a written authorization. No production attach, no “just this one vendor box on the internet.”
Identify before you decompile
file, readelf/otool, objdump -d | head, hashes. You want architecture, stripped or not, packed or not, linked how. A 40 MB “firmware.bin” is not an ELF. Opening it in IDA as raw x86 is how you waste a day.
strings is a map of what the author left readable. Use it to name targets (“dropbear”, “uboot”, “JNI_OnLoad”), not to declare findings.
sha256sum sample
file sample
readelf -h sample 2>/dev/null || otool -hv sample
# packer hint: high entropy + tiny readable stub
Decompilers are hypotheses
Ghidra
Default on our desk. Free, headless, good enough decompiler, SLEIGH for odd ISAs. Java, slow to start, excellent for “analyze this folder of ELFs overnight.” If the customer has no IDA seats, this is the report’s screenshot.
IDA Pro + Hex-Rays
Still the industry default when the decompiler is the product: FLIRT, processor modules, the graph people already know how to read. We open it when the customer already paid for it, or when Hex-Rays is clearly better on that compiler.
Binary Ninja
BNIL is the reason to buy it: a stable intermediate language you can script without fighting the GUI. Smaller processor coverage than Ghidra. We use it when the question is “rewrite this parser in Python,” not “what is this PowerPC VLE blob.”
radare2 / rizin
Pipes. Headless by nature. Ugly graphs, unmatched for “give me the xref to this immediate from a script.” We teach r2 as the thing that runs in CI.
Capstone / Keystone / Unicorn
Libraries, not products. Capstone disassembles a buffer. Keystone assembles. Unicorn executes a snippet. Together they are the offset-oracle: the decompiler guessed a struct; the emulator votes.
How we actually combine them
One sequence, almost every time:
- Hash and file. If packed, unpack or stop and say packed.
- Load in Ghidra (or IDA if that is the house tool). Do not rename 400 functions on day one.
- Find the parser, the update path, or the JNI bridge, the thing in scope.
- Treat recovered types as fiction until confirmed.
- Confirm with Unicorn or QEMU on a slice, or with a debugger on a device you own.
- Write the layout the bytes actually use. That is the deliverable, not the decompiler listing.
identify → decompile → confirm → write
file/readelf Ghidra/IDA Unicorn/QEMU struct notes
strings BN (optional) Frida (owned) risk register
If you skip confirm, you are shipping Ghidra’s opinion. We have been wrong that way. Unicorn on a slice is the vote; the decompiler window is the draft.
What we do not combine
We do not chain “decompiler → copy-paste into a consumer chatbot → publish.” Customer samples stay in the tenant. The model, if used, sees a function or a calling convention, not the whole firmware.
Related