DEV Community

ddupard
ddupard

Posted on

Ghidra Internals: My Discoveries - Part I

I don't like the way Ghidra displays assembly. In fact, I dislike it so much that I started working on a tool that replicates some of Ghidra's core functions while adding cool new features. I use Ghidra on a 14-inch screen, which probably explains why I'm not a fan of its default assembly view.

Moreover, most of the time I don't have the source code, and since I started to read disassembly code when dinosaurs... (well, maybe a little bit later, on the 6502 and Oric-1), I really like raw disassembly code.

However, Ghidra remains an industry standard for reverse engineering for very good reasons (alongside IDA Pro, etc.).

So, I decided to build a custom assembly view tailored to how I actually like reading assembly code. To achieve this, I need to understand how Ghidra works under the hood. This is my personal journey—I started just 2 days ago.

Below is the way ghidra shows an assembly code

In my view I don't have big blocks of information. Instead I change the view depending on what I want to see. Moreover what I want to see is programmable. For example below I want to see the external calls and the stack allocation:

I am a complete beginner when it comes to Ghidra's internals, so please feel free to leave comments to correct my mistakes or help me understand things better!

1. Some Basic Information

The source code of Ghidra is publicly available on GitHub:
https://github.com/nationalsecurityagency/ghidra

Collecting the sources and compiling them is an absolute breeze—really easy. All I did was applying the instructions on the github repo of Ghidra (see below).

To create the latest development build for your platform from this source repository:

Install build tools:

JDK 25 64-bit
Gradle 9.1.0+ (or provided Gradle wrapper if Internet connection is available)
Python3 (version 3.9 to 3.14) with bundled pip
GCC or Clang, and make (Linux/macOS-only)


Download and extract the source: ghidra-master

unzip ghidra-master
cd ghidra-master

NOTE: Instead of downloading the compressed source, you may instead want to clone the GitHub repository: git clone https://github.com/NationalSecurityAgency/ghidra.git

Download additional build dependencies into source repository:
NOTE: If an Internet connection is available and you did not install Gradle, the ./gradlew (or gradlew.bat) command may be used in place of the gradle command in the following instructions.

gradle -I gradle/support/fetchDependencies.gradle

Create development build:
gradle buildGhidra

The compressed development build will be located at build/dist/.
Enter fullscreen mode Exit fullscreen mode

Ghidra is written mainly (exclusively?) in Java. It is highly modular, allowing you to add your own plugins, tools, extensions, and scripts.

It seems to work smoothly with Python scripts as well, though I have only tested Java scripts so far.

Ghidra is massive. It contains more than 15,700 Java files, which means I urgently need a solid methodology to figure out how it ticks. Fortunately, the creators of Ghidra followed a very rigorous naming convention.

2. The Cartography

Ghidra is organized in tools (like the CodeBrowser, the Emulator, the Debugger, the Version Tracking tool )
Each tool contains plugins. These plugins can be found in files whose names finish with Plugin.java like (SymbolTreePlugin.java, FunctionWindowPlugin.java, CallTreePlugin.java, ..)
There are 235 plugins. See below

//@formatter:on
public class CallTreePlugin extends ProgramPlugin {

    static final Icon PROVIDER_ICON = Icons.ARROW_DOWN_RIGHT_ICON;

    private List<CallTreeProvider> providers = new ArrayList<>();
    private DockingAction showCallTreeFromMenuAction;
    private CallTreeProvider primaryProvider;

    public CallTreePlugin(PluginTool tool) {
        super(tool);

        createActions();
        primaryProvider = new CallTreeProvider(this, true);
        providers.add(primaryProvider);
    }

    @Override
    protected void locationChanged(ProgramLocation loc) {
        for (CallTreeProvider provider : providers) {
            provider.setLocation(loc);
        }
    }

    @Override
    protected void programActivated(Program program) {
        for (CallTreeProvider provider : providers) {
            provider.programActivated(program);
        }
    }

    @Override
    protected void programDeactivated(Program program) {
        for (CallTreeProvider provider : providers) {
            provider.programDeactivated(program);
        }
    }

    @Override
    protected void programClosed(Program program) {
        for (CallTreeProvider provider : providers) {
            provider.programClosed(program);
        }
    }

    @Override
    public void readConfigState(SaveState saveState) {
        primaryProvider.readConfigState(saveState);
    }

    @Override
    public void writeConfigState(SaveState saveState) {
        primaryProvider.writeConfigState(saveState);
    }

