Skip to content

GhidraPlugin_Development

niklas fassbender edited this page Jan 27, 2022 · 2 revisions

Prerequisites

Building and running the project requires at least JDK-11 and python 3.8. Furthermore ghidra needs to be installed.

Building the project

The plugin is build using gradle. To get started simply set the GHIDRA_INSTALL_DIR environment variable and run ./gradlew. This builds and packages the plugin. In addition to the compiled jar the python scripts inside the py_scripts directory are also packaged. The packaged plugin can then be found in the dist directory. The package can then be installed through the ghidra GUI.

Development Setup

For development purposes the ./rebuild.sh script can be used. It builds and installs the plugin automatically. Furthermore ghidra is started in development mode with logs visible in stdout/stderr.

Architecture

This plugin consists of two major parts. The ghidra side is written in java and mainly provides the GUI. Since angr is can only be used with python3, the angr part is located in an external python script which is called via a java processbuilder. The communication between java and python is done through a yaml file. See the section below for the specification.

YAML format

glitch_request:

mainOptions:
  pathToBinary: "path/to/binary" # The path to the binary that should be loaded
  angrBackend: "elf|mach-o|pe|blob" # The type of binary used
  arch: "arch specification (e.g. arm)" # The system architecture of the binary
  entryPoint: "0x00400000" # When using the blob backend the entrypoint needs to be specified
  baseAddress: "0x00400000" # When using the blob backend angr needs to now at which address the binary needs to be loaded
  useBlankState: false # Start execution at the address specified at "blankStateStartAt"
  blankStateStartAt: ""
findOptions:
  findAddress: "0x004007e4" # The Address angr searches for
  avoidAddresses: [] # A list of addresses angr avoids
  useCustomFindFunction: false # use a custom find function instead of the find address
  customFindFunction: "" # The custom find function. See notebook section for an example. Can be a yaml multiline string to deal with escaping problems
stateModificationOptions: 
  memoryModifications: # A list of memory modifications
    - address: "0x1FE" # Address which should be modified
      value: "0x21435487" # Value which should be stored in "address"
      length: 4 # The length of the value in bytes
glitchOptions: 
  instructions: # List of instructions at which a glitch should be tested
  - address: "0x0040076c"
  - address: "0x0040076e"

glitch_response:

contains a list of all instructions that led to a successful glitch.

- glitchAddress: '0x00400780' # The address of the glitch
  paths: # The path toward the glitch
  - blocks: # The path consists of multiple blocks
    - address: '0x500010' # each block has a starting address
      instructionAddrs: [] 
    - address: '0x400650'
      instructionAddrs: # each block can have multiple instructions. These are listed here
      - '0x400650'
      - '0x400654'
      - '0x400658'
      - '0x40065c'
  instructionCount: 24 # sum of instructions over all blocks
- glitchAddress: '0x004007a0'
  paths:
    - blocks:
        - address: '0x500010'
          instructionAddrs: []
        - address: '0x400650'
          instructionAddrs:
            - '0x400650'
            - '0x400654'
            - '0x400658'
            - '0x40065c'
  instructionCount: 46

Plugin development

Code Architecture

The core of every plugin is the plugin class (GhidraFaultInjectorPlugin) which extends ProgramPlugin. Here all components needed for the plugin are initialised. For the fault-injector plugin two main components are initialised. The GhidraFaultInjectorProvider is responsible for the main GUI while the GhidraFaultInjectorListingContextAction is responsible for creating the context menu that is shown in ghidras code view.

GUI development

The main window is created in GhidraFaultInjectorProvider. The window consists of a JTabbedPane which creates a panel with multiple tabs which can be clicked to change the subpannel that is currently shown. For the fault-injector plugin two tabs were used, the glitch option and the result tab which are created in the buildPanel method. Each of the tabs consist of multiple panels. These panels can be found in the panels package. Each panel extends the JPanel class and contains a method to build the respective panel. In addition to that the panels used in the glitch option tab have a getOptions method that collects all the input and returns it as an object. Each panel has an associated model which can be found in the model package.

Since the number/features of available components in swing are quite small, Ghidra provides additional components that should be used if applicable. The VariableHeightPairLayout component provides a layout option that makes it easy to create label/input field pairs. Components like GCheckBox or AddressInput help with maintaining the ghidra look and feel.

Ghidra Tasks

In java swing the GUI runs on the same thread as the rest of the code which results in the GUI becoming unresponsive while a background task is running. Ghidra provides a task scheduler to solve this problem. Tasks run in a separate thread so the GUI stays responsive during long running tasks. Currently the plugin uses one task. The FindGlitchTask is responsible for writing/reading the yaml for communicating with the python part. Furthermore the task creates a subprocess that runs the python script responsible for running angr.

Context Actions

Context actions are defined in the GhidraFaultInjectorListingContextAction class which extends Ghidras ListingContextAction class. Inside the class multiple context actions can be added. They all follow the same scheme. First a ListingContextAction with an implemented actionPerformed method is created. actionPerformed defines what action should be performed when the context action is clicked. Next the context action has to be assigned to a menu path. This is done as follows:

contextAction.setPopupMenuData(new MenuData(new String[]{
        MENUNAME,
        "Path",
        "TO Action"
        }));

Lastly the contextAction needs to be added to the plugin to become available: pluginTool.addAction(setBlankStateAddress);