Abc Xyz
Not to my taste, but…
Use default Skeleton
project
Copy Skeleton
's directory (or yours prepared extension) to needed location
File
→ New
→ Project from Existing Sources...
(use Gradle model)gradle
's environment (GHIDRA_INSTALL_DIR
)
Create gradle.properties
file and set the environment:
GHIDRA_INSTALL_DIR = /home/user/ghidra
Point to the directory of sources of Ghidra, when it will be needed
ghidra_scripts
directory
Use existing HelloWorldScript
script as a template
${GHIDRA_HOME}/Ghidra/Features/Base/ghidra_scripts/HelloWorldScript.java
F4
hotkey in Project window)Import Module (select the directory of sources of Ghidra)
Add module dependencies via Context Actions
Run Ghidra in Debug mode
$ /opt/ghidra/support/ghidraDebug
Attach to Process…
Clone the repository
$ git clone https://github.com/NationalSecurityAgency/ghidra
Build Ghidra (see DevGuide.md
for details)
$ gradle --init-script gradle/support/fetchDependencies.gradle init $ gradle buildGhidra
sed
, inotify
, (bsd)tar
, etc)
Skip Gradle's tasks for faster building (use -x
argument):
createJavadocs
createJsondocs
sleighCompile
Every piece (Plugins, Scripts, Analyzers, Fields, Importers, Exporters, etc) of Ghidra is extensible!
Extensible components:
ExtensionPoint
interfaceExtensionPoint.manifest
src
./src ├── main │ ├── help │ │ └── help │ │ ├── shared │ │ │ └── Frontpage.css │ │ ├── topics │ │ │ └── skeleton │ │ │ └── help.html │ │ └── TOC_Source.xml │ ├── java │ │ └── skeleton │ │ ├── SkeletonAnalyzer.java │ │ ├── SkeletonExporter.java │ │ ├── SkeletonFileSystem.java │ │ ├── SkeletonLoader.java │ │ └── SkeletonPlugin.java │ └── resources │ └── images └── test └── java
./src/main ├── java │ └── skeleton │ ├── SkeletonAnalyzer.java │ ├── SkeletonExporter.java │ ├── SkeletonFileSystem.java │ ├── SkeletonLoader.java │ └── SkeletonPlugin.java └── resources └── images
.jar
file./src/test └── java
.jar
file./src/main/help └── help ├── shared │ └── Frontpage.css ├── topics │ └── skeleton │ └── help.html └── TOC_Source.xml
ghidra_scripts
./ghidra_scripts
data
./data ├── languages │ ├── skel.cspec │ ├── skel.ldefs │ ├── skel.opinion │ ├── skel.pspec │ ├── skel.sinc │ └── skel.slaspec ├── buildLanguage.xml └── sleighArgs.txt
.jar
file.zip
filelib
./lib
os
./os ├── linux64 ├── osx64 └── win64
. ├── build.gradle ├── extension.properties └── Module.manifest
build.gradle
Gradle's task. No need for changes
extension.properties
name=@extname@ description=The extension description. author= createdOn= version=@extversion@
Module.manifest
MODULE NAME: MODULE DEPENDENCY: MODULE FILE LICENSE: EXCLUDE FROM GHIDRA JAR DATA SEARCH IGNORE DIR: MODULE DIR: FAT JAR:
$ gradle
or
$ GHIDRA_INSTALL_DIR=${GHIDRA_HOME} gradle
See ./dist/
Program
Listing
Instructions
Data
Functions
Basic Blocks
Comments
Memory
Memory Blocks
Bytes
Symbol Tables
Symbols
FlatProgramAPI
public class FlatProgramAPI { FlatProgramAPI(Program) analyze() clear...() create...() find...() get...() remove...() save() set...() to...() }
Default:
${HOME}/ghidra_scripts
${GHIDRA_HOME}/Features/Base/ghidra_scripts
${GHIDRA_MODULE}/ghidra_scripts
GhidraScriptAPI
public class GhidraScriptAPI extends FlatProgramAPI { ask...() create...() get...() print...() run...() to...() }
//Writes "Hello World" to console. //@category Examples //@menupath Help.Examples.Hello World //@keybinding ctrl shift COMMA //@toolbar world.png import ghidra.app.script.GhidraScript; public class HelloWorldScript extends GhidraScript { @Override public void run() throws Exception { println("Hello World"); } }
currentProgram
The current active open program
currentAddress
The current address of the location of the cursor
currentLocation
The program location of the cursor
OperandFieldLocation@00400260, row=0, col=0, charOffset=8, OpRep = 47h G, subOpIndex = -1, VariableOffset = null
currentSelection
The current selection or null
if no selection exists
currentHighlight
The current highlight or null
if no highlight exists
state
Provides place to store environment variables
monitor
while (!monitor.isCancelled()) { ... }
Dynamic modules with OSGi
my_ghidra_scripts/mylib/MyLibrary.java
:
package mylib; public class MyLibrary { public void doStuff() { // ... } }
my_ghidra_scripts/IntraBundleExampleScript.java
:
// Intra-bundle dependency example. //@category Examples import ghidra.app.script.GhidraScript; import mylib.MyLibrary;
@importpackage
in a script
your_ghidra_scripts/yourlib/YourLibrary.java
:
package yourlib; public class YourLibrary { public void doOtherStuff() { // ... } }
my_ghidra_scripts/InterBundleExampleScript.java
:
// Inter-bundle dependency example. //@category Examples //@importpackage yourlib import ghidra.app.script.GhidraScript; import yourlib.YourLibrary; public class InterBundleExampleScript extends GhidraScript { @Override public void run() throws Exception { new YourLibrary().doOtherStuff(); } }
$HOME/.ghidra/.ghidra-<version>/osgi/compiled-bundles/<hash>
Usage: analyzeHeadless <project_location> <project_name>[/<folder_path>] | ghidra://<server>[:<port>]/<repository_name>[/<folder_path>] [[-import [<directory>|<file>]+] | [-process [<project_file>]]] [-preScript <ScriptName>] [-postScript <ScriptName>] [-scriptPath "<path1>[;<path2>...]"] [-propertiesPath "<path1>[;<path2>...]"] [-scriptlog <path to script log file>] [-log <path to log file>] [-overwrite] [-recursive]
[-readOnly] [-deleteProject] [-noanalysis] [-processor <languageID>] [-cspec <compilerSpecID>] [-analysisTimeoutPerFile <timeout in seconds>] [-keystore <KeystorePath>] [-connect <userID>] [-p] [-commit ["<comment>"]] [-okToDelete] [-max-cpu <max cpu cores to use>] [-loader <desired loader name>]
Derive from Plugin
(directly or indirectly)
/** * Plugin to for adding/deleting/editing bookmarks. */ //@formatter:off @PluginInfo( status = PluginStatus.RELEASED, packageName = CorePluginPackage.NAME, category = PluginCategoryNames.CODE_VIEWER, shortDescription = "Manage Bookmarks", description = "This plugin allows the user to add, edit, " + "delete, and show bookmarks. It adds navigation markers at " + "addresses where bookmarks reside.", servicesRequired = { GoToService.class, MarkerService.class }, servicesProvided = { BookmarkService.class }, eventsProduced = { ProgramSelectionPluginEvent.class } ) //@formatter:on
/** * Plugin to for adding/deleting/editing bookmarks. */ ... servicesRequired = { GoToService.class, MarkerService.class }, servicesProvided = { BookmarkService.class }, ...
/** * Visible Plugin to show ByteBlock data in various formats. */ //@formatter:off @PluginInfo( ... shortDescription = "Displays bytes in memory", ... servicesRequired = { ProgramManager.class, GoToService.class, NavigationHistoryService.class, ClipboardService.class }, eventsConsumed = { ProgramLocationPluginEvent.class, ProgramActivatedPluginEvent.class, ProgramSelectionPluginEvent.class, ProgramHighlightPluginEvent.class, ProgramClosedPluginEvent.class, ByteBlockChangePluginEvent.class }, eventsProduced = { ProgramLocationPluginEvent.class, ProgramSelectionPluginEvent.class, ByteBlockChangePluginEvent.class } ) //@formatter:on
/** * Visible Plugin to show ByteBlock data in various formats. */ ... eventsConsumed = { ProgramLocationPluginEvent.class, ProgramActivatedPluginEvent.class, ProgramSelectionPluginEvent.class, ProgramHighlightPluginEvent.class, ProgramClosedPluginEvent.class, ByteBlockChangePluginEvent.class }, eventsProduced = { ProgramLocationPluginEvent.class, ProgramSelectionPluginEvent.class, ByteBlockChangePluginEvent.class } ...
DockingAction
defines a user action associated with a toolbar icon and/or menu
item.
DockingActions can be invoked from the global menu, a popup menu, a toolbar, and/or a keybinding.
A plugin may supply a ComponentProvider
that provides a visual component when
the plugin is added to the tool
Have a @PluginInfo(...)
annotation
PluginInfo( status = PluginStatus.RELEASED, packageName = CorePluginPackage.NAME, category = PluginCategoryNames.COMMON, shortDescription = "Short description of plugin", description = "Longer description of plugin.", servicesProvided = { ServiceInterfaceThisPluginProvides.class } servicesRequired = { RequiredServiceInterface1.class, RequiredServiceInterface2.class }, eventsConsumed = { SomePluginEvent.class }, eventsProduced = { AnotherPluginEvent.class }, isSlowInstallation = false )
Have a constructor with exactly 1 parameter: PluginTool
public MyPlugin(PluginTool tool) { ... }
constructor
init()
dispose()
OptionsChangeListener
— to receive notification when a configuration option
is changed by the userFrontEndable
— marks this Plugin as being suitable for inclusion in the
FrontEnd toolFrontEndOnly
— marks this Plugin as FrontEnd only, not usable in CodeBrowser
or other toolsProgramaticUseOnly
— marks this Plugin as special and not for user
configurationProgramPlugin
Extends Plugin
class
Base class to handle common program events:
Allow users to customize the layout of components within a tool
Not used GUI toolkit
Managed GUI component in the tool
myComponent = new MyComponent(...); tool.addComponent(this, myComponent);
GTable
GTree
GComboBox
Provides:
GTable
GTree
F4
)What is needed for a new format?
Use Skeleton extension
${GHIDRA_HOME}/Ghidra/Processors
Must implement Loader
interface (all Loader Classes MUST END IN "Loader")
Consider AbstractProgramLoader
or AbstractLibraryLoader
public class SkeletonLoader implements Loader { Collection<LoadSpec> findSupportedLoadSpecs(...); List<DomainObject> load(...); ... }
.opinion
files
Must update the .opinion
file for each processor supported by the format
<opinions> <constraint loader="Skeleton" compilerSpecID="default"> <constraint primary="40" secondary="123" processor="Skel" size="16" variant="default" /> </constraint> <constraint loader="MS Common Object File Format (COFF)" compilerSpecID="default"> <constraint primary="61" processor="Skel" size="16" variant="default" /> </constraint> </opinions>
Must implement Analyzer
interface (all Analyzer Classes MUST END IN
"Analyzer")
// Display name, input type, priority String getName(); AnalyzerType getAnalysisType(); AnalysisPriority getPriority(); // Called for changes to analyzers inputs boolean added(...); boolean removed(...); // Register and react to user options void registerOptions(...); void optionsChanged(...); ...
AnalyzerType
Provides an alternative importer, which allows importing many programs from a single archive or image
Extensible using GFileSystem
interface (all GFileSystem Sub-classes MUST END
IN "FileSystem")
@FileSystemInfo(type = "ext4", description = "EXT4", factory = Ext4FileSystemFactory.class) public class Ext4FileSystem implements GFileSystem { ... }