Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
161 changes: 144 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,154 @@
# <img src="./images/logo.png" width=20> RevEng.AI Binary Ninja Plugin
<p align="center"><img src="./images/banner.png" ></p>
Official Binary Ninja Plugin for RevEng.AI

A Binary Ninja plugin for integrating with the RevEng.AI platform.
### Features Supported

## Installation
This plugin brings the power of RevEng.AI directly into Binary Ninja. Here are the main features currently supported:

1. Ensure you have Python 3.9 or later installed
2. Install the required dependencies:
```bash
pip install -r requirements.txt
```
3. Copy the `revengai_bn` directory to your Binary Ninja plugins directory:
- Linux: `~/.binaryninja/plugins/`
- Windows: `%APPDATA%\Binary Ninja\plugins\`
- macOS: `~/Library/Application Support/Binary Ninja/plugins/`
- **Configuration Panel**: Easily configure your API credentials and platform settings.
- **Choose a Source**: Select the uploaded binary whose analysis will be used for other features such as matching and renaming.
- **Process Binary**: Upload the currently loaded binary in Binary Ninja to RevEng.AI for analysis.
- **Auto-Unstrip**: Automatically restore stripped symbols in your binary using our AI engine.
- **Function Matching**: Compare and match functions from your current binary with those in your existing collections.

---

## Requirements
## Installation & Running 🚀

- Binary Ninja 5.0 or later
- Python 3.9 or later
- Internet connection for API access
- RevEng.AI API key
### Step 1: Locate Binary Ninja Plugins Folder

Locate your Binary Ninja user plugin directory:

- **Tools > Plugins > Open Plugin Folder** from the Binary Ninja menu

> 💡 **Tip**: This opens the correct path regardless of OS or install type.

Expected output locations:
- Linux: `~/.binaryninja/plugins/`
- Windows: `%APPDATA%\Binary Ninja\plugins\`
- macOS: `~/Library/Application Support/Binary Ninja/plugins/`


### Step 2: Download & Install the Plugin

1. Visit the releases page: https://github.com/RevEngAI/reai-ida/releases
2. Download the latest release (look for the most recent version).
3. Extract the contents into the opened plugin folder.
4. Ensure the folder structure looks like this:

```
Example in Linux...
~/.binaryninja/plugins/
└── revengai/
└── [plugin files...]
```

> 🖼️ *Insert screenshot of the correct plugin folder structure*

### Step 3: Install Dependencies

In your system terminal (not inside Binary Ninja), move to the directory with the 'requirements.txt' file and install required dependencies using:

```bash
pip install -r requirements.txt
```

Or directly from within Binary Ninja’s built-in Python terminal:

```python
import subprocess
subprocess.check_call(['pip', 'install', '-r', '/path/to/requirements.txt']) # Change to your path to requirements.txt
```

---

## Using the Plugin ⚙️

Once installed, you’ll find `RevEng.AI` listed in the Binary Ninja plugins toolbar menu.

<img src="images/plugintoolbar.png" >

Make sure to restart Binary Ninja completely after installation.
Then, check the Plugins menu — the RevEng.AI plugin should be visible.
Finally, load a binary and explore the features described below.

### 1. Configure the Plugin

Select `Configuration` from the menu to set up your API key and host.

<img src="./images/config.png" >

Clicking "Continue" will validate your API key.

---

### 2. Process a Binary

Upload the currently loaded binary to RevEng.AI:

- Select `RevEng.AI > Process Binary`

<img src="./images/processbinary.png" >

Before starting the process, you can add a PDB file and debug information, assign custom tags for better tracking, choose which AI model you want to use, and decide whether to keep the analysis private (default) or make it publicly available.
The plugin will handle the upload and initiate the analysis. Once completed, an internal analysis ID is assigned.

---

### 3. Choose Source Analysis

If you have already processed your binary on the platform or if there are publicly available analyses, you can select one as your working source.

- Select `RevEng.AI > Choose Source`

<img src="./images/choosesource.png" >

This is required before using some features like function matching or auto unstrip.

---

### 4. Auto Unstrip

Bring back symbol names automatically:

- Select `RevEng.AI > Auto Unstrip`

<img src="./images/autounstrip.png" >

Functions will be renamed with the most likely matching names from your configured collections.

---

### 5. Match Functions

Use function matching to identify similar functions in other binaries or collections:

- Click `RevEng.AI > Match Functions`

<img src="./images/matchedfunctions.png" >

Matched functions are displayed based on the given confidence value. You can navigate or rename based on the results.

---

## Troubleshooting

- Only Binary Ninja 3.0+ is supported
- Python 3.9 or later is required
- Ensure your API key is valid and your analysis contains function-level information

## Software Requirements

This plugin relies on:

- [reait](https://github.com/RevEngAI/reait)
- requests
- PySide6

## License

This plugin is released under the GPL-2.0 license.

## Disclaimer

Binary Ninja is a trademark of Vector 35. This project is not affiliated with or endorsed by Vector 35.
19 changes: 0 additions & 19 deletions features/auto_unstrip/auto_unstrip_thread.py

This file was deleted.

21 changes: 0 additions & 21 deletions features/choose_source/analysis_load_thread.py

This file was deleted.

20 changes: 0 additions & 20 deletions features/choose_source/choose_source_thread.py

This file was deleted.

19 changes: 0 additions & 19 deletions features/upload/model_load_thread.py

This file was deleted.

20 changes: 0 additions & 20 deletions features/upload/upload_thread.py

This file was deleted.

Binary file added images/autounstrip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/choosesource.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/matchedfunctions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/plugintoolbar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/processbinary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
4 changes: 3 additions & 1 deletion features/__init__.py → revengai/features/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
from .upload import UploadFeature
from .auto_unstrip import AutoUnstripFeature
from .choose_source import ChooseSourceFeature
from .match_functions import MatchFunctionsFeature
from .match_current_function import MatchCurrentFunctionFeature

__all__ = ['ConfigurationFeature', 'UploadFeature', 'AutoUnstripFeature', 'ChooseSourceFeature']
__all__ = ['ConfigurationFeature', 'UploadFeature', 'AutoUnstripFeature', 'ChooseSourceFeature', 'MatchFunctionsFeature', 'MatchCurrentFunctionFeature']
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from binaryninja import PluginCommand, log_info, BinaryView
from .auto_unstrip import AutoUnstrip
from .auto_unstrip_dialog import AutoUnstripDialog
from revengai_bn.utils import BaseAuthFeature
from revengai.utils import BaseAuthFeature

class AutoUnstripFeature(BaseAuthFeature):
def __init__(self, config=None):
Expand All @@ -11,7 +11,7 @@ def __init__(self, config=None):

def register(self):
PluginCommand.register(
"RevEng.AI\\AutoUnstrip",
"RevEng.AI\\4 - Auto Unstrip",
"Attempt to recover stripped function names",
self.show_auto_unstrip_dialog,
self.is_valid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Dict, Tuple
import math
from revengai.utils import rename_function as rename_function_util

class AutoUnstrip:
def __init__(self, config):
Expand All @@ -12,29 +13,7 @@ def __init__(self, config):
self.path = None
self.max_workers = 4

def _rename_function(self, bv: BinaryView, addr: int, new_name: str, new_name_mangled: str) -> bool:
try:
func = bv.get_function_at(addr)
if not func:
log_error(f"RevEng.AI | No function found at address {hex(addr)}")
return False

if func.name == new_name or func.name == new_name_mangled:
log_info(f"RevEng.AI | Function at {hex(addr)} already has name {func.name}")
return False

new_symbol = Symbol(SymbolType.FunctionSymbol, addr, new_name)
bv.define_user_symbol(new_symbol)

log_info(f"RevEng.AI | Renamed function at {hex(addr)} to {new_name}")
return True

except Exception as e:
log_error(f"RevEng.AI | Error renaming function at {hex(addr)}: {str(e)}")
return False

def _process_batch(self, function_ids: List[int], id_to_addr: Dict[int, int], bv: BinaryView) -> Tuple[int, List[str]]:
"""Process a batch of function IDs and return the number of renamed functions"""
try:
functions_by_distance = RE_nearest_symbols_batch(
function_ids=function_ids,
Expand All @@ -46,9 +25,9 @@ def _process_batch(self, function_ids: List[int], id_to_addr: Dict[int, int], bv
functions = []
for function in functions_by_distance:
functions.append({"function_id": function['origin_function_id'], "function_name": function['nearest_neighbor_function_name']})
log_info(f"RevEng.AI | Functions by distance: {functions}")
#log_info(f"RevEng.AI | Functions by distance: {functions}")
functions_by_score = RE_name_score(functions).json()["data"]
log_info(f"RevEng.AI | Functions by score: {functions_by_score}")
#log_info(f"RevEng.AI | Functions by score: {functions_by_score}")
renamed_count = 0
errors = []
for result in functions_by_distance:
Expand All @@ -69,16 +48,17 @@ def _process_batch(self, function_ids: List[int], id_to_addr: Dict[int, int], bv
for function in functions_by_score:
if function['function_id'] == func_id:
if function['box_plot']["average"] < 0.9:
log_info(f"RevEng.AI | Function {function['function_id']} has a score of {function['box_plot']["average"]:.2f} for name {function['function_name']}, skipping")
log_info(f"RevEng.AI | Function {function['function_id']} has a score of {function['box_plot']['average']:.2f} for name {new_name_mangled}, skipping")
break
else:
log_info(f"RevEng.AI | Function {function['function_id']} has a score of {function['box_plot']["average"]:.2f} for name {function['function_name']}, renaming")
if self._rename_function(bv, func_addr, new_name, new_name_mangled):
log_info(f"RevEng.AI | Function {function['function_id']} has a score of {function['box_plot']['average']:.2f} for name {new_name_mangled}, renaming")
if rename_function_util(bv, func_addr, new_name_mangled):
renamed_count += 1
break


except Exception as e:
log_error(f"RevEng.AI | Error processing function {result['origin_function_id']}: {str(e)}")
errors.append(str(e))

return renamed_count, errors
Expand Down Expand Up @@ -146,4 +126,4 @@ def auto_unstrip(self, bv: BinaryView):

except Exception as e:
log_error(f"RevEng.AI | Error: {str(e)}")
return False, str(e)
return False, str(e)
Loading