raw-data memdumps

Styling Ghidra - is that (even) a thing?

September 8, 2023

It’s been quite a long time since I last used Ghidra during some late nights analysis, but recently I thought to dust it off, maybe I will blog more about it in the future, but for now, let me drop this here.

As most of us, I also fiddled with different disassembler engines, frameworks and what not, and most likely we got used to the application shortcuts (you might have also tweaked them to mimic other tools), started adding plugins, maybe even creating themes - if you are getting funky - and the list keeps going.

Anyhow, as an excuse to force myself back into Ghidra, I wrote - a ridiculous script - NostalgicIDA and two themes, as you will guess, the first one has to do with IDA, probably a very lame try to port some visual “standards” seen in IDA pseudo-code … the plugin will not make you any better RE 😉 enough blating, grab your copy â¤ĩ

# @author _raw_data_ @ https://github.com/raw-data
# @category N/A
# @keybinding
# @menupath
# @toolbar

"""
Apply some pseudo-code changes, that recalls IDA display "style" and 
some custom ones
    - Rename all `local_xxxx` variables to `var_xxxx`
    - Rename all `FUN_xxxx` functions to `sub_xxxx`
    - Rename all `_DAT_xxxx` or `DAT_xxxx` globals to `glob_`
"""

from ghidra.program.model.symbol import SourceType
from ghidra.program.model.symbol import SymbolType


def globals_rename():
    # type (None) -> None
    """Rename global variables with prefix
    `DAT_` or `_DAT_` to `glob_`
    """

    glob_types = {"DAT_": "", "_DAT_": ""}

    for s in currentProgram.getSymbolTable().getAllSymbols(True):
        symbol_name = s.getName()

        for prefix, var_type in glob_types.items():
            if symbol_name.startswith(prefix):
                _new_symbol_name = var_type + "glob_" + symbol_name[len(prefix) :]
                s.setName(
                    _new_symbol_name,
                    SourceType.USER_DEFINED,
                )
                print("[i] Renamed %s to %s" % (symbol_name, _new_symbol_name))
                break

        if s.getSymbolType() == SymbolType.LABEL:
            if symbol_name.startswith("LAB_"):
                hexAddress = symbol_name[4:].upper()
                _new_symbol_name = "loc_" + hexAddress

                s.setName(_new_symbol_name, SourceType.USER_DEFINED)
                print("[i] Renamed %s to %s" % (symbol_name, _new_symbol_name))


def functions_rename(ren_function=True, ren_args=False, ren_local_var=False):
    # type (bool, bool, bool) -> None
    """Rename functions, arguments and local variables

    Args:
        ren_function (bool, optional): rename function to `sub_<hex_value_uppercase>`. 
                                        Defaults to True.
        ren_args (bool, optional): rename function's arguments to `a<integer_number>`. 
                                        Defaults to False.
        ren_local_var (bool, optional): rename local variables to `var<integer_number>` . 
                                        Defaults to False.
    """
    func_manager = currentProgram.getFunctionManager()

    if ren_function:
        for f in func_manager.getFunctions(True):
            function_name = f.getName()
            if not (f.isLibrary()):
                if function_name.startswith("FUN_"):
                    _new_function_name = "sub_" + function_name[len("FUN_") :].upper()
                    f.setName(_new_function_name, SourceType.USER_DEFINED)
                    print(
                        "[i] Renamed fnc: %s to %s"
                        % (function_name, _new_function_name)
                    )

                if ren_args:
                    print("[+] Starting renaming function's arguments ...")
                    args = f.getParameters()
                    for p in args:
                        arg = p.getName()
                        if arg.startswith("param_"):
                            _new_arg_name = "a" + arg[len("param_") :]

                            p.setName(_new_arg_name, SourceType.USER_DEFINED)
                            print(
                                "[i] Renamed parameter: %s to %s in function %s"
                                % (arg, _new_arg_name, function_name)
                            )

                if ren_local_var:
                    print("[+] Starting renaming function's local variables ...")
                    variables = f.getAllVariables()
                    for local_var in variables:
                        str_symbol = local_var.getSymbol().getName()

                        if not str_symbol.startswith("local_res"):
                            # * usually found in pseudo-code view
                            if str_symbol.startswith("local_"):
                                str_symbol_ending = str_symbol[len("local_") :]
                                _symbol = "var" + str_symbol_ending
                                local_var.setName(_symbol, SourceType.USER_DEFINED)
                                print(
                                    "[i] Renamed local var: %s to %s in fnc %s"
                                    % (str_symbol, _symbol, function_name)
                                )
                        else:
                            # * usually found in listing (Assembly) view
                            str_symbol_ending = str_symbol[len("local_res") :]
                            _symbol = "arg_" + str_symbol_ending + "h"
                            local_var.setName(_symbol, SourceType.USER_DEFINED)
                            print(
                                "[i] Renamed local var: %s to %s in fnc %s"
                                % (str_symbol, _symbol, function_name)
                            )
            else:
                print("[ii] Function library %s found, skipping ..." % function_name)


def main():
    # type (None) -> None

    print("[+] Starting renaming global symbols ...")
    globals_rename()
    print("[+] Starting renaming functions ...")
    functions_rename(ren_function=True, ren_args=True, ren_local_var=True)


if __name__ == "__main__":
    main()

A simple comparison can be observed below, IDA Free (with it’s cloud-based x86/x64 decompiler)

IDA listing view

and Ghidra, after running the plugin (with GhidraLightIDA theme and custom Code Browser Tool )

Same goes for the decompiler view, IDA showcased first

followed by Ghidra below

Painting the Dragon 🎨

There are plenty of resources out there explaining how to customize Ghidra panels and views, nonetheless, if you are looking for the same style and feel showcased above and an additional sleek dark theme, you can download the customized Code Browser Tool and the associated theme.

Below some screenshots to get you and idea about it - I know, I am late to the (dark) party ;)

ℹī¸ Script and themes tested with latest Ghidra, currently v10.3.3

Till next time, learn to love the 🐲