courses

Reverse Engineering Platforms: IDA, Ghidra, and Cutter

This page introduces the three reverse engineering (RE) platforms used in this course: IDA Classroom (Hex-Rays), Ghidra (NSA), and Cutter (the Rizin-based GUI). It assumes you are already comfortable reading x86 assembly and have worked through basic malware triage — extracting strings, checking imports, examining PE headers, and running file/hash/entropy checks. This page picks up where triage ends: you have an interesting binary, and now you need to understand what it actually does.

All three tools attempt to solve the same core problem — turn a binary back into something a human can reason about — and they share most of the same vocabulary. Once you know how to navigate one, the other two feel familiar. The differences show up in cost, licensing, decompiler quality, debugger integration, and scripting ecosystems.


What an RE Platform Does

A reverse engineering platform is a workbench for static binary analysis. Every one of these tools does the following things, just with different names and hotkeys:

  1. Loader — parses the executable format (PE, ELF, Mach-O, raw binary, firmware image) and maps sections into a virtual address space the same way the OS loader would.
  2. Disassembler — converts machine code into assembly, identifies function boundaries, and recovers stack frames and parameter layouts.
  3. Cross-referencer — builds a bidirectional index of “who calls this function,” “who reads this string,” and “where does this jump come from.” This is the single most important feature for analysis work; you will use it constantly.
  4. Decompiler — translates assembly into C-like pseudocode. All three tools now have a decompiler, though their quality and availability differ.
  5. Database — stores your annotations (renames, comments, type information, structure definitions) so your analysis survives closing the program.
  6. Scripting / plugin interface — lets you automate repetitive tasks and build on top of the platform.

The workflow is the same everywhere: load → auto-analyze → navigate from known starting points (imports, strings, entry point) → rename and comment as you understand code → iterate until the behavior is clear.


The Three Platforms at a Glance

Feature IDA Classroom Ghidra Cutter
License / cost Free for educational use (per-student license file, non-transferable) Free and open source (Apache 2.0) Free and open source (GPLv3)
Developer Hex-Rays US National Security Agency Rizin Organization
First released 1991 (IDA); Classroom edition recent 2019 (publicly released) 2018
Implementation C++ native binary Java (requires JDK 21) Qt/C++ frontend over Rizin (C)
Primary view Graph view (toggle with Space) Listing window + Decompiler side-by-side Disassembly + Graph + Decompiler, freely arranged
Decompiler Cloud-based (Classroom: x86, x86-64, ARM-32, ARM-64) Native, full-featured, recovers C++ classes Ghidra decompiler via rz-ghidra + jsdec
Debugger Yes (local and remote; gdb, WinDbg, Bochs, etc.) Yes (added in recent versions; less mature) Yes (via Rizin; gdb/lldb/windbg/native)
Architecture support Classroom: x86/x64/ARM32/ARM64 ~30 architectures including PPC, MIPS, SH-4, 6502, PIC Very broad (Rizin inherits from radare2’s esil engine)
Scripting IDC, IDAPython Java plugins, Jython/PyGhidra Rizin commands, Python plugins, C++ plugins
Project model Single .idb / .i64 database per binary Project contains many binaries; supports shared multi-user repos Rizin project files (.rzdb)

The one-sentence summary: IDA is the industry reference with the polished UI and the best signature database; Ghidra has the best decompiler and scales to multi-binary projects; Cutter is the lightweight Rizin-backed option that lets you drop to a command-line console whenever the GUI gets in the way.


Installation and Licensing

IDA Classroom

See the IDA Classroom installation page. Each student receives a pre-activated license registered to their PSU email; download the .hexlic file from the My Hex-Rays portal and place it in the install directory or home folder.

Ghidra

Download a pre-built release from the Ghidra GitHub releases page. Requires JDK 21 (64-bit). Extract the archive and launch:

# Linux / macOS
./ghidraRun

# Windows
ghidraRun.bat

On REMnux, Ghidra is pre-installed; just type ghidra at the shell.

Cutter

