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):
createJavadocscreateJsondocssleighCompileEvery 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
InstructionsDataFunctions
Basic BlocksCommentsMemory
Memory BlocksBytesSymbol Tables
SymbolsFlatProgramAPIpublic 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
GhidraScriptAPIpublic 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"); } }
currentProgramThe current active open program
currentAddressThe current address of the location of the cursor
currentLocationThe 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
stateProvides place to store environment variables
monitorwhile (!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) { ... }
constructorinit()
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);
GTableGTreeGComboBoxProvides:
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(...); ...
AnalyzerTypeProvides 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 { ... }