Tools

Reverse Engineering (2/5): static analysis with Ghidra, IDA and Binary Ninja

TL;DR

Static analysis is not reading every function; it is finding an anchor via strings and xrefs, then renaming and retyping iteratively. Free Ghidra is the default place to start.

The first time you open a binary in a decompiler, you see thousands of functions called FUN_00401a30 and variables called local_28. Reading them all is impossible. Part 2 of the Reverse Engineering for Developers series covers static analysis — understanding a program without running it: choosing a tool, the first 15 minutes, and turning decompiler output into something that reads like real source code.

Choosing a tool

ToolCostStrengthsBest for
Ghidra (NSA)Free, open sourceStrong decompiler, many architectures, Java/Python scriptingDefault choice for learners and teams
IDA Pro / IDA FreeCommercial; Free edition is limitedIndustry standard, FLIRT library signatures, many pluginsProfessional malware and vulnerability work
Binary NinjaCommercialClean IL layers, strong Python APIAutomation and custom analyses
radare2 / Rizin / CutterFreeScriptable CLI, runs anywhereQuick triage on servers

Pick one and go deep; the concepts transfer between tools.

The first 15 minutes

  1. Identify: file, checksec, Detect It Easy — architecture, compiler, packer, protections (PIE, NX, canary, RELRO).
  2. Strings and imports: flag URLs, crypto names, error messages, registry keys.
  3. Find an anchor: start from main (on Linux, the first argument to __libc_start_main) or from xrefs to an interesting string or import, such as "invalid license".
  4. Work outward: follow callers and callees; ignore library code.

Making the decompiler readable

The real work is iterative renaming and retyping:

  • Rename immediately once you have a guess (L in Ghidra, N in IDA). A wrong name you fix later beats no name.
  • Set function signatures: once param_1 is typed as Config *, the type propagates to every caller.
  • Create structs: when *(int *)(param_1 + 0x18) keeps appearing, right-click, Auto Create Structure, and name each field.
  • Apply library signatures: FLIRT (IDA) and Function ID (Ghidra) recognise statically linked libc, OpenSSL and zlib, removing large numbers of functions from view.
  • Spot crypto by its constants: 0x67452301 (MD5/SHA-1), 0x6A09E667 (SHA-256), the AES S-box starting 63 7C 77 7B.
  • Comment and bookmark every finding; this is a long investigation.

Language-specific notes

  • C++: use RTTI and vtables to recover class hierarchies; demangle with c++filt.
  • Go: binaries keep a pclntab table with function names even when stripped.
  • Rust: heavy inlining and long mangled names; panic strings leak source file paths.
  • .NET / Java: these are bytecode — ILSpy/dnSpyEx or jadx/CFR give you near-original source.

Automation

Ghidra's headless mode lets you batch-analyse binaries with scripts:

$GHIDRA_HOME/support/analyzeHeadless /tmp/proj MyProj \
  -import ./target.bin -postScript MyScript.py

Risks and caveats

  • Decompilers can be wrong: output is a best guess; when in doubt, check the assembly or confirm with dynamic analysis (part 3).
  • Avoid rabbit holes: start with a concrete question ("where is the key derived?") so you don't wander through unrelated code.
  • Legal scope: only analyse software you have the right to analyse.

How to apply it

  • Dev: grab an easy crackme from crackmes.one, open it in Ghidra, find the password check, rename every variable and write down the valid input — without running it.
  • Tech Lead: use Ghidra to vet closed-source libraries before shipping them: does it talk to the network, does it hardcode anything?
  • PM: free Ghidra lets a team start without licence costs; buy IDA or Binary Ninja only when the workload really needs it.

Sources & references

  1. Ghidra Software Reverse Engineering Framework — NSA
  2. NationalSecurityAgency/ghidra — GitHub
  3. crackmes.one — crackmes.one
  4. Reverse Engineering for Beginners — Dennis Yurichev