Skip to content

Commit 5493fbd

Browse files
committed
dev: start of ai decomp
1 parent 7b1c238 commit 5493fbd

6 files changed

Lines changed: 150 additions & 4 deletions

File tree

revengai/features/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .choose_source import ChooseSourceFeature
55
from .match_functions import MatchFunctionsFeature
66
from .match_current_function import MatchCurrentFunctionFeature
7-
from .view_function_in_portal import ViewFunctionInPortalFeature
7+
from .view_function_in_portal import ViewFunctionInPortalFeature
8+
from .ai_decompiler import AIDecompilerFeature
89

9-
__all__ = ['ConfigurationFeature', 'UploadFeature', 'AutoUnstripFeature', 'ChooseSourceFeature', 'MatchFunctionsFeature', 'MatchCurrentFunctionFeature', 'ViewFunctionInPortalFeature']
10+
__all__ = ['ConfigurationFeature', 'UploadFeature', 'AutoUnstripFeature', 'ChooseSourceFeature', 'MatchFunctionsFeature', 'MatchCurrentFunctionFeature', 'ViewFunctionInPortalFeature', 'AIDecompilerFeature']
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from binaryninja import PluginCommand, log_info, BinaryView
2+
from .ai_decompiler import AIDecompiler
3+
from .ai_decompiler_dialog import AIDecompilerDialog
4+
from revengai.utils import BaseAuthFeature
5+
6+
class AIDecompilerFeature(BaseAuthFeature):
7+
def __init__(self, config=None):
8+
super().__init__(config)
9+
self.ai_decompiler = AIDecompiler(config)
10+
log_info("RevEng.AI | AIDecompiler Feature initialized")
11+
12+
def register(self):
13+
PluginCommand.register_for_address(
14+
"RevEng.AI\\7 - AI Decompiler",
15+
"Get the AI decompiler for the current function",
16+
self.show_ai_decompiler_dialog,
17+
self.is_valid
18+
)
19+
log_info("RevEng.AI | AIDecompiler Feature registered")
20+
21+
def show_ai_decompiler_dialog(self, bv: BinaryView, func):
22+
log_info("RevEng.AI | Opening MatchCurrentFunction dialog")
23+
dialog = AIDecompilerDialog(self.config, self.ai_decompiler, bv, func)
24+
dialog.exec_()
25+
26+
def is_valid(self, bv: BinaryView, func):
27+
return self.config.is_configured == True
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from binaryninja import BinaryView, log_info, log_error, Symbol, SymbolType, interaction
2+
from binaryninja.interaction import InteractionHandler
3+
from reait.api import RE_authentication, RE_search, RE_nearest_symbols_batch, RE_analyze_functions, RE_name_score, RE_functions_data_types, RE_functions_data_types_poll, RE_get_analysis_id_from_binary_id, RE_get_functions_from_analysis
4+
from concurrent.futures import ThreadPoolExecutor, as_completed
5+
from typing import List, Dict, Tuple
6+
import math
7+
from revengai.utils.datatypes import apply_data_types as apply_data_types_util
8+
import time
9+
from revengai.utils import rename_function as rename_function_util
10+
from libbs.api import DecompilerInterface
11+
from libbs.decompilers.binja.interface import BinjaInterface
12+
from libbs.artifacts import _art_from_dict
13+
from libbs.artifacts import (
14+
Function,
15+
FunctionArgument,
16+
GlobalVariable,
17+
Enum,
18+
Struct,
19+
Typedef,
20+
)
21+
22+
class AIDecompiler:
23+
def __init__(self, config):
24+
self.config = config
25+
26+
27+
def get_ai_decompiler(self, bv: BinaryView, options: Dict) -> None:
28+
"""Match functions from the binary against RevEng.AI database"""
29+
try:
30+
log_info("RevEng.AI | Starting function searching in portal")
31+
function_addr = options.get("function", None)
32+
33+
functions_containing = bv.get_functions_containing(function_addr)
34+
35+
if not functions_containing:
36+
log_error(f"RevEng.AI | Function not found at 0x{function_addr:x}")
37+
raise Exception("Function not found at address")
38+
39+
function = functions_containing[0]
40+
log_info(f"RevEng.AI | Function: {function.name} at 0x{function.start:x} (Clicked address: 0x{function_addr:x})")
41+
42+
binary_id = self.config.get_binary_id(bv)
43+
if not binary_id:
44+
raise Exception("Analysis not found. Please choose one using 'Choose Source' feature.")
45+
46+
analysis = RE_get_analysis_id_from_binary_id(binary_id).json()
47+
analyzed_functions = RE_get_functions_from_analysis(analysis["analysis_id"]).json()["data"]["functions"]
48+
49+
analyzed_function = next((f for f in analyzed_functions if (f["function_vaddr"] + bv.image_base) == function.start), None)
50+
if not analyzed_function:
51+
log_error(f"RevEng.AI | Function {function.name} not found in analyzed functions")
52+
raise Exception("Function not found in analyzed functions")
53+
54+
url = f"https://portal.reveng.ai/function/{analyzed_function['function_id']}"
55+
InteractionHandler().open_url(url)
56+
57+
return True, "Function found in portal"
58+
59+
except Exception as e:
60+
log_error(f"RevEng.AI | Error in function matching: {str(e)}")
61+
return False, str(e)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from binaryninja import log_error
2+
from PySide6.QtWidgets import (QDockWidget, QVBoxLayout, QHBoxLayout,
3+
QPushButton, QLabel, QCheckBox, QWidget)
4+
from PySide6.QtCore import Qt
5+
from PySide6.QtGui import QPixmap
6+
from PySide6.QtCore import QCoreApplication
7+
from PySide6.QtWidgets import QMessageBox
8+
from PySide6.QtWidgets import QProgressBar
9+
from revengai.utils import create_progress_dialog
10+
from revengai.utils.data_thread import DataThread
11+
import os
12+
13+
class AIDecompilerDialog(QDockWidget):
14+
def __init__(self, config, ai_decompiler, bv, func):
15+
super().__init__()
16+
self.config = config
17+
self.ai_decompiler = ai_decompiler
18+
self.bv = bv
19+
self.func = func
20+
self.init_ui()
21+
22+
def init_ui(self):
23+
self.setWindowTitle("RevEng.AI: AI Decompiler")
24+
25+
# Create a widget to hold the layout
26+
content_widget = QWidget()
27+
layout = QVBoxLayout(content_widget)
28+
29+
title_label = QLabel("Getting AI decompiler...")
30+
title_label.setStyleSheet("font-size: 18px;")
31+
layout.addWidget(title_label)
32+
33+
progress_bar = QProgressBar()
34+
progress_bar.setMinimumWidth(250)
35+
progress_bar.setMinimumHeight(20)
36+
layout.addWidget(progress_bar)
37+
38+
# Set the content widget
39+
self.setWidget(content_widget)
40+
41+
self.setStyleSheet("""
42+
QProgressBar {
43+
border: 1px solid #cccccc;
44+
border-radius: 4px;
45+
text-align: center;
46+
background-color: #f0f0f0;
47+
min-width: 250px;
48+
min-height: 20px;
49+
}
50+
QProgressBar::chunk {
51+
background-color: #007bff;
52+
border-radius: 3px;
53+
}
54+
""")

