11from binaryninja import BinaryView , log_info , log_error , Symbol , SymbolType , interaction
22from 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
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 , RE_poll_ai_decompilation , RE_begin_ai_decompilation
44from concurrent .futures import ThreadPoolExecutor , as_completed
55from typing import List , Dict , Tuple
66import math
77from revengai .utils .datatypes import apply_data_types as apply_data_types_util
88import time
9- from revengai .utils import rename_function as rename_function_util
9+ from revengai .utils import rename_function as rename_function_util , get_function_id_by_addr as get_function_id_by_addr_util
1010from libbs .api import DecompilerInterface
1111from libbs .decompilers .binja .interface import BinjaInterface
1212from libbs .artifacts import _art_from_dict
1818 Struct ,
1919 Typedef ,
2020)
21+ from revengai .utils .periodic_check import PeriodicChecker
22+ from PySide6 .QtWidgets import QPlainTextEdit
23+ from binaryninja import BinaryView
24+ from binaryninjaui import UIContext
25+ from PySide6 .QtCore import QTimer
2126
2227class AIDecompiler :
2328 def __init__ (self , config ):
2429 self .config = config
30+ self ._current_checker = None
31+ self ._track_timer = None # Add timer instance variable
2532
33+ def stop_ai_decompiler (self ):
34+ """Stop the current AI decompiler checking"""
35+ try :
36+ if self ._current_checker :
37+ self ._current_checker .stop ()
38+ self ._current_checker = None
39+ log_info ("RevEng.AI | Stopped AI decompiler" )
40+ except Exception as e :
41+ log_error (f"RevEng.AI | Error stopping AI decompiler: { str (e )} " )
42+
43+ def stop_tracking (self ):
44+ """Stop the active line tracking"""
45+ try :
46+ if self ._track_timer :
47+ self ._track_timer .stop ()
48+ self ._track_timer = None
49+ log_info ("RevEng.AI | Stopped active line tracking" )
50+ except Exception as e :
51+ log_error (f"RevEng.AI | Error stopping active line tracking: { str (e )} " )
2652
27- def get_ai_decompiler (self , bv : BinaryView , options : Dict ) -> None :
53+
54+ def start_ai_decompiler (self , bv : BinaryView , options : Dict ) -> None :
2855 """Match functions from the binary against RevEng.AI database"""
2956 try :
57+ ClickMonitor ()
58+
3059 log_info ("RevEng.AI | Starting function searching in portal" )
31- function_addr = options .get ("function" , None )
60+ editor = options .get ("editor" )
61+ tab_name = options .get ("tab_name" )
62+ function = options .get ("function" )
63+ callback = options .get ("callback" )
64+ binary_id = self .config .get_binary_id (bv )
65+ function_id = get_function_id_by_addr_util (bv , function .start , binary_id )
3266
33- functions_containing = bv .get_functions_containing (function_addr )
67+ res = RE_poll_ai_decompilation (
68+ function_id ,
69+ summarise = True ,
70+ ).json ()
3471
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" )
72+ if not res . get ( "status" , False ) :
73+ callback ( editor , " AI Decompilation failed. " )
74+ return
3875
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 } ) " )
76+ poll_status = res . get ( "data" ). get ( "status" , "uninitialised" )
77+ log_info (f"RevEng.AI | Polling AI decompilation: { poll_status } " )
4178
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" ]
79+ if poll_status == "uninitialised" :
80+ log_info (f"RevEng.AI | Starting AI Decompilation for function at 0x{ function .start :x} " )
4881
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 )
82+ try :
83+ res2 = RE_begin_ai_decompilation (
84+ function_id
85+ ).json ()
86+ except Exception as e :
87+ log_error (f"RevEng.AI | Error beginning AI decompilation: { str (e )} " )
88+ callback (editor , "AI Decompilation failed." )
89+ return
90+
91+ if not res2 .get ("status" , False ):
92+ callback (editor , "AI Decompilation failed." )
93+ return
94+
95+ log_info ("RevEng.AI | AI Decompilation started" )
96+
97+ # Create PeriodicChecker instance (it's now a QObject)
98+ periodic_checker = PeriodicChecker ()
99+
100+ # Start the AI decompiler checking with proper parameters
101+ periodic_checker .start_ai_decompiler_checking (function_id , callback , editor , tab_name )
102+
103+ # Store reference to prevent garbage collection
104+ self ._current_checker = periodic_checker
56105
57- return True , "Function found in portal"
106+ if poll_status == "success" :
107+ log_info (f"RevEng.AI | AI Decompilation for function at 0x{ function .start :x} is completed" )
108+ callback (editor , res .get ("data" ).get ("decompilation" ))
58109
59110 except Exception as e :
60- log_error (f"RevEng.AI | Error in function matching: { str (e )} " )
61- return False , str (e )
111+ log_error (f"RevEng.AI | Error in AI decompiler: { str (e )} " )
112+ return False , str (e )
113+
114+ from binaryninja import PluginCommand , BinaryView
115+ from binaryninjaui import UIContext , UIContextNotification
116+
117+ class ClickMonitor (UIContextNotification ):
118+ def __init__ (self ):
119+ log_info ("RevEng.AI | ClickMonitor initialized" )
120+ super ().__init__ ()
121+ log_info (f"RevEng.AI | class ClickMonitor" )
122+ for nome in dir (self ):
123+ attr = getattr (self , nome )
124+ if callable (attr ) and not nome .startswith ("__" ) and not nome .startswith ("On" ):
125+ log_info (f"RevEng.AI | { nome } " )
126+ UIContext .registerNotification (self )
127+
128+ def OnViewChanged (self , context , view ):
129+ log_info (f"RevEng.AI | View changed: { view } " )
130+
131+ def OnAddressChanged (self , context , view , addr ):
132+ log_info (f"RevEng.AI | User navigated to address: { hex (addr )} " )
133+
0 commit comments