    @Override
    protected void dispose() {
        List<CallTreeProvider> copy = new ArrayList<>(providers);
        for (CallTreeProvider provider : copy) {
            removeProvider(provider);
        }
    }
    ...
Enter fullscreen mode Exit fullscreen mode

All Plugins derive from a unique class called Plugin or a class called ProgramPlugin.
The Plugin class can be found in the file ./Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/Plugin.java
The ProgramPlugin class which is derived from the class Plugin can be found in the file ./Ghidra/Features/Base/src/main/java/ghidra/app/plugin/ProgramPlugin.java

Plugins are a basic building block in Ghidra, used to bundle features or capabilities into a unit that can be enabled or disabled by the user in their Tool.

Plugins expose their features or capabilities to users via menu items and buttons that the user can click on, and via "service" APIs that other Plugins can programmatically subscribe to, and via {@link PluginEvent}s that are broadcast.

3. The CodeBrowser

Using Ghidra's capability to export tools,

one can see what is hidden in a tool

For example the CodeBrowser accepts the following data types

<SUPPORTED_DATA_TYPE CLASS_NAME="ghidra.program.model.listing.Program" />
<SUPPORTED_DATA_TYPE CLASS_NAME="ghidra.program.model.listing.DataTypeArchive" />
Enter fullscreen mode Exit fullscreen mode

if contains the following packages

 <PACKAGE NAME="BSim" />
<PACKAGE NAME="Ghidra Core">
Enter fullscreen mode Exit fullscreen mode

and the following plugins

<INCLUDE CLASS="ghidra.app.plugin.core.interpreter.InterpreterPanelPlugin" />
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.functionwindow.FunctionWindowPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.datapreview.DataTypePreviewPlugin">
<PLUGIN_STATE CLASS="ghidra.features.base.memsearch.gui.MemorySearchPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.overview.OverviewColorPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.symboltree.SymbolTreePlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.calltree.CallTreePlugin">
<PLUGIN_STATE CLASS="functioncalls.plugin.FunctionCallGraphPlugin">
<PLUGIN_STATE CLASS="datagraph.DataGraphPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.symtable.SymbolTablePlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.script.GhidraScriptMgrPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.bookmark.BookmarkPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.byteviewer.ByteViewerPlugin">
<PLUGIN_STATE CLASS="ghidra.features.codecompare.plugin.FunctionComparisonPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.functiongraph.FunctionGraphPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.graph.GraphDisplayBrokerPlugin">
<PLUGIN_STATE CLASS="ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin">
Enter fullscreen mode Exit fullscreen mode

Moreover a tool contains some fields which describe the gui ie. how the panels (or windows) are arranged on the screen

<ROOT_NODE X_POS="348" Y_POS="294" WIDTH="1390" HEIGHT="786" EX_STATE="6" FOCUSED_OWNER="DecompilePlugin" FOCUSED_NAME="Decompiler" FOCUSED_TITLE="Decompile: handle_client">
            <SPLIT_NODE WIDTH="100" HEIGHT="100" DIVIDER_LOCATION="0" ORIENTATION="VERTICAL">
                <SPLIT_NODE WIDTH="1621" HEIGHT="816" DIVIDER_LOCATION="148" ORIENTATION="VERTICAL">
                    <COMPONENT_NODE TOP_INFO="0">
                        <COMPONENT_INFO NAME="Entropy" OWNER="EntropyPlugin" TITLE="Entropy" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772885" />
                        <COMPONENT_INFO NAME="Overview" OWNER="OverviewPlugin" TITLE="Overview" ACTIVE="false" GROUP="Header" INSTANCE_ID="3207819926581772883" />
                    </COMPONENT_NODE>
                    <SPLIT_NODE WIDTH="1854" HEIGHT="929" DIVIDER_LOCATION="191" ORIENTATION="HORIZONTAL">
                        <SPLIT_NODE WIDTH="353" HEIGHT="929" DIVIDER_LOCATION="640" ORIENTATION="VERTICAL">
                            <SPLIT_NODE WIDTH="353" HEIGHT="592" DIVIDER_LOCATION="502" ORIENTATION="VERTICAL">
                                <COMPONENT_NODE TOP_INFO="0">
                                    <COMPONENT_INFO NAME="Program Tree" OWNER="ProgramTreePlugin" TITLE="Program Trees" ACTIVE="true" GROUP="Default" INSTANCE_ID="3743589477541406473" />
                                </COMPONENT_NODE>
                                <COMPONENT_NODE TOP_INFO="0">
                                    <COMPONENT_INFO NAME="Symbol Tree" OWNER="SymbolTreePlugin" TITLE="Symbol Tree" ACTIVE="true" GROUP="Default" INSTANCE_ID="3743589477541406468" />
                                </COMPONENT_NODE>
                            </SPLIT_NODE>
                            <COMPONENT_NODE TOP_INFO="0">
                                <COMPONENT_INFO NAME="DataTypes Provider" OWNER="DataTypeManagerPlugin" TITLE="Data Type Manager" ACTIVE="true" GROUP="Default" INSTANCE_ID="3743590794492045077" />
                            </COMPONENT_NODE>
                        </SPLIT_NODE>
Enter fullscreen mode Exit fullscreen mode

and finally some preferences in terms of columns and options for the panels

4. Epilogue

In this very short article, I tried to explain what I discovered about Ghidra internals. I am a complete beginner on it. I am just scratching the surface of Ghidra and viewing the amount of work which has been done on it demonstrates how idotic was my idea of creating another tool.

In the next part, we will dive into the CodeBrowser's Java code to understand how it intercepts clicks and renders (or rather, overrides) the assembly view...

Top comments (0)