revengai/features/view_function_in_portal/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def __init__(self, config=None):
1111

1212
def register(self):
1313
PluginCommand.register_for_address(
14-
"RevEng.AI\\7 - View Function in Portal",
14+
"RevEng.AI\\8 - View Function in Portal",
1515
"View the current function in the RevEng.AI portal",
1616
self.show_match_current_function_dialog,
1717
self.is_valid

revengai/revengai.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .features import MatchFunctionsFeature
77
from .features import MatchCurrentFunctionFeature
88
from .features import ViewFunctionInPortalFeature
9+
from .features import AIDecompilerFeature
910

1011
class RevengAIPlugin:
1112
def __init__(self):
@@ -17,6 +18,7 @@ def __init__(self):
1718
self.match_functions_feature = MatchFunctionsFeature(self.config_feature.get_config())
1819
self.match_current_function_feature = MatchCurrentFunctionFeature(self.config_feature.get_config())
1920
self.view_function_in_portal_feature = ViewFunctionInPortalFeature(self.config_feature.get_config())
21+
self.ai_decompiler_feature = AIDecompilerFeature(self.config_feature.get_config())
2022
self._register_features()
2123

2224
def _register_features(self):
@@ -27,4 +29,5 @@ def _register_features(self):
2729
self.choose_source_feature.register()
2830
self.match_functions_feature.register()
2931
self.match_current_function_feature.register()
30-
self.view_function_in_portal_feature.register()
32+
self.view_function_in_portal_feature.register()
33+
self.ai_decompiler_feature.register()

0 commit comments

Comments
 (0)