Download from the Cutter releases page. Platform packages:

chmod +x Cutter-v*-x86_64.AppImage
./Cutter-v*-x86_64.AppImage

Cutter bundles Rizin; no separate installation required. REMnux ships with Cutter as well.


The Concepts You Need First

Before walking through each tool, here are the concepts that show up in all three. Learn them once and the platform-specific terminology follows.

Loaders and Base Addresses

When a platform loads a binary, it parses the container format and lays the sections out in virtual memory exactly as the OS loader would. This is why the addresses you see (0x00401000, 0x10001757) match what you’d see at runtime in a debugger. Malware frequently appends shellcode or encrypted blobs after the normal PE sections; the loader won’t include these by default. All three platforms offer a “raw binary” or “manual load” option to force every byte into the analysis view.

Auto-Analysis

After loading, each tool runs an analysis pass that starts at the entry point, follows control flow through call/jmp/jcc instructions, marks function boundaries, recovers stack frames, and identifies strings and data. This takes anywhere from a few seconds (small EXEs) to several minutes (statically linked binaries). Let auto-analysis finish before you start working — navigating into unanalyzed regions will confuse you.

Disassembly Views: Linear vs. Graph

In all three tools, edge color conveys branch semantics (taken/not-taken/unconditional). Upward-pointing edges are loops.

Decompilers

A decompiler lifts assembly into C-like pseudocode. This is not the original source — variable names are synthesized, control-flow may be restructured, and types are guessed from usage — but it is dramatically easier to read than assembly for most functions. The three tools handle decompilation differently:

Workflow tip: read the decompiler output first to form a hypothesis, then drop to assembly to verify the details. Don’t trust the decompiler blindly — optimized or obfuscated code produces misleading pseudocode.

Cross-References (XRefs)

Every tool tracks two categories:

Cross-references are how you move through a binary productively. You find an interesting API call in Imports → follow its xrefs to see every caller → rename the caller based on what it’s doing → follow its xrefs, and so on.

Renaming and Commenting

Auto-generated names like sub_401000, FUN_00401000, fcn.00401000, var_8, and arg_4 tell you nothing. As soon as you understand what a function or variable does, rename it. All three tools propagate the new name to every reference. Add comments for the why (non-obvious constraints, observed behavior, references to external documentation) rather than the what (which the code already says).

The Database / Project

Your analysis is saved in a per-binary database:

Save often. None of these tools have a crash recovery model as reliable as modern IDEs, and large malware samples can provoke interesting bugs.


Getting Started with IDA

Loading a File

Drag the binary onto IDA or use File → Open. IDA’s loader dialog asks you to confirm the file format, processor, and loading options. Accepting defaults works for almost all PE/ELF malware; the two options worth knowing are:

Let auto-analysis complete before doing anything else (the progress bar at the bottom).

The Interface

The main window is the disassembly view, which opens in graph mode by default. Press Space to toggle between graph and text (linear) modes.

Subviews you will use constantly, found under View → Open Subviews:

At the bottom of the toolbar is the navigation band, a color-coded map of the binary’s address space. Dark blue is user-written code — focus your analysis there.

Action Shortcut
Jump to address or name G
Jump to file offset Jump → Jump to File Offset
Toggle graph / text mode Space
Open pseudocode (decompile current function) F5 (opens in new tab) or Tab (toggles)
Back / forward in history Esc / Ctrl+Enter
Follow link (jump target, string, etc.) double-click or Enter
Xrefs to the item under cursor X
Xrefs from the current address Ctrl+J

Annotation

Action Shortcut
Rename N
Local comment :
Repeatable comment (shows at xrefs) ;
Define as code C
Define as data D
Define as string A
Undefine U
Create function P
Standard symbolic constant M

The M shortcut is especially useful when you see push 80000000h — pressing M lets you replace the literal with GENERIC_READ, instantly revealing that the nearby call is CreateFile.

Decompiler

Press F5 on any function to open the Pseudocode view in a new tab. Renames and type edits in the pseudocode propagate to the disassembly view and vice versa. Right-click a variable → Set lvar type to apply a C type; this often cleans up casts and reveals structure access.


