Getting Started with Ghidra
Prerequisites
- Download and install Ghidra
- Install Java runtime (required by Ghidra)
- Follow Ghidra’s installation guide for your platform
Creating a New Project
- Launch Ghidra
- File → New Project or press
Ctrl+N - Select Non-Shared Project and click Next
- Choose a directory and project name, then click Finish
Importing FFXIV Executable
- File → Import File or press
i - Navigate to your FFXIV installation:
- Windows:
C:\Program Files (x86)\SquareEnix\FINAL FANTASY XIV - A Realm Reborn\game
- Windows:
- Select
ffxiv_dx11.exeand click Select File To Import - Accept default import settings and click OK
- Double-click the imported file in the project window
Initial Analysis
On first opening, Ghidra will prompt you to analyze:- Click Yes when asked to analyze
- Accept the default analysis options (or customize as needed)
- Click Analyze
- Wait for analysis to complete (this can take several minutes)
Initial analysis is a good time to install script dependencies while you wait.
Installing Script Dependencies
Ghidra uses an embedded Jython (Java implementation of Python 2) interpreter, which makes dependency installation slightly more complex than IDA Pro.Step 1: Install Python 2
Download and install Python 2.7.18 (or any Python 2.7.x version).Step 2: Install Required Packages
Run this command, replacing<YourGhidraFolder> with your Ghidra installation path:
If you have multiple Python versions installed, use the full path to the Python 2 executable.
Step 3: Add Script Directories
- In the CodeBrowser window, click the Script Manager icon (or Window → Script Manager)
- Click the Manage Script Directories button (folder icon)
- Click the + button to add directories
- Add both:
FFXIVClientStructs/ida(contains ffxiv_idarename.py)FFXIVClientStructs/Ghidra/scripts(contains SigScanner.java and others)
- Click OK
Step 4: Configure Script Keybindings
- In Script Manager, select
__UserScriptscategory - You should see all FFXIVClientStructs scripts
- Right-click scripts to assign keybindings:
- SigScanner.java →
Ctrl+Alt+S(default) - ffxiv_idarename.py → Your preference
- SigScanner.java →
- Check the box next to each script to enable it
Understanding Ghidra Naming
Ghidra’s auto-analysis creates default labels based on what it detects:| Label Format | Meaning |
|---|---|
FUN_14####### | Function |
PTR_FUN_14####### | Pointer to function |
DAT_14####### | Data |
LAB_14####### | Code label (not a function) |
SUB_14####### | Subroutine |
14 because the default Windows 64-bit image base is 0x140000000.
Address Translation
When you see an address in Dalamud like:- Press
g(Go To…) - Enter:
141A0D480 - Press Enter
Available Scripts
ffxiv_idarename.py
Despite the name, this script fully supports Ghidra through the abstraction layer.What It Does
Ingests data.yml and renames symbols throughout the disassembly:- Global variables:
DAT_*→g_FloatOne - Functions:
FUN_*→Client::System::Framework::Framework.ctor - Vtables: Unnamed addresses →
vtbl_Component::GUI::AtkResNode - Virtual functions: With inheritance tracking
- Instances: Named global pointers to classes
Running the Script
- Open Script Manager (
Window → Script Manageror toolbar icon) - Navigate to
__UserScripts - Find
ffxiv_idarename.py - Right-click → Run Script (or use your keybinding)
- Wait for completion (watch console for progress)
Example Transformation
Before running the script:GetRowBySheetIndexAndRowIndex are already applied from data.yml.
Vtable Visualization
The script adds inheritance trees as comments to vtables: Before:Ghidra-Specific Function Handling
The Ghidra implementation handles different naming patterns:| Current Name | Action |
|---|---|
FUN_*, LAB_*, SUB_*, DAT_* | Rename to class.function |
thunk_* | Strip prefix and rename |
_purecall | Skip (named in derived class) |
| Already named | Update if changed in data.yml |
/home/daytona/workspace/source/ida/ffxiv_idarename.py:372-407 for implementation details.
SigScanner.java
Generates byte pattern signatures for functions that work across game patches.What It Does
Creates the smallest unique signature for a function:- Reads instruction bytes at cursor position
- Replaces dynamic offsets with wildcards (
??) - Tests signature uniqueness in
.textsection - Copies result to clipboard
How Signatures Work
Consider this instruction sequence:e4 69 03 00 and c2 eb 04 02 are offsets that change with each patch. Wildcarded signature:
Using SigScanner
- Navigate to the instruction you want a signature for
- Place cursor on the instruction
- Press
Ctrl+Alt+S(or your configured keybinding) - The signature is generated and copied to your clipboard
- Paste into your code or data.yml
If you place the cursor on the first instruction of a function, SigScanner will find a caller of that function instead (useful for Dalamud signatures).
Configuration
Edit SigScanner.java to customize behavior:/home/daytona/workspace/source/Ghidra/scripts/SigScanner.java:22-28.
Common Issues and Solutions
Ghidra’s analysis sometimes produces different results than IDA. Here are common issues when running ffxiv_idarename.py.Function Appears Read-Only
In the Symbol Tree, virtual functions may appear in two places:- Functions node (light blue) - Editable
- Labels node (dark blue) - Read-only, grayed decompiler
- Navigate to the address
- Right-click first instruction → Create Function
- Or press
f
Error: Unexpected name “Client::UI::Agent::AgentInterface.vf1”
This occurs when a base class has multiple virtual functions, but Ghidra only detected the first one. Solution:- Navigate to
vtbl_Component::GUI::AtkModuleInterface::AtkEventInterface - You’ll see:
- The second entry should be a pointer. Place cursor on line
1418ebca8 - Press
p(create pointer) or right-click → Data → Pointer - Delete the incorrect label: cursor on label, press
Delete - Re-run ffxiv_idarename.py
Error: Function at 0xXXXXXXXX had unexpected name ""
Ghidra didn’t identify this memory as code. Solution:- Press
g(Go To…) - Enter the address from the error message
- You’ll see undefined bytes:
- Right-click → Disassemble or press
d - Right-click → Create Function or press
f - Re-run the script
Error: Unexpected name “Concurrency::details::FreeThreadProxy::…”
Ghidra’s analyzer matched this to a Visual Studio runtime function. Solution:- Navigate to the function
- Right-click the name
- Remove Label or press
Delete - Repeat until it becomes
FUN_XXXXXXXX - Re-run the script
Error: Two vtables detected, second not labeled
Occurs when a class has multiple vtables, but Ghidra didn’t find pointers to the secondary vtable. Solution:- Find where the script stopped processing (e.g., vf20)
- Look for the first overridden function in the secondary vtable (e.g., vf8)
- Navigate to that address and look upward for undefined bytes (not
cc) - First non-
ccbyte: pressd(disassemble) thenf(create function) - In the decompiled function, find:
- The address (141935128) is your secondary vtable
- Re-run the script
Error: Base vtbl size greater than actual class
Navigate to the vtable and look for the last entry. You might see:- The
a0should be a pointer - Place cursor on that line
- Press
pto create a pointer - Re-run the script
Known Ignorable Errors
These errors are expected and can be safely ignored:/home/daytona/workspace/source/Ghidra/Common Issues.md:92-98 for details.
Version Tracking (After Patches)
After each game patch, you need to re-import and re-analyze. Ghidra supports version tracking to help identify changes:- Import the new ffxiv_dx11.exe into the same project
- Use folders to organize versions:
- Open the new version and analyze
- Use Tools → Version Tracking to compare with previous version
- Re-run scripts on the new version
Tips and Tricks
Navigation Shortcuts
g- Go to addressd- Disassemblef- Create functionp- Create pointerDelete- Remove labelCtrl+Shift+E- Set equate (name a constant);- Add comment
Finding Constructors
Look for functions that:- Take a pointer as first parameter (usually
rcxin x64) - Write a vtable pointer to offset 0:
Debugging Script Issues
Check the Console window for:- Python tracebacks
- Warning messages
- Processing progress
Performance Optimization
For large analysis sessions:- Increase Ghidra’s memory in
ghidraRun.batorghidra.sh: - Disable unnecessary analyzers for faster initial analysis
- Save frequently - analysis can crash on very large executables
Next Steps
- Learn the data.yml structure
- Compare with IDA Pro workflow
- Read the contributing guide to submit findings
- Explore Ghidra’s built-in decompiler and analysis tools