Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
26289c0
build: resolve the SDK from mavenLocal with a version override
tjmblake Aug 13, 2026
5c3bed3
refactor: remove the v2 data-type path
tjmblake Aug 15, 2026
f230f68
feat: add a flat model for v3 data types
tjmblake Aug 15, 2026
e10bbf0
feat: decode v3 data types into Ghidra types
tjmblake Aug 15, 2026
d54d788
feat: read signatures from /v3/functions/signatures
tjmblake Aug 15, 2026
6f5dc97
feat: push local type edits to /v3
tjmblake Aug 15, 2026
ca30d22
fix: resolve archive-category types to the servers root namespace
tjmblake Aug 15, 2026
57bc998
fix: count bitfield offsets from the start of the type on big-endian
tjmblake Aug 15, 2026
37cd2d6
feat: migrate AI decompilation tokenised path to /token-values
tjmblake Aug 16, 2026
d69a652
fix: follow the AI decompilation token endpoint rename
tjmblake Aug 19, 2026
780c4d8
fix: fetch disassembly from the v3 blocks endpoint
tjmblake Aug 19, 2026
c5494db
refactor(api): move function details onto the v3 endpoint
tjmblake Aug 19, 2026
b9218fb
fix(api): move single function rename onto the v3 batch endpoint
tjmblake Aug 19, 2026
c400698
fix: move the analysis function list to the v3 endpoint
tjmblake Aug 19, 2026
ddac537
refactor: move analysis basic-info onto the v3 endpoint
tjmblake Aug 19, 2026
ed4d041
refactor: retire the last hand-rolled HTTP calls and the legacy Binar…
tjmblake Aug 19, 2026
117fbc5
fix: rename the selected match, accept Uploaded status, survive a mis…
tjmblake Aug 19, 2026
e0a74ba
chore: remove dead analysis-creation controls and unread builder options
tjmblake Aug 19, 2026
3c81f87
chore: drop guava, trim extension zip, remove help skeleton
tjmblake Aug 20, 2026
514a03b
chore: remove four dead-code clusters
tjmblake Aug 20, 2026
8d21180
chore: remove dead code
tjmblake Aug 20, 2026
0a5d378
chore: remove a no-op analyzer and orphaned test fixtures
tjmblake Aug 20, 2026
2b2f7a5
docs: correct stale plugin documentation
tjmblake Aug 20, 2026
eea2ba4
test: remove duplication and bare-assert hazard from the test suite
tjmblake Aug 20, 2026
b0775f8
fix: request the function list within the page size the API accepts
tjmblake Aug 20, 2026
f8e3871
build: resolve the SDK from the public 4.4.0 release
tjmblake Aug 24, 2026
3dd6d70
feat: sync the portal signatures and data types into Ghidra
tjmblake Aug 24, 2026
cbfe74d
fix: stop re-applying a portal signature that has not changed
tjmblake Aug 25, 2026
8135c7d
fix: only offer a rename for the tokens the portal can rename
tjmblake Aug 25, 2026
22338f3
fix: say what happened when function matching finishes
tjmblake Aug 25, 2026
f12192c
fix: decide a rename by whether the token carries an id
tjmblake Aug 25, 2026
a4bc707
fix: never let a double-click to rename do nothing silently
tjmblake Aug 25, 2026
ccb33f8
fix: take the whole identifier from a double-click
tjmblake Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ dev/
*.class
*.jar
!gradle/wrapper/gradle-wrapper.jar
!lib/json-20230618.jar
!lib/toml4j-0.7.2.jar
*.war
*.ear

Expand Down Expand Up @@ -47,7 +45,6 @@ Thumbs.db
*.kotlin_builtins

# Ignore development config files
lib/src/test/resources/reai-dev-config.toml
bin
.antProperties.xml

Expand Down
3 changes: 2 additions & 1 deletion .revengai/features.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"status": "yes"
},
"fs_nns_filter": {
"status": "partial"
"note": "Results per function is fixed: 1 for binary-level matching, 25 for function-level. Not user configurable.",
"status": "absent"
},
"fs_similarity_filter": {
"status": "yes"
Expand Down
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ Ghidra extension for the RevEng.AI toolkit (Java 21). Build with `GHIDRA_INSTALL

## API access

**All RevEng.AI API calls must go through the generated `ai.reveng:sdk` client** (the `*Api` classes such as `CollectionsApi`, `SearchApi`, `AnalysesCoreApi`). Do not hand-roll HTTP requests. The legacy manual path in `TypedApiImplementation` (`requestBuilderForEndpoint` / `sendRequest` / `sendVersion2Request`) is being migrated away from — do not extend it.
**All RevEng.AI API calls must go through the generated `ai.reveng:sdk` client** (the `*Api` classes such as `CollectionsApi`, `SearchApi`, `AnalysesCoreApi`). Do not hand-roll HTTP requests. Where a response cannot go through a generated model, use the generated `*Call` form and read the body directly, so the path, query and auth still come from the SDK.

If a generated SDK model rejects a live response (e.g. strict validation throwing on an undeclared field), fix it by bumping the SDK to a version whose model matches the API — not by falling back to a manual request. `SdkSchemaTest` guards the SDK version floor and the specific API/model surface the plugin depends on; update it when you change which SDK methods are used.

## Dependencies in the built extension

Runtime dependencies are copied into `lib/` and bundled into the extension zip. `lib/` is gitignored. The copy step does not prune old versions, so after bumping a dependency delete the previous jar from `lib/` before rebuilding — otherwise the zip ships two versions and the classloader may load the stale one.
Runtime dependencies are copied into `lib/` by Ghidra's `copyDependencies` task, put on the compile classpath, and bundled into the extension zip. The jars themselves are gitignored.

`copyDependencies` never removes anything, so `build.gradle` registers a `pruneStaleJars` task that deletes `lib/*.jar` and runs before it. Every build therefore starts from an empty `lib/` and ships exactly the jars that resolved; bumping or dropping a dependency needs no manual cleanup.
34 changes: 22 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ and use it for Binary Code Similarity to help you Reverse Engineer stripped bina

## Key features

* Upload the current binary for analysis
* Automatically rename all functions above a confidence threshold
* Show similar functions and their names for one selected function
* Create a RevEng.AI analysis for the open binary, or attach to one that already exists in the portal
* Match functions against the RevEng.AI dataset and rename them, either one at a time or across the whole binary
* A Similar Functions window that follows the cursor and diffs the selected function against each match
* AI Decompilation, with a natural language explanation of what the function does
* Agent Chat: ask the RevEng.AI agent about the current binary and let it rename and re-type functions
* Sync With Portal: apply the names, function signatures and data types the portal holds for your analysis, and push local renames back up. Local type and signature edits go up on their own as you make them
* Automatic sync of the names and data types recovered by the server-side auto-unstrip pass

## Installation

Expand Down Expand Up @@ -67,7 +71,9 @@ Once installed, you can enable the plugin via the `Configure` tool.
1. Navigate to Ghidra's Configure tool
- `File` -> `Configure`
2. Click `Configure` under the `RevEng.AI` plugin group
3. Select the checkbox next to each of the plugins except the `DevPlugin` (unless you are doing development on the plugin itself)
3. Select the checkbox next to every plugin in the list: `AgentChatPlugin`, `AnalysisManagementPlugin`, `BinarySimilarityPlugin`, `LoggingPlugin` and `ReaiAPIServicePlugin`

`ReaiAPIServicePlugin` and `LoggingPlugin` provide the API and logging services that the three feature plugins require, so all five need to be enabled.

![Plugins Configuration Window](screenshots/plugins-configuration-window.png)

Expand All @@ -94,7 +100,7 @@ When you load the plugin for the first time, or by selecting `RevEng.AI -> Confi
You are now ready to analyse a binary.

Import `src/test/resources/fdupes` into Ghidra and then create a new RevEng analysis, by going to `RevEng.AI -> Analysis -> Create New`.
Usually it's enough to use the default options, but you can also select specific platforms or architectures if you want to.
Usually it's enough to use the default options, but you can also select a specific architecture if you want to.

![Upload Dialog](screenshots/upload-dialog-v2.png)

Expand All @@ -115,15 +121,15 @@ applying them.

We now have uploaded `fdupes` to our dataset, meaning we can now use it for our binary similarity tasks. Let's see how this works on a stripped version of `fdupes`.

Import `src/test/resourcesfdupes.stripped` using the same steps as before. Once this has been completed, you can move on to the next step.
Import `src/test/resources/fdupes.stripped` using the same steps as before. Once this has been completed, you can move on to the next step.

With `fdupes.stripped` open in Ghidra, select a function in Ghidra's listing or decompiler view, and `Right-Click -> Match function`.
This will open the function matching and renaming window.

![Function Matching Action](screenshots/function-matching-action.png)
![Function Matching Window](screenshots/function-matching-window-2.png)

Adjust the filters as necessary and when ready click `Match Functions`. This will return up to 10 functions that match
Adjust the filters as necessary and when ready click `Match Functions`. This will return up to 25 candidate matches for
the selected function. You can then decide to rename the function to one of the suggested names by clicking `Rename Selected`.

You can always update the filters and click `Match Functions` again to update the returned functions based on updated filters.
Expand Down Expand Up @@ -160,11 +166,15 @@ The plugin is still undergoing active development currently, and we are looking

### Code Overview

We have tried to decompose the plugin into a series of individual plugins dependent on a **CorePlugin**.
The extension is decomposed into several Ghidra plugins, all in `src/main/java/ai/reveng/toolkit/ghidra/plugins`.

The **CorePlugin** provides services that are shared across all parts of the toolkit, namely configuration and API Services.
Two of them exist only to provide shared services: **ReaiAPIServicePlugin** handles the API credentials and
provides `GhidraRevengService`, the single entry point to the RevEng.AI API, and **LoggingPlugin** provides
`ReaiLoggingService`. The feature plugins — **AnalysisManagementPlugin**, **BinarySimilarityPlugin** and
**AgentChatPlugin** — declare those services in their `servicesRequired` and acquire them from the tool.

You should therefore group related features into a Feature Plugin, and then acquire services from the CorePlugin as required. This gives users the flexiblity to enable / disable features based on their use-case and/or preferences.
You should therefore group related features into a feature plugin, and then acquire services as required.
This gives users the flexibility to enable / disable features based on their use-case and/or preferences.

### Building from source

Expand All @@ -177,10 +187,10 @@ Gradle can be used to build the plugin from its source code.
git clone https://github.com/RevEngAI/plugin-ghidra.git
```

2. Enter the repository and build with gradle.
2. Enter the repository and build with the Gradle wrapper.
```
cd plugin-ghidra
gradle -PGHIDRA_INSTALL_DIR=<ghidra_install_dir>
./gradlew -PGHIDRA_INSTALL_DIR=<ghidra_install_dir> buildExtension
```
* Replace `<ghidra_install_dir>` with the path to your local Ghidra installation path.

Expand Down
43 changes: 38 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ repositories {
// dropped into the lib/ directory.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html for more info.
// Ex: mavenCentral()
// mavenLocal() is listed first so that locally installed artifacts take precedence.
mavenLocal()
mavenCentral()
}

Expand All @@ -64,23 +66,46 @@ dependencies {
// this extension is built.
implementation 'io.github.java-diff-utils:java-diff-utils:4.12'
implementation 'org.json:json:20250107'
implementation "com.google.guava:guava:33.2.0-jre"
implementation group: 'com.fifesoft', name: 'rsyntaxtextarea', version: '3.5.2'
implementation 'org.commonmark:commonmark:0.24.0'
implementation 'org.commonmark:commonmark-ext-gfm-tables:0.24.0'
implementation('ai.reveng:sdk:3.123.0')
implementation('ai.reveng:sdk:4.4.0')
testImplementation('junit:junit:4.13.1')
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.8.2")
// Version comes from the junit-bom pulled in by junit-vintage-engine.
testRuntimeOnly('org.junit.platform:junit-platform-launcher')

// https://mvnrepository.com/artifact/org.jetbrains/annotations
implementation group: 'org.jetbrains', name: 'annotations', version: '26.0.2'

}

// Build against a different ai.reveng:sdk than the pin above, e.g. one installed into the local
// Maven repository:
//
// ./gradlew buildExtension -PrevengSdkVersion=<version>
//
// The pin in the dependencies block stays the literal default so that
// .github/scripts/bump_revengai.py can still find and rewrite it.
if (project.hasProperty('revengSdkVersion')) {
configurations.all {
resolutionStrategy.force "ai.reveng:sdk:${project.revengSdkVersion}"
}
}

// Ghidra's copyDependencies task copies runtime jars into lib/ but never prunes, and everything
// in lib/ ends up on the compile classpath and in the extension zip, and copyDependencies never
// removes anything. Without this, dropping or bumping a dependency leaves the old jar behind and
// it keeps shipping. copyDependencies puts back exactly the jars that resolved.
tasks.register('pruneStaleJars', Delete) {
delete fileTree(dir: 'lib', include: '*.jar')
}
copyDependencies.dependsOn pruneStaleJars

test {
maxParallelForks = 3
useJUnitPlatform()
jvmArgs '--add-exports=java.desktop/sun.awt=ALL-UNNAMED'
// systemProperty 'java.awt.headless', 'true'
systemProperty "ghidra.test.property.batch.mode", 'true'

// Ghidra 12.1+ installs a serial filter factory during application initialization. The JVM
Expand All @@ -99,8 +124,16 @@ test {
systemProperty 'jdk.serialFilterFactory', filterFactoryClass
}
}
// Exclude additional files from the built extension
// Ex: buildExtension.exclude '.idea/**'
// Ghidra's buildExtension zips the whole project directory, excluding only build output, IDE
// dotfiles and src/. These paths are development-only and nothing reads them at runtime.
buildExtension.exclude 'screenshots/**'
buildExtension.exclude '.github/**'
buildExtension.exclude 'docs/**'
buildExtension.exclude 'scripts/**'
buildExtension.exclude '.revengai/**'
buildExtension.exclude 'CLAUDE.md'
buildExtension.exclude '.worktreeinclude'
buildExtension.exclude '.java-version'


tasks.register('updateReadmeScreenshots', Copy) {
Expand Down
15 changes: 0 additions & 15 deletions data/README.txt

This file was deleted.

9 changes: 6 additions & 3 deletions lib/README.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
The "lib" directory is intended to hold Jar files which this module is dependent upon. Jar files
may be placed in this directory manually, or automatically by maven via the dependencies block
of this module's build.gradle file.
The "lib" directory holds the Jar files which this module depends upon at runtime. They are put
here by Gradle from the dependencies block of this module's build.gradle, and end up in the built
extension zip. The jars themselves are not checked in.

Do not place jars here by hand: every build first deletes lib/*.jar (see the pruneStaleJars task in
build.gradle) so that only the dependencies that actually resolved are shipped.
3 changes: 0 additions & 3 deletions os/linux_x86_64/README.txt

This file was deleted.

3 changes: 0 additions & 3 deletions os/mac_x86_64/README.txt

This file was deleted.

3 changes: 0 additions & 3 deletions os/win_x86_64/README.txt

This file was deleted.

5 changes: 4 additions & 1 deletion scripts/emit_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
"fs_collection_filter": {"status": "yes"},
"fs_binary_filter": {"status": "yes"},
"fs_debug_filter": {"status": "yes"},
"fs_nns_filter": {"status": "partial"},
"fs_nns_filter": {
"status": "absent",
"note": "Results per function is fixed: 1 for binary-level matching, 25 for function-level. Not user configurable.",
},
"fs_similarity_filter": {"status": "yes"},
"upload_function_names": {"status": "yes"},
"data_types_sync": {"status": "yes"},
Expand Down
57 changes: 0 additions & 57 deletions src/main/help/help/TOC_Source.xml

This file was deleted.

23 changes: 0 additions & 23 deletions src/main/help/help/topics/reait/help.html

This file was deleted.

This file was deleted.

Loading
Loading