Getting Started with Ghidra

Creating a Project

Ghidra organizes work into projects, which hold one or more binaries plus your annotations. On first launch, create a project via File → New Project → Non-Shared Project, pick a directory, and name it. Projects persist across sessions; you can import many binaries into the same project and cross-reference between them (useful for malware families with multiple components).

Importing and Analyzing

Drag a binary into the project window, or use File → Import File. Ghidra auto-detects the format and opens an import dialog; the defaults are almost always correct. Once imported, double-click the binary to open it in the CodeBrowser, then say Yes to the auto-analyze prompt. The default analysis options are reasonable; for malware, leave Decompiler Parameter ID and Stack enabled.

The CodeBrowser

The CodeBrowser is Ghidra’s main analysis environment. The default layout shows:

Opening the Function Graph (Window → Function Graph, or the icon in the toolbar) gives you a graph view equivalent to IDA’s graph mode.

Action Shortcut
Go to address or symbol G
Back / forward in history Alt+Left / Alt+Right
Show references to cursor Ctrl+Shift+F (or right-click → References → Show References To)
Show references from cursor Ctrl+Shift+E
Open Function Graph Window → Function Graph
Open Decompiler if closed Window → Decompiler
Find next function Ctrl+Shift+F in Functions window

Annotation

Action Shortcut
Rename label / function L
Add comment ; (opens comment dialog with all five types)
Cycle byte size (byte → word → dword → qword) B
Cycle string type
Cycle float type F
Define function at cursor F (in listing when on undefined bytes)
Disassemble D
Undo Ctrl+Z

Ghidra’s comment system offers five distinct types (EOL, Plate, Pre, Post, Repeatable), all reachable from the single ; dialog. Use plate comments to mark section headers (“— Decryption routine —”) and EOL comments for inline notes.

Decompiler Workflow

The decompiler is where you spend most of your time in Ghidra. Key operations:

Multi-Binary Projects

Ghidra’s killer feature for malware work is multi-binary projects. Import a dropper, its second-stage payload, and any dropped DLLs into the same project. You can cross-reference symbols across binaries and use Version Tracking (Tools → Version Tracking) to compare variants of the same family.


Getting Started with Cutter

Loading a File

Launch Cutter and pick Open File. The load dialog shows detected architecture, bits, OS, and base address — usually correct. For shellcode or firmware, toggle Load in write mode, Load bin info, and Use virtual addressing as needed. Click Ok and Cutter runs Rizin’s auto-analysis (aaa under the hood).

The Interface

Cutter’s UI is fully dockable: every panel (widget) can be dragged, detached, or closed. The default layout includes:

Close unused panels via Windows → [panel name] and save your preferred layout with Windows → Save Layout.

Action Shortcut
Go to address / symbol G
Toggle disassembly / graph Space
Back / forward Alt+Left / Alt+Right
Follow reference at cursor Enter
Show xrefs X
Seek to entry point . (period)
Toggle decompiler sync with cursor sync button in decompiler toolbar

Annotation

Action Shortcut
Rename N
Add comment ;
Define function P
Undefine function U
Edit function signature right-click → Edit function
Add flag (label) Shift+N

The Rizin Console

The console at the bottom exposes the full Rizin command surface. A few commands worth knowing:

Command Effect
aaa Re-run full analysis
afl List all functions
pdf @ main Print disassembly of main
izz List all strings (not just those in data sections)
axt <addr> Show xrefs to address
/ <string> Search for string
? Help

Rizin uses an operation-on-what @ where syntax. pdf @ 0x401000 prints function disassembly at 0x401000. This is Cutter’s escape hatch when the GUI doesn’t expose what you need.

Decompiler Selection

Switch decompiler engines via the dropdown in the Decompiler panel header:

For serious analysis, always use the Ghidra backend.


Side-by-Side: Common Operations

Task IDA Ghidra Cutter
Go to address G G G
Toggle graph/text Space Window → Function Graph Space
Decompile current function F5 always visible (right pane) always visible (Decompiler panel)
Rename N L N
Add comment : or ; ; ;
Xrefs to X Ctrl+Shift+F X
Back / forward Esc / Ctrl+Enter Alt+Left / Alt+Right Alt+Left / Alt+Right
Undefine U C (clear) U
Define as function P F P
Define as string A cycle Ay (via console)
Standard constant M right-click → Set Equate right-click → Set as
Apply struct type T drag from Data Type Manager right-click → Structure offset
Scripting console IDAPython (File → Script File) Window → Python Console (Rizin commands) or Python plugin

A Suggested First-Binary Workflow

This workflow applies to all three tools. The specifics of how you do each step are covered above.

  1. Triage recap: before loading anything, you should already know the file’s hash, architecture, import table highlights, and any obvious strings. If you don’t, go back to triage.
  2. Load and let auto-analysis finish. Don’t touch anything until the progress bar clears.
  3. Scan Imports. Flag network APIs (WSAStartup, connect, HttpSendRequest), process manipulation (CreateProcess, WriteProcessMemory, CreateRemoteThread), persistence (RegSetValue, CreateService), crypto (CryptEncrypt, BCryptEncrypt), and file I/O (CreateFile, WriteFile).
  4. Scan Strings. Look for URLs, file paths, registry keys, mutex names, user-agent strings, ransom notes, and error messages. Double-click interesting strings to jump to the code that uses them.
  5. Find main (or WinMain, or DllMain). Start from the entry point and follow calls.
  6. Decompile each called function. Rename as you identify behavior: sub_401200 becomes resolve_c2_domain; FUN_00402000 becomes build_rc4_key.
  7. Follow xrefs from imports you flagged in step 3. If CreateProcessA is only called in one place, you want to read that function first.
  8. Save frequently.
  9. When stuck, toggle views. If the decompiler output is confusing, read the assembly. If the assembly is too tedious, check the decompiler. If both are confusing, look at the graph — the shape of the control flow sometimes reveals the construct (loop, switch, error handling) faster than either text view.

Scripting and Automation

All three platforms expose their analysis database through scripting APIs. You don’t need these for basic analysis, but they become essential once you start dealing with obfuscated or packed samples.

Platform Languages Typical use case
IDA IDC (built-in), IDAPython Automated string decryption, batch renaming, custom analyzers
Ghidra Java, Jython, PyGhidra (CPython3) Headless batch analysis, custom decompiler transformations, Version Tracking
Cutter Python plugins, C++ plugins, Rizin commands Quick one-liners via the console, Python scripts for custom widgets

For classroom exercises, IDAPython scripts are usually the most approachable. Ghidra’s Script Manager (Window → Script Manager) ships with hundreds of example scripts that demonstrate the API.


Choosing a Tool

You will use all three in this course. In practice, working analysts tend to settle on a primary tool and use others as needed:

You’ll develop strong opinions about which one feels right; they’re all correct opinions. What matters is that you can navigate any binary handed to you in any of the three.


Troubleshooting

Problem Cause / fix
IDA hangs on load Very large binary or statically-linked runtime; wait, or disable some analysis passes in Options → General → Analysis
Ghidra decompiler shows UNRECOVERED_JUMPTABLE Indirect jump (virtual call or computed jump); right-click the jump → Create Jump Table, or fix parameter types upstream
Cutter decompiler is empty or wrong Switch backend from jsdec to Ghidra in the decompiler toolbar
Functions tab is empty Auto-analysis didn’t run or was skipped; trigger it manually (IDA: Options → Analysis; Ghidra: Analysis → Auto Analyze; Cutter: aaa in console)
Can’t see PE header / resource section Load manually (IDA: Manual Load checkbox; Ghidra: Import format options; Cutter: toggle Load bin info)
Variable names don’t propagate You renamed in the decompiler but the disassembly didn’t update, or vice versa — save the project and refresh the view

Further Reading

Official documentation

Books

Community writeups

Source repositories