Cross-References, Renaming, and Annotation
Why Annotation Is Essential
Raw Ghidra output is filled with auto-generated names like FUN_00401030 and DAT_00403000. These names tell you nothing about what the code does. The act of renaming functions, variables, and data labels as you understand them is what transforms an impenetrable wall of assembly into a readable analysis. Annotation is not optional cleanup -- it is the core analytical process.
The Transformation
Before annotation:
void FUN_00401030(void) {
FUN_00401080(DAT_00403000, 0x50);
local_10c = FUN_00401130(0, DAT_00403000, 0x1bb, 0, 0, 3, 0, 0);
FUN_004010c0(local_10c, DAT_00403200, 0x100);
}
After annotation:
void establish_c2_session(void) {
xor_decrypt(g_encrypted_c2_domain, 0x50);
hConnection = InternetConnectA(0, g_encrypted_c2_domain, 443, 0, 0, INTERNET_SERVICE_HTTP, 0, 0);
send_beacon(hConnection, g_system_fingerprint, 256);
}
The second version tells the complete story: the function decrypts a C2 domain, connects to it on port 443, and sends a system fingerprint beacon. This is the goal of annotation.
Cross-References (XRefs) -- The Analyst's Best Tool
Cross-references answer the fundamental question: "Where is this function, variable, or data used?" They are the single most important navigation mechanism in Ghidra.
Viewing Cross-References
- Click on any function name, data label, or symbol
- Press
X(or right-click > References > Show References To) - A table appears listing every location that references the selected item
XRef Types Explained
| Type | Symbol | Meaning |
|---|---|---|
| Call (c) | (c) | A CALL instruction targets this function |
| Data Read (r) | (r) | This data is read at the referencing location |
| Data Write (w) | (w) | This data is written at the referencing location |
| Unconditional Jump | (j) | A JMP instruction targets this address |
| Conditional Jump | (j) | A conditional branch (Jcc) targets this address |
XRef Analysis Strategies
Strategy 1: API-driven analysis (most effective for malware)
- Open the Symbol Tree > Imports
- Select a suspicious API (e.g.,
CreateFileA,RegSetValueExA,InternetOpenA) - Press
Xto see every function that calls this API - Navigate to each caller to understand how the API is used
- Rename the calling function based on its purpose
Strategy 2: String-driven analysis
- Open Window > Defined Strings to see all strings in the binary
- Look for suspicious strings: URLs, file paths, registry keys, commands
- Double-click a string to navigate to its location in the data section
- Press
Xon the string to find which function references it - The referencing function reveals how the string is used
Strategy 3: Function popularity analysis
- Functions with many callers (many incoming XRefs) are utility functions: decryption routines, string builders, logging
- Functions with many callees (many outgoing calls) are orchestrators:
main(), initialization, command dispatchers - Functions called from only one location are often specific-purpose: a single persistence mechanism, a single exfiltration method
The Function Call Tree
Ghidra provides Window > Function Call Trees which shows both:
- Incoming Calls -- every function that calls the current function
- Outgoing Calls -- every function the current function calls
This is invaluable for understanding a function's role in the overall program architecture without manually tracing each XRef.
Renaming: Building the Narrative
Renaming Functions
- Click on the function name (in Listing or Decompiler)
- Press
L(Label) to open the rename dialog - Type a descriptive name following a consistent convention
Naming conventions for malware analysis:
| Function Purpose | Naming Pattern | Example |
|---|---|---|
| Network communication | verb_network_object | send_beacon_http, receive_c2_command |
| File operations | verb_file_object | drop_payload_to_temp, read_config_file |
| Persistence | install_persistence_type | install_run_key, create_scheduled_task |
| Crypto/encoding | algorithm_operation | xor_decrypt_buffer, base64_decode |
| Anti-analysis | check_condition | check_debugger_present, detect_vm_artifacts |
| Data collection | collect_data_type | collect_system_info, harvest_browser_creds |
Renaming Variables
- In the Decompiler view, right-click a variable
- Select Rename Variable (or press
L) - Use names that describe the data, not the type
Good variable names: c2_domain, xor_key, file_handle, beacon_interval, encoded_payload
Bad variable names: var1, temp, x, buf (too generic to be useful)
Renaming Data Labels
- Click on a
DAT_XXXXXXXXreference in the Listing or Decompiler - Press
Lto rename - Use the
g_prefix for global data:g_encrypted_c2_config,g_mutex_name,g_xor_key
Retyping Variables and Parameters
Ghidra's auto-detected types are often too generic. Correcting types dramatically improves decompiler output readability.
How to Retype
- In the Decompiler view, right-click a variable or parameter
- Select Retype Variable (or press
Ctrl+L) - Enter the correct type
Common Retypes
| Ghidra Auto-Type | Context Clue | Correct Type |
|---|---|---|
undefined4 | Return value of CreateFileA | HANDLE |
undefined4 | Used in arithmetic | int or DWORD |
undefined4 | Passed to RegSetValueEx as type | DWORD (REG_SZ, REG_BINARY, etc.) |
undefined * | Passed where a string is expected | char * or LPCSTR |
undefined * | Passed to VirtualAlloc | LPVOID |
undefined8 | 64-bit handle or pointer | HANDLE, size_t, LPVOID |
Applying Data Type Archives
Ghidra ships with Windows API data type archives that define parameter names and types for thousands of Windows APIs:
- Open File > Parse C Source or apply a
.gdtarchive - For 32-bit: use
windows_vs12_32.gdtorwinapi_32.gdt - For 64-bit: use
windows_vs12_64.gdtorwinapi_64.gdt - After applying, Ghidra automatically labels API parameters with their correct names
Analyst Tip: After loading a data type archive, re-run Analysis > One Shot > WindowsPE x86 Propagate External Parameters. This propagates the named parameters to all call sites, turning
param_1, param_2, param_3intolpFileName, dwDesiredAccess, dwShareMode.
Comments: Documenting Your Analysis
End-of-Line (EOL) Comments
- Click at the end of a disassembly line in the Listing view
- Press
;(semicolon) - Add a short inline explanation
Use for: explaining magic numbers, noting what a register holds, clarifying a non-obvious instruction.
Pre-Comments
- Right-click in the Listing > Comments > Set Pre-Comment
- Appears above the instruction as a block comment
- Use for: section headers, block descriptions, analysis notes
Plate Comments
- Right-click a function name > Set Plate Comment
- Appears as a decorative header above the entire function
- Ideal for function summaries:
/***********************************************************
* xor_decrypt_buffer
* Decrypts a buffer using single-byte XOR
* Params: buffer (char*), key (byte), length (int)
* Called from: establish_c2_session, load_config
* Note: Key 0x50 used for C2 config, 0x37 for strings
***********************************************************/
Bookmarks: Marking Key Locations
For long analysis sessions (hours or days), bookmarks help you return to important locations:
- Click on an address in the Listing view
- Press
Ctrl+Dto add a bookmark - Add a descriptive note: "C2 decryption routine", "persistence install", "command dispatcher"
- View all bookmarks via Window > Bookmarks
- Double-click any bookmark to navigate directly to it
Suggested Bookmark Categories
| Category | What to Bookmark |
|---|---|
| C2 | C2 initialization, beacon function, command handler |
| Persistence | Registry write, service creation, scheduled task |
| Crypto | Decryption routines, key derivation, encoding functions |
| IOC | Hardcoded IPs, domains, file paths, mutex names |
| TODO | Functions you need to revisit or investigate further |
Practical Workflow: Annotating a Function
- Select a function from the Symbol Tree or navigate via XRef
- Read the Decompiler output to get a high-level understanding
- Identify API calls and rename the function based on its purpose
- Rename parameters using Windows API documentation as a guide
- Retype variables where Ghidra's auto-detection is wrong
- Add a Plate Comment summarizing the function
- Add EOL comments for non-obvious logic or magic numbers
- Bookmark the function if it is important for your analysis report
- Press
Ctrl+Sto save your work
