# Copyright (c) 2015-2025 Vector 35 Inc## Permission is hereby granted, free of charge, to any person obtaining a copy# of this software and associated documentation files (the "Software"), to# deal in the Software without restriction, including without limitation the# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or# sell copies of the Software, and to permit persons to whom the Software is# furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in# all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS# IN THE SOFTWARE.importabcimportcodeimportctypesimportdataclassesimportimportlibimportosimportreimportsubprocessimportsysimportthreadingimporttracebackfromcollections.abcimportCallablefromctypes.utilimportfind_libraryfrompathlibimportPathfromtypingimportGenerator,Optional,List,Tuple,Dict,AnyfromtypingimportTypeasTypeHintType# Just windows things...ifsys.platform=="win32":frompydocimporthelp# Binary Ninja componentsimportbinaryninjafrom.importbncompleterfrom.import_binaryninjacoreascorefrom.importsettingsfrom.importbinaryviewfrom.importbasicblockfrom.importfunctionfrom.importlogfrom.pluginmanagerimportRepositoryManagerfrom.enumsimportScriptingProviderExecuteResult,ScriptingProviderInputReadyStatefrom.settingsimportSettingsfrom.enumsimportSettingsScope_WARNING_REGEX=re.compile(r'^\S+:\d+: \w+Warning: ')logger=log.Logger(0,"ScriptingProvider")class_ThreadActionContext:_actions=[]def__init__(self,func):self.func=funcself.interpreter=Noneifhasattr(PythonScriptingInstance._interpreter,"value"):self.interpreter=PythonScriptingInstance._interpreter.valueself.__class__._actions.append(self)self.callback=ctypes.CFUNCTYPE(None,ctypes.c_void_p)(lambdactxt:self.execute())defexecute(self):old_interpreter=Noneifhasattr(PythonScriptingInstance._interpreter,"value"):old_interpreter=PythonScriptingInstance._interpreter.valuePythonScriptingInstance._interpreter.value=self.interpretertry:self.func()finally:PythonScriptingInstance._interpreter.value=old_interpreterself.__class__._actions.remove(self)[docs]classScriptingOutputListener:def_register(self,handle):self._cb=core.BNScriptingOutputListener()self._cb.context=0self._cb.output=self._cb.output.__class__(self._output)self._cb.warning=self._cb.warning.__class__(self._warning)self._cb.error=self._cb.error.__class__(self._error)self._cb.inputReadyStateChanged=self._cb.inputReadyStateChanged.__class__(self._input_ready_state_changed)core.BNRegisterScriptingInstanceOutputListener(handle,self._cb)def_unregister(self,handle):core.BNUnregisterScriptingInstanceOutputListener(handle,self._cb)def_output(self,ctxt,text):try:self.notify_output(text)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingOutputListener._output")def_warning(self,ctxt,text):try:self.notify_warning(text)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingOutputListener._warning")def_error(self,ctxt,text):try:self.notify_error(text)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingOutputListener._error")def_input_ready_state_changed(self,ctxt,state):try:self.notify_input_ready_state_changed(state)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingOutputListener._input_ready_state_changed")[docs]defnotify_output(self,text):pass [docs]defnotify_warning(self,text):pass [docs]defnotify_error(self,text):pass [docs]defnotify_input_ready_state_changed(self,state):pass [docs]classScriptingInstance:_registered_instances=[][docs]def__init__(self,provider,handle=None):ifhandleisNone:self._cb=core.BNScriptingInstanceCallbacks()self._cb.context=0self._cb.externalRefTaken=self._cb.externalRefTaken.__class__(self._external_ref_taken)self._cb.externalRefReleased=self._cb.externalRefReleased.__class__(self._external_ref_released)self._cb.executeScriptInput=self._cb.executeScriptInput.__class__(self._execute_script_input)self._cb.executeScriptInputFromFilename=self._cb.executeScriptInputFromFilename.__class__(self._execute_script_input_from_filename)self._cb.cancelScriptInput=self._cb.cancelScriptInput.__class__(self._cancel_script_input)self._cb.releaseBinaryView=self._cb.releaseBinaryView.__class__(self._release_binary_view)self._cb.setCurrentBinaryView=self._cb.setCurrentBinaryView.__class__(self._set_current_binary_view)self._cb.setCurrentFunction=self._cb.setCurrentFunction.__class__(self._set_current_function)self._cb.setCurrentBasicBlock=self._cb.setCurrentBasicBlock.__class__(self._set_current_basic_block)self._cb.setCurrentAddress=self._cb.setCurrentAddress.__class__(self._set_current_address)self._cb.setCurrentSelection=self._cb.setCurrentSelection.__class__(self._set_current_selection)self._cb.completeInput=self._cb.completeInput.__class__(self._complete_input)self._cb.stop=self._cb.stop.__class__(self._stop)self._completed_input=Noneself.handle=core.BNInitScriptingInstance(provider.handle,self._cb)self.delimiters='\t\n`~!@#$%^&*()-=+{}\\|;:\'",<>/?'else:self.handle=core.handle_of_type(handle,core.BNScriptingInstance)self.listeners=[] def__del__(self):ifcoreisnotNone:core.BNFreeScriptingInstance(self.handle)def_external_ref_taken(self,ctxt):try:self.__class__._registered_instances.append(self)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._external_ref_taken")def_external_ref_released(self,ctxt):try:self.__class__._registered_instances.remove(self)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._external_ref_released")def_execute_script_input(self,ctxt,text):try:returnself.perform_execute_script_input(text)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._execute_script_input")returnScriptingProviderExecuteResult.InvalidScriptInputdef_execute_script_input_from_filename(self,ctxt,filename):try:returnself.perform_execute_script_input_from_filename(filename)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._execute_script_input_from_filename")returnScriptingProviderExecuteResult.InvalidScriptInputdef_cancel_script_input(self,ctxt):try:returnself.perform_cancel_script_input()except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._cancel_script_input")returnScriptingProviderExecuteResult.ScriptExecutionCancelleddef_release_binary_view(self,ctxt,view):try:binaryview.BinaryView._cache_remove(view)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._release_binary_view")def_set_current_binary_view(self,ctxt,view):try:ifview:view=binaryview.BinaryView(handle=core.BNNewViewReference(view))binaryview.BinaryView._cache_insert(view)else:view=Noneself.perform_set_current_binary_view(view)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._set_current_binary_view")def_set_current_function(self,ctxt,func):try:iffunc:func=function.Function(handle=core.BNNewFunctionReference(func))else:func=Noneself.perform_set_current_function(func)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._set_current_function")def_set_current_basic_block(self,ctxt,block):try:ifblock:func=core.BNGetBasicBlockFunction(block)iffuncisNone:block=Noneelse:core_block=core.BNNewBasicBlockReference(block)assertcore_blockisnotNone,"core.BNNewBasicBlockReference returned None"block=basicblock.BasicBlock(core_block,binaryview.BinaryView(handle=core.BNGetFunctionData(func)))core.BNFreeFunction(func)else:block=Noneself.perform_set_current_basic_block(block)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._set_current_basic_block")def_set_current_address(self,ctxt,addr):try:self.perform_set_current_address(addr)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._set_current_address")def_set_current_selection(self,ctxt,begin,end):try:self.perform_set_current_selection(begin,end)except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._set_current_selection")def_complete_input(self,ctxt,text,state):try:ifnotisinstance(text,str):text=text.decode("utf-8")returncore.BNAllocString(self.perform_complete_input(text,state))except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._complete_input")returncore.BNAllocString("")def_stop(self,ctxt):try:self.perform_stop()except:logger.log_error_for_exception("Unhandled Python exception in ScriptingInstance._stop")[docs]@abc.abstractmethoddefperform_execute_script_input(self,text):returnScriptingProviderExecuteResult.InvalidScriptInput [docs]@abc.abstractmethoddefperform_execute_script_input_from_filename(self,text):returnScriptingProviderExecuteResult.InvalidScriptInput [docs]@abc.abstractmethoddefperform_cancel_script_input(self):returnScriptingProviderExecuteResult.ScriptExecutionCancelled [docs]@abc.abstractmethoddefperform_set_current_binary_view(self,view):returnNotImplemented [docs]@abc.abstractmethoddefperform_set_current_function(self,func):returnNotImplemented [docs]@abc.abstractmethoddefperform_set_current_basic_block(self,block):returnNotImplemented [docs]@abc.abstractmethoddefperform_set_current_address(self,addr):returnNotImplemented [docs]@abc.abstractmethoddefperform_set_current_selection(self,begin,end):returnNotImplemented [docs]@abc.abstractmethoddefperform_complete_input(self,text:str,state)->str:returnNotImplemented [docs]@abc.abstractmethoddefperform_stop(self):returnNotImplemented @propertydefinput_ready_state(self):returncore.BNGetScriptingInstanceInputReadyState(self.handle)@input_ready_state.setterdefinput_ready_state(self,value):core.BNNotifyInputReadyStateForScriptingInstance(self.handle,value.value)[docs]defoutput(self,text):core.BNNotifyOutputForScriptingInstance(self.handle,text) [docs]defwarning(self,text):core.BNNotifyWarningForScriptingInstance(self.handle,text) [docs]deferror(self,text):core.BNNotifyErrorForScriptingInstance(self.handle,text) [docs]defexecute_script_input(self,text):returncore.BNExecuteScriptInput(self.handle,text) [docs]defexecute_script_input_from_filename(self,filename):returncore.BNExecuteScriptInputFromFilename(self.handle,filename) [docs]defcancel_script_input(self,text):returncore.BNCancelScriptInput(self.handle) [docs]defset_current_binary_view(self,view):ifviewisnotNone:view=view.handlecore.BNSetScriptingInstanceCurrentBinaryView(self.handle,view) [docs]defset_current_function(self,func):iffuncisnotNone:func=func.handlecore.BNSetScriptingInstanceCurrentFunction(self.handle,func) [docs]defset_current_basic_block(self,block):ifblockisnotNone:block=block.handlecore.BNSetScriptingInstanceCurrentBasicBlock(self.handle,block) [docs]defset_current_address(self,addr):core.BNSetScriptingInstanceCurrentAddress(self.handle,addr) [docs]defset_current_selection(self,begin,end):core.BNSetScriptingInstanceCurrentSelection(self.handle,begin,end) [docs]defcomplete_input(self,text,state):returncore.BNScriptingInstanceCompleteInput(self.handle,text,state) [docs]defstop(self):core.BNStopScriptingInstance(self.handle) [docs]defregister_output_listener(self,listener):listener._register(self.handle)self.listeners.append(listener) [docs]defunregister_output_listener(self,listener):iflistenerinself.listeners:listener._unregister(self.handle)self.listeners.remove(listener) @propertydefdelimiters(self):returncore.BNGetScriptingInstanceDelimiters(self.handle)@delimiters.setterdefdelimiters(self,value):core.BNSetScriptingInstanceDelimiters(self.handle,value) class_ScriptingProviderMetaclass(type):def__iter__(self)->Generator['ScriptingProvider',None,None]:binaryninja._init_plugins()count=ctypes.c_ulonglong()types=core.BNGetScriptingProviderList(count)asserttypesisnotNone,"core.BNGetScriptingProviderList returned None"try:foriinrange(0,count.value):yieldScriptingProvider(types[i])finally:core.BNFreeScriptingProviderList(types)def__getitem__(self,value)->'ScriptingProvider':binaryninja._init_plugins()provider=core.BNGetScriptingProviderByName(str(value))ifproviderisNone:raiseKeyError("'%s' is not a valid scripting provider"%str(value))returnScriptingProvider(provider)[docs]classScriptingProvider(metaclass=_ScriptingProviderMetaclass):_registered_providers=[]name=''apiName=''instance_class:Optional[TypeHintType[ScriptingInstance]]=None[docs]def__init__(self,handle=None):ifhandleisnotNone:self.handle=core.handle_of_type(handle,core.BNScriptingProvider)self.__dict__["name"]=core.BNGetScriptingProviderName(handle) [docs]defregister(self)->None:self._cb=core.BNScriptingProviderCallbacks()self._cb.context=0self._cb.createInstance=self._cb.createInstance.__class__(self._create_instance)self._cb.loadModule=self._cb.loadModule.__class__(self._load_module)self._cb.installModules=self._cb.installModules.__class__(self._install_modules)self._cb.moduleInstalled=self._cb.installModules.__class__(self._module_installed)self.handle=core.BNRegisterScriptingProvider(self.__class__.name,self.__class__.apiName,self._cb)self.__class__._registered_providers.append(self) def_create_instance(self,ctxt):try:assertself.__class__.instance_classisnotNoneresult=self.__class__.instance_class(self)# type: ignoreifresultisNone:returnNonescript_instance=core.BNNewScriptingInstanceReference(result.handle)assertscript_instanceisnotNone,"core.BNNewScriptingInstanceReference returned None"returnctypes.cast(script_instance,ctypes.c_void_p).valueexcept:logger.log_error_for_exception("Unhandled Python exception in ScriptingProvider._create_instance")returnNone[docs]defcreate_instance(self)->Optional[ScriptingInstance]:result=core.BNCreateScriptingProviderInstance(self.handle)ifresultisNone:returnNonereturnScriptingInstance(self,handle=result) def_load_module(self,ctx,repo_path:bytes,plugin_path:bytes,force:bool)->bool:returnFalsedef_install_modules(self,ctx,modules:bytes)->bool:returnFalsedef_module_installed(self,ctx,module:str)->bool:returnFalse class_PythonScriptingInstanceOutput:def__init__(self,orig,is_error_output):self.orig=origself.is_error_output=is_error_outputself.buffer=""self.encoding='UTF-8'self.errors=Noneself.mode='w'self.name='PythonScriptingInstanceOutput'self.newlines=Nonedefclose(self):passdefclosed(self):returnFalsedefflush(self):passdefisatty(self):returnFalsedefnext(self):raiseIOError("File not open for reading")defread(self):raiseIOError("File not open for reading")defreadinto(self):raiseIOError("File not open for reading")defreadlines(self):raiseIOError("File not open for reading")defseek(self):passdefsoftspace(self):return0deftruncate(self):passdeftell(self):returnself.orig.tell()defwritelines(self,lines):returnself.write('\n'.join(lines))defwrite(self,data):interpreter=Noneifhasattr(PythonScriptingInstance._interpreter,"value"):interpreter=PythonScriptingInstance._interpreter.valueifinterpreterisNone:iflog.is_output_redirected_to_log():self.buffer+=datawhileTrue:i=self.buffer.find('\n')ifi==-1:breakline=self.buffer[:i]self.buffer=self.buffer[i+1:]ifself.is_error_output:if_WARNING_REGEX.match(line):logger.log_warn(line)else:logger.log_error(line)else:logger.log_info(line)else:self.orig.write(data)else:PythonScriptingInstance._interpreter.value=Nonetry:ifself.is_error_output:if_WARNING_REGEX.match(data):interpreter.instance.warning(data)else:interpreter.instance.error(data)else:interpreter.instance.output(data)finally:PythonScriptingInstance._interpreter.value=interpreterclass_PythonScriptingInstanceInput:def__init__(self,orig):self.orig=origdefisatty(self):returnFalsedefread(self,size):interpreter=Noneifhasattr(PythonScriptingInstance._interpreter,"value"):interpreter=PythonScriptingInstance._interpreter.valueifinterpreterisNone:returnself.orig.read(size)else:PythonScriptingInstance._interpreter.value=Nonetry:result=interpreter.read(size)finally:PythonScriptingInstance._interpreter.value=interpreterreturnresultdefreadline(self):interpreter=Noneifhasattr(PythonScriptingInstance._interpreter,"value"):interpreter=PythonScriptingInstance._interpreter.valueifinterpreterisNone:returnself.orig.readline()else:result=""whileTrue:data=interpreter.read(1)result+=dataif(len(data)==0)or(data=="\n"):breakreturnresult[docs]classBlacklistedDict(dict):[docs]def__init__(self,blacklist,*args):super(BlacklistedDict,self).__init__(*args)self.__blacklist=set(blacklist)self._blacklist_enabled=True def__setitem__(self,k,v):ifself.blacklist_enabledandkinself.__blacklist:sys.stderr.write('Setting variable "{}" will have no affect as it is automatically controlled by the ScriptingProvider.\n'.format(k))super(BlacklistedDict,self).__setitem__(k,v)[docs]defenable_blacklist(self,enabled):self.__enable_blacklist=enabled [docs]defadd_blacklist_item(self,item):self.__blacklist.add(item) [docs]defremove_blacklist_item(self,item):self.__blacklist.remove(item) [docs]defis_blacklisted_item(self,item):returniteminself.__blacklist @propertydefblacklist_enabled(self):returnself._blacklist_enabled@blacklist_enabled.setterdefblacklist_enabled(self,value):self._blacklist_enabled=value [docs]defbninspect(code_,globals_,locals_):"""``bninspect`` prints documentation about a command that is about to be runThe interpreter will invoke this function if you input a line ending in `?` e.g. `bv?`:param str code_: Python code to be evaluated:param dict globals_: globals() from callsite:param dict locals_: locals() from callsite"""try:importinspectvalue=eval(code_,globals_,locals_)try:ifnot(inspect.ismethod(value)orinspect.isclass(value)):ifisinstance(code_,bytes):code_=code_.decode("utf-8")class_type_str=code_.split(".")[:-1]class_value=eval("type("+".".join(class_type_str)+")."+code_.split(".")[-1],globals_,locals_)doc=inspect.getdoc(class_value)ifdocisNone:comments=inspect.getcomments(class_value)ifcommentsisNone:passelse:print(comments)returnelse:print(doc)returnexcept:passdoc=inspect.getdoc(value)ifdocisNone:comments=inspect.getcomments(value)ifcommentsisNone:passelse:print(comments)returnelse:print(doc)returnprint(f"No documentation found for{code_}")except:# Hide exceptions so the normal execution can report thempass [docs]classPythonScriptingInstance(ScriptingInstance):_interpreter=threading.local()[docs]classInterpreterThread(threading.Thread):[docs]def__init__(self,instance):super(PythonScriptingInstance.InterpreterThread,self).__init__()self.instance=instanceblacklisted_vars={"get_selected_data","write_at_cursor",}self.locals=BlacklistedDict(blacklisted_vars,{"__name__":"__console__","__doc__":None,"binaryninja":sys.modules[__name__]})self.cached_locals={}self.interpreter=code.InteractiveConsole(self.locals)self.event=threading.Event()self.daemon=True# Latest selections from UIself.current_view=Noneself.current_func=Noneself.current_block=Noneself.current_addr=0self.current_selection_begin=0self.current_selection_end=0self.current_dbg=None# Selections that were current as of last issued commandself.active_view=Noneself.active_func=Noneself.active_block=Noneself.active_addr=0self.active_selection_begin=0self.active_selection_end=0self.active_file_offset=Noneself.active_dbg=Noneself.active_il_index=0self.selection_start_il_index=0self.active_il_function=Noneself.update_magic_variables()self.locals.blacklist_enabled=Falseself.locals["get_selected_data"]=self.get_selected_dataself.locals["write_at_cursor"]=self.write_at_cursorself.locals.blacklist_enabled=Trueself.exit=Falseself.code=Noneself.input=""self.completer=bncompleter.Completer(namespace=self.locals)startup_file=os.path.join(binaryninja.user_directory(),"startup.py")ifnotos.path.isfile(startup_file):withopen(startup_file,'w')asf:f.write("""# Commands in this file will be run in the interactive python console on startupfrom binaryninja import *""")withopen(startup_file,'r')asf:self.interpreter.runsource(f.read(),filename="startup.py",symbol="exec") [docs]defupdate_magic_variables(self):for(name,var)inPythonScriptingProvider.magic_variables.items():ifvar.set_valueisNone:self.locals.add_blacklist_item(name)elifself.locals.is_blacklisted_item(name):self.locals.remove_blacklist_item(name) [docs]defexecute(self,_code):self.code=_codeself.event.set() [docs]defadd_input(self,data):self.input=self.input+data.decode("utf-8")self.event.set() [docs]defend(self):self.exit=Trueself.event.set() [docs]defread(self,size):whilenotself.exit:iflen(self.input)>size:result=self.input[:size]self.input=self.input[size:]returnresulteliflen(self.input)>0:result=self.inputself.input=""returnresultself.instance.input_ready_state=ScriptingProviderInputReadyState.ReadyForScriptProgramInputself.event.wait()self.event.clear()return"" [docs]defrun(self):core.BNSetThreadName("PythonInterpreterThread")whilenotself.exit:self.event.wait()self.event.clear()ifself.exit:breakifself.codeisnotNone:self.instance.input_ready_state=ScriptingProviderInputReadyState.NotReadyForInput_code=self.codeself.code=NonePythonScriptingInstance._interpreter.value=selftry:try:self.update_locals()except:traceback.print_exc()ifisinstance(_code,(lambda:0).__code__.__class__):self.interpreter.runcode(_code)self.locals['__name__']='__console__'delself.locals['__file__']else:# If a single-line command ends in ?, show docs as wellif_code[-2:]==b'?\n'andlen(_code.split(b'\n'))<3:escaped_code=repr(_code[:-2])self.interpreter.push(f'bninspect({escaped_code}, globals(), locals())\n')# Strip ? from the evaluated input_code=_code[:-2]+b'\n'forlinein_code.split(b'\n'):self.interpreter.push(line.decode("utf-8"))self.apply_locals()ifself.active_viewisnotNone:value,scope=Settings().get_bool_with_scope("python.updateAnalysisAfterCommand")ifscope==SettingsScope.SettingsInvalidScopeorvalue:self.active_view.update_analysis()except:traceback.print_exc()finally:PythonScriptingInstance._interpreter.value=Noneself.instance.input_ready_state=ScriptingProviderInputReadyState.ReadyForScriptExecution [docs]defupdate_locals(self):self.active_view=self.current_viewself.active_func=self.current_funcself.active_block=self.current_blockself.active_addr=self.current_addrself.active_selection_begin=self.current_selection_beginself.active_selection_end=self.current_selection_endself.active_dbg=self.current_dbgself.locals.blacklist_enabled=False# Clear old values of magic variables first, so we don't update with stale datafornameinPythonScriptingProvider.magic_variables.keys():ifnameinself.locals:delself.locals[name]# Apply registered magic variablesvars=list(PythonScriptingProvider.magic_variables.items())used_vars=set()whilelen(vars)>0:(name,var)=vars.pop(0)# Vars depending on others should make sure their deps have loaded first# TODO: Is this O(n^2)? Probably, but shouldn't be that big of a dealneeds_deps=Falsefordepinvar.depends_on:ifdepinPythonScriptingProvider.magic_variables.keys()anddepnotinused_vars:needs_deps=Truebreakifneeds_deps:# Add to the end and we'll get to it latervars.append((name,var))continueused_vars.add(name)try:value=var.get_value(self.instance)except:value=Noneself.locals[name]=valueself.cached_locals[name]=valueself.locals.blacklist_enabled=True [docs]defapply_locals(self):for(name,var)inPythonScriptingProvider.magic_variables.items():ifvar.set_valueisNone:continueold_value=self.cached_locals[name]new_value=self.locals[name]ifold_value==new_value:continuetry:var.set_value(self.instance,old_value,new_value)except:sys.stderr.write(f"Exception thrown trying to update variable:\n")traceback.print_exc(file=sys.stderr)self.cached_locals.clear() [docs]defget_selected_data(self):ifself.active_viewisNone:returnNonelength=self.active_selection_end-self.active_selection_beginreturnself.active_view.read(self.active_selection_begin,length) [docs]defwrite_at_cursor(self,data):ifself.active_viewisNone:return0selected_length=self.active_selection_end-self.active_selection_beginif(len(data)==selected_length)or(selected_length==0):returnself.active_view.write(self.active_selection_begin,data)else:self.active_view.remove(self.active_selection_begin,selected_length)returnself.active_view.insert(self.active_selection_begin,data) [docs]def__init__(self,provider):super(PythonScriptingInstance,self).__init__(provider)self.interpreter=PythonScriptingInstance.InterpreterThread(self)self.interpreter.start()self.queued_input=""self.input_ready_state=ScriptingProviderInputReadyState.ReadyForScriptExecutionself.debugger_imported=Falsefrombinaryninja.settingsimportSettingssettings=Settings()ifsettings.contains('corePlugins.view.sharedCache')andsettings.get_bool('corePlugins.view.sharedCache'):from.sharedcacheimportSharedCacheControllerifsettings.contains('corePlugins.view.kernelCache')andsettings.get_bool('corePlugins.view.kernelCache'):from.kernelcacheimportKernelCacheControllerifos.environ.get('BN_STANDALONE_DEBUGGER'):# By the time this scriptingprovider.py file is imported, the user plugins are not loaded yet.# So `from debugger import DebuggerController` would not work.fromdebuggerimportDebuggerControllerself.DebuggerController=DebuggerControllerself.debugger_imported=Trueelse:ifsettings.contains('corePlugins.debugger')andsettings.get_bool('corePlugins.debugger')and \
(os.environ.get('BN_DISABLE_CORE_DEBUGGER')isNone):from.debuggerimportDebuggerControllerself.DebuggerController=DebuggerControllerself.debugger_imported=True [docs]@abc.abstractmethoddefperform_stop(self):self.interpreter.end() [docs]@abc.abstractmethoddefperform_execute_script_input(self,text):ifself.input_ready_state==ScriptingProviderInputReadyState.NotReadyForInput:returnScriptingProviderExecuteResult.InvalidScriptInputifself.input_ready_state==ScriptingProviderInputReadyState.ReadyForScriptProgramInput:iflen(text)==0:returnScriptingProviderExecuteResult.SuccessfulScriptExecutionself.input_ready_state=ScriptingProviderInputReadyState.NotReadyForInputself.interpreter.add_input(text)returnScriptingProviderExecuteResult.SuccessfulScriptExecutiontry:ifisinstance(text,str):result=code.compile_command(text)else:result=code.compile_command(text.decode("utf-8"))except:result=FalseifresultisNone:# Command is not complete, ask for more inputreturnScriptingProviderExecuteResult.IncompleteScriptInputself.input_ready_state=ScriptingProviderInputReadyState.NotReadyForInputself.interpreter.execute(text)returnScriptingProviderExecuteResult.SuccessfulScriptExecution [docs]@abc.abstractmethoddefperform_execute_script_input_from_filename(self,filename):ifisinstance(filename,bytes):filename=filename.decode("utf-8")ifnotos.path.exists(filename)andos.path.isfile(filename):returnScriptingProviderExecuteResult.InvalidScriptInput# TODO: maybe this isn't the best result to use?try:withopen(filename,'rb')asfp:file_contents=fp.read()exceptIOError:# File was not readable or something went horribly wrongreturnScriptingProviderExecuteResult.InvalidScriptInputiflen(file_contents)==0:returnScriptingProviderExecuteResult.SuccessfulScriptExecution_code=code.compile_command(file_contents.decode('utf-8'),filename,'exec')self.interpreter.locals['__file__']=filenameself.interpreter.locals['__name__']='__main__'self.interpreter.execute(_code)returnScriptingProviderExecuteResult.SuccessfulScriptExecution [docs]@abc.abstractmethoddefperform_cancel_script_input(self):fortid,tobjinthreading._active.items():# type: ignoreiftobjisself.interpreter:ifctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),ctypes.py_object(KeyboardInterrupt))!=1:ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),None)break [docs]@abc.abstractmethoddefperform_set_current_binary_view(self,view):self.interpreter.current_view=viewifviewisnotNone:ifself.debugger_imported:self.interpreter.current_dbg=self.DebuggerController(view)else:self.interpreter.current_dbg=None# This is a workaround that allows BN to properly free up resources when the last tab of a binary view is closed.# Without this update, the interpreter local variables will NOT be updated until the user interacts with the# Python console for the next time, which means the relevant resources, e.g., the binary view is not freed until# then.# However, since perform_set_current_binary_view is called every time the user clicks in the UI, we would like# to avoid updating the local variables every time. So the compromise is to only do an explicit update when the# view is None.ifviewisNone:try:self.interpreter.update_locals()except:traceback.print_exc() [docs]@abc.abstractmethoddefperform_set_current_function(self,func):self.interpreter.current_func=func [docs]@abc.abstractmethoddefperform_set_current_basic_block(self,block):self.interpreter.current_block=block [docs]@abc.abstractmethoddefperform_set_current_address(self,addr):self.interpreter.current_addr=addr [docs]@abc.abstractmethoddefperform_set_current_selection(self,begin,end):self.interpreter.current_selection_begin=beginself.interpreter.current_selection_end=end [docs]@abc.abstractmethoddefperform_complete_input(self,text,state):try:self.interpreter.update_locals()except:traceback.print_exc()result=self.interpreter.completer.complete(text,state)ifresultisNone:return""returnresult [docs]classPythonScriptingProvider(ScriptingProvider):name="Python"apiName=f"python{sys.version_info.major}"# Used for plugin compatibility testinginstance_class:TypeHintType[PythonScriptingInstance]=PythonScriptingInstancemagic_variables:Dict[str,'MagicVariable']={}[docs]@dataclasses.dataclassclassMagicVariable:"""Represents an automatically-populated (magic) variable in the python scripting console"""get_value:Callable[[PythonScriptingInstance],Any]"""Function to call, before every time a script is evaluated,to get the value of the variable"""set_value:Optional[Callable[[PythonScriptingInstance,Any,Any],None]]"""(Optional) function to call after a script is evaluated, if the value of thevariable has changed during the course of the script. If None, a warning will beprinted stating that the variable is read-only.Signature: (instance: PythonScriptingInstance, old_value: any, new_value: any) -> None"""depends_on:List[str]"""List of other variables whose values on which this variable's value depends""" @propertydef_python_bin(self)->Optional[str]:python_lib=settings.Settings().get_string("python.interpreter")python_bin_override=settings.Settings().get_string("python.binaryOverride")python_env=self._get_python_environment(using_bundled_python=notpython_lib)python_bin,status=self._get_executable_for_libpython(python_lib,python_bin_override,python_env=python_env)returnpython_bindef_load_module(self,ctx,_repo_path:bytes,_module:bytes,force:bool):repo_path=_repo_path.decode("utf-8")module=_module.decode("utf-8")try:repo=RepositoryManager()[repo_path]plugin=repo[module]ifnotforceandself.apiNamenotinplugin.api:raiseValueError(f"Plugin API name is not{self.name}")ifnotforceandcore.core_platformnotinplugin.install_platforms:raiseValueError(f"Current platform{core.core_platform} isn't in list of valid platforms for this plugin{plugin.install_platforms}")ifnotplugin.installed:plugin.installed=Trueplugin_full_path=str(Path(repo.full_path)/plugin.path)ifrepo.full_pathnotinsys.path:sys.path.append(repo.full_path)ifplugin_full_pathnotinsys.path:sys.path.append(plugin_full_path)ifplugin.subdir:__import__(module+"."+plugin.subdir.replace("/","."))else:__import__(module)returnTrueexceptKeyError:logger.log_error_for_exception(f"Failed to find python plugin:{repo_path}/{module}")exceptImportErrorasie:logger.log_error_for_exception(f"Failed to import python plugin:{repo_path}/{module}:{ie}")exceptbinaryninja.UIPluginInHeadlessError:logger.log_info(f"Ignored python UI plugin:{repo_path}/{module}")returnFalse# This function can only be used to execute commands that return ASCII-only output, otherwise the decoding will faildef_run_args(self,args,env:Optional[Dict]=None):si=Noneifsys.platform=="win32":si=subprocess.STARTUPINFO()si.dwFlags|=subprocess.STARTF_USESHOWWINDOWtry:return(True,subprocess.check_output(args,startupinfo=si,stderr=subprocess.STDOUT,env=env).decode("utf-8"))exceptsubprocess.SubprocessErrorasse:return(False,str(se))def_pip_exists(self,python_bin:str,python_env:Optional[Dict]=None)->bool:returnself._run_args([python_bin,"-c","import pip; pip.__version__"],env=python_env)[0]def_satisfied_dependencies(self,python_bin:str)->Generator[str,None,None]:ifpython_binisNone:returnNonepython_lib=settings.Settings().get_string("python.interpreter")python_env=self._get_python_environment(using_bundled_python=notpython_lib)success,result=self._run_args([python_bin,"-m","pip","freeze"],env=python_env)ifnotsuccess:returnNoneforlineinresult.splitlines():yieldline.split("==",2)[0]def_bin_version(self,python_bin:str,python_env:Optional[Dict]=None):returnself._run_args([str(python_bin),"-c","import sys; sys.stdout.write(f'{sys.version_info.major}.{sys.version_info.minor}')"],env=python_env)[1]def_get_executable_for_libpython(self,python_lib:str,python_bin:str,python_env:Optional[Dict]=None)->Tuple[Optional[str],str]:python_lib_version=f"{sys.version_info.major}.{sys.version_info.minor}"ifpython_binisnotNoneandpython_bin!="":python_bin_version=self._bin_version(python_bin,python_env=python_env)ifpython_lib_version!=python_bin_version:return(None,f"Specified Python Binary Override is the wrong version. Expected:{python_lib_version} got:{python_bin_version}")return(python_bin,"Success")using_bundled_python=notpython_libifsys.platform=="darwin":ifusing_bundled_python:python_bin=Path(binaryninja.get_install_directory()).parent/f"Frameworks/Python.framework/Versions/Current/bin/python3"else:python_bin=str(Path(python_lib).parent/f"bin/python{python_lib_version}")elifsys.platform=="linux":classDl_info(ctypes.Structure):_fields_=[("dli_fname",ctypes.c_char_p),("dli_fbase",ctypes.c_void_p),("dli_sname",ctypes.c_char_p),("dli_saddr",ctypes.c_void_p),]def_linked_libpython():libdl=ctypes.CDLL(find_library("dl"))libdl.dladdr.argtypes=[ctypes.c_void_p,ctypes.POINTER(Dl_info)]libdl.dladdr.restype=ctypes.c_intdlinfo=Dl_info()retcode=libdl.dladdr(ctypes.cast(ctypes.pythonapi.Py_GetVersion,ctypes.c_void_p),ctypes.pointer(dlinfo))ifretcode==0:# means errorreturnNonereturnos.path.realpath(dlinfo.dli_fname.decode())ifusing_bundled_python:python_lib=_linked_libpython()ifpython_libisNone:return(None,"Failed: No python specified. Specify a full python installation in your 'Python Interpreter' and try again")ifpython_lib==os.path.realpath(sys.executable):python_bin=python_libelse:python_path=Path(python_lib)forpathinpython_path.parents:ifpath.namein["lib","lib64"]:breakelse:return(None,f"Failed to find python binary from{python_lib}")python_bin=path.parent/f"bin/python{python_lib_version}"else:ifusing_bundled_python:python_bin=Path(binaryninja.get_install_directory())/"plugins\\python\\python.exe"else:python_bin=Path(python_lib).parent/"python.exe"python_bin_version=self._bin_version(python_bin,python_env=python_env)ifpython_bin_version!=python_lib_version:return(None,f"Failed: Python version not equal{python_bin_version} and{python_lib_version}")return(python_bin,"Success")def_get_python_environment(self,using_bundled_python:bool=False)->Optional[Dict]:ifusing_bundled_pythonandsys.platform=="darwin":return{"PYTHONHOME":Path(binaryninja.get_install_directory()).parent/f"Resources/bundled-python3"}returnNonedef_install_modules(self,ctx,_modules:bytes)->bool:# This callback should not be called directlymodules=_modules.decode("utf-8")iflen(modules.strip())==0:returnTruepython_lib=settings.Settings().get_string("python.interpreter")python_bin_override=settings.Settings().get_string("python.binaryOverride")python_env=self._get_python_environment(using_bundled_python=notpython_lib)python_bin,status=self._get_executable_for_libpython(python_lib,python_bin_override,python_env=python_env)ifpython_binisnotNoneandnotself._pip_exists(str(python_bin),python_env=python_env):logger.log_error(f"Pip not installed for configured python:{python_bin}.\n""Please install pip or switch python versions.")returnFalseifpython_binisNone:logger.log_error(f"Unable to discover python executable required for installing python modules:{status}\n""Please specify a path to a python binary in the 'Python Path Override'")returnFalsepython_bin_version=subprocess.check_output([python_bin,"-c","import sys; sys.stdout.write(f'{sys.version_info.major}.{sys.version_info.minor}')"],env=python_env).decode("utf-8")python_lib_version=f"{sys.version_info.major}.{sys.version_info.minor}"if(python_bin_version!=python_lib_version):logger.log_error(f"Python Binary Setting{python_bin_version} incompatible with python library{python_lib_version}")returnFalseargs:List[str]=[str(python_bin),"-m","pip","--isolated","--disable-pip-version-check"]proxy_settings=settings.Settings().get_string("network.httpsProxy")ifproxy_settings:args.extend(["--proxy",proxy_settings])args.extend(["install","--upgrade","--upgrade-strategy","only-if-needed"])venv=settings.Settings().get_string("python.virtualenv")in_virtual_env='VIRTUAL_ENV'inos.environifvenvisnotNoneandvenv.endswith("site-packages")andPath(venv).is_dir()andnotin_virtual_env:args.extend(["--target",venv])else:user_dir=binaryninja.user_directory()ifuser_dirisNone:raiseException("Unable to find user directory.")site_package_dir=Path(user_dir)/f"python{sys.version_info.major}{sys.version_info.minor}"/"site-packages"site_package_dir.mkdir(parents=True,exist_ok=True)args.extend(["--target",str(site_package_dir)])args.extend(list(filter(len,modules.split("\n"))))logger.log_info(f"Running pip{args}")status,result=self._run_args(args,env=python_env)ifstatus:importlib.invalidate_caches()else:logger.log_error(f"Error while attempting to install requirements{result}")returnstatusdef_module_installed(self,ctx,module:str)->bool:ifself._python_binisNone:returnFalsereturnre.split('>|=|,',module.strip(),1)[0]inself._satisfied_dependencies(self._python_bin)[docs]@classmethoddefregister_magic_variable(cls,name:str,get_value:Callable[[PythonScriptingInstance],Any],set_value:Optional[Callable[[PythonScriptingInstance,Any,Any],None]]=None,depends_on:Optional[List[str]]=None):"""Add a magic variable to all scripting instances created by the scripting provider:param name: Variable name identifier to be used in the interpreter:param get_value: Function to call, before every time a script is evaluated, \ to get the value of the variable:param set_value: (Optional) Function to call after a script is evaluated, if the \ value of the variable has changed during the course of the script. \ If None, a warning will be printed stating that the variable is read-only. \ Signature: \ (instance: PythonScriptingInstance, old_value: any, new_value: any) -> None:param depends_on: List of other variables whose values on which this variable's value depends"""ifdepends_onisNone:depends_on=[]cls.magic_variables[name]=PythonScriptingProvider.MagicVariable(get_value=get_value,set_value=set_value,depends_on=depends_on)forinstinPythonScriptingInstance._registered_instances:inst.interpreter.update_magic_variables() [docs]@classmethoddefunregister_magic_variable(cls,name:str):"""Remove a magic variable by name:param name: Variable name"""delcls.magic_variables[name]forinstinPythonScriptingInstance._registered_instances:inst.interpreter.update_magic_variables() PythonScriptingProvider().register()# Wrap stdin/stdout/stderr for Python scripting provider implementationoriginal_stdin=sys.stdinoriginal_stdout=sys.stdoutoriginal_stderr=sys.stderr[docs]defredirect_stdio():sys.stdin=_PythonScriptingInstanceInput(sys.stdin)sys.stdout=_PythonScriptingInstanceOutput(sys.stdout,False)sys.stderr=_PythonScriptingInstanceOutput(sys.stderr,True)sys.excepthook=sys.__excepthook__ def_get_here(instance:PythonScriptingInstance):returninstance.interpreter.current_addrdef_set_here(instance:PythonScriptingInstance,old_value:Any,new_value:Any):ifinstance.interpreter.active_viewisNone:returnifisinstance(new_value,str):new_value=instance.interpreter.active_view.parse_expression(new_value,instance.interpreter.active_addr)iftype(new_value)isnotint:raiseValueError("Can only replace this variable with an integer")ifnotinstance.interpreter.active_view.file.navigate(instance.interpreter.active_view.file.view,new_value):binaryninja.mainthread.execute_on_main_thread(lambda:instance.interpreter.locals["current_ui_context"].navigateForBinaryView(instance.interpreter.active_view,new_value))PythonScriptingProvider.register_magic_variable("here",_get_here,_set_here,["current_ui_context"])PythonScriptingProvider.register_magic_variable("current_address",_get_here,_set_here,["current_ui_context"])def_get_current_comment(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:returnNoneifinstance.interpreter.active_funcisNone:returninstance.interpreter.active_view.get_comment_at(instance.interpreter.active_addr)elifinstance.interpreter.active_func.get_comment_at(instance.interpreter.active_addr)!='':returninstance.interpreter.active_func.get_comment_at(instance.interpreter.active_addr)else:returninstance.interpreter.active_view.get_comment_at(instance.interpreter.active_addr)def_set_current_comment(instance:PythonScriptingInstance,old_value:Any,new_value:Any):ifinstance.interpreter.active_viewisNone:returnifinstance.interpreter.active_funcisNone:instance.interpreter.active_view.set_comment_at(instance.interpreter.active_addr,new_value)else:ifinstance.interpreter.active_view.get_comment_at(instance.interpreter.active_addr)!='':# Prefer editing active view comment if one existsinstance.interpreter.active_view.set_comment_at(instance.interpreter.active_addr,new_value)else:instance.interpreter.active_func.set_comment_at(instance.interpreter.active_addr,new_value)PythonScriptingProvider.register_magic_variable("current_comment",_get_current_comment,_set_current_comment)def_get_current_raw_offset(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisnotNone:returninstance.interpreter.active_view.get_data_offset_for_address(instance.interpreter.active_addr)else:returnNonedef_set_current_raw_offset(instance:PythonScriptingInstance,old_value:Any,new_value:Any):ifinstance.interpreter.active_viewisNone:returnifisinstance(new_value,str):new_value=instance.interpreter.active_view.parse_expression(new_value,instance.interpreter.active_addr)iftype(new_value)isnotint:raiseValueError("Can only replace this variable with an integer")addr=instance.interpreter.active_view.get_address_for_data_offset(new_value)ifaddrisnotNone:ifnotinstance.interpreter.active_view.file.navigate(instance.interpreter.active_view.file.view,addr):binaryninja.mainthread.execute_on_main_thread(lambda:instance.interpreter.locals["current_ui_context"].navigateForBinaryView(instance.interpreter.active_view,new_value))PythonScriptingProvider.register_magic_variable("current_raw_offset",_get_current_raw_offset,_set_current_raw_offset,["current_ui_context"])def_get_current_selection(instance:PythonScriptingInstance):returninstance.interpreter.active_selection_begin,instance.interpreter.active_selection_enddef_set_current_selection(instance:PythonScriptingInstance,old_value:Any,new_value:Any):ifnotinstance.interpreter.locals["current_ui_view"]:returnif(notisinstance(new_value,list))and \(notisinstance(new_value,tuple)):returniflen(new_value)!=2:raiseValueError("Current selection needs to be a list or tuple of two items")new_value=[new_value[0],new_value[1]]ifisinstance(new_value[0],str):new_value[0]=instance.interpreter.active_view.parse_expression(new_value[0],instance.interpreter.active_addr)ifisinstance(new_value[1],str):new_value[1]=instance.interpreter.active_view.parse_expression(new_value[1],instance.interpreter.active_addr)ifnew_value[0]!=instance.interpreter.active_selection_beginor \new_value[1]!=instance.interpreter.active_selection_end:new_selection=(new_value[0],new_value[1])binaryninja.mainthread.execute_on_main_thread(lambda:instance.interpreter.locals["current_ui_view"].setSelectionOffsets(new_selection))PythonScriptingProvider.register_magic_variable("current_selection",_get_current_selection,_set_current_selection,["current_ui_view"])PythonScriptingProvider.register_magic_variable("current_thread",lambdainstance:instance.interpreter.interpreter)def_get_current_project(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisnotNone:returninstance.interpreter.active_view.projectifinstance.interpreter.locals["current_ui_context"]isnotNone:returninstance.interpreter.locals["current_ui_context"].getProject()returnNonePythonScriptingProvider.register_magic_variable("current_project",_get_current_project,depends_on=["current_ui_context","current_view"],)PythonScriptingProvider.register_magic_variable("current_view",lambdainstance:instance.interpreter.active_view)PythonScriptingProvider.register_magic_variable("bv",lambdainstance:instance.interpreter.active_view)PythonScriptingProvider.register_magic_variable("current_function",lambdainstance:instance.interpreter.active_func)PythonScriptingProvider.register_magic_variable("current_basic_block",lambdainstance:instance.interpreter.active_block)# todo: this is the debugger's responsibilityPythonScriptingProvider.register_magic_variable("dbg",lambdainstance:instance.interpreter.active_dbg)def_get_current_llil(instance:PythonScriptingInstance):ifinstance.interpreter.active_funcisNone:returnNonereturninstance.interpreter.active_func.llil_if_availablePythonScriptingProvider.register_magic_variable("current_llil",_get_current_llil)def_get_current_lifted_il(instance:PythonScriptingInstance):ifinstance.interpreter.active_funcisNone:returnNonereturninstance.interpreter.active_func.lifted_il_if_availablePythonScriptingProvider.register_magic_variable("current_lifted_il",_get_current_lifted_il)def_get_current_llil_ssa(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_llil"]isNone:returnNonereturninstance.interpreter.locals["current_llil"].ssa_formPythonScriptingProvider.register_magic_variable("current_llil_ssa",_get_current_llil_ssa,depends_on=["current_llil"])def_get_current_mapped_mlil(instance:PythonScriptingInstance):ifinstance.interpreter.active_funcisNone:returnNonereturninstance.interpreter.active_func.mmlil_if_availablePythonScriptingProvider.register_magic_variable("current_mapped_mlil",_get_current_mapped_mlil)def_get_current_mapped_mlil_ssa(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_mapped_mlil"]isNone:returnNonereturninstance.interpreter.locals["current_mapped_mlil"].ssa_formPythonScriptingProvider.register_magic_variable("current_mapped_mlil_ssa",_get_current_mapped_mlil_ssa,depends_on=["current_mapped_mlil"])def_get_current_mlil(instance:PythonScriptingInstance):ifinstance.interpreter.active_funcisNone:returnNonereturninstance.interpreter.active_func.mlil_if_availablePythonScriptingProvider.register_magic_variable("current_mlil",_get_current_mlil)def_get_current_mlil_ssa(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_mlil"]isNone:returnNonereturninstance.interpreter.locals["current_mlil"].ssa_formPythonScriptingProvider.register_magic_variable("current_mlil_ssa",_get_current_mlil_ssa,depends_on=["current_mlil"])def_get_current_hlil(instance:PythonScriptingInstance):ifinstance.interpreter.active_funcisNone:returnNonereturninstance.interpreter.active_func.hlil_if_availablePythonScriptingProvider.register_magic_variable("current_hlil",_get_current_hlil)def_get_current_hlil_ssa(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_hlil"]isNone:returnNonereturninstance.interpreter.locals["current_hlil"].ssa_formPythonScriptingProvider.register_magic_variable("current_hlil_ssa",_get_current_hlil_ssa,depends_on=["current_hlil"])def_get_current_data_var(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:returnNonereturninstance.interpreter.active_view.get_data_var_at(instance.interpreter.active_addr)PythonScriptingProvider.register_magic_variable("current_data_var",_get_current_data_var)def_get_current_symbol(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:returnNonereturninstance.interpreter.active_view.get_symbol_at(instance.interpreter.active_addr)PythonScriptingProvider.register_magic_variable("current_symbol",_get_current_symbol)def_get_current_symbols(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:return[]returninstance.interpreter.active_view.get_symbols(instance.interpreter.active_addr,1)PythonScriptingProvider.register_magic_variable("current_symbols",_get_current_symbols)def_get_current_segment(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:returnNonereturninstance.interpreter.active_view.get_segment_at(instance.interpreter.active_addr)PythonScriptingProvider.register_magic_variable("current_segment",_get_current_segment)def_get_current_sections(instance:PythonScriptingInstance):ifinstance.interpreter.active_viewisNone:return[]returninstance.interpreter.active_view.get_sections_at(instance.interpreter.active_addr)PythonScriptingProvider.register_magic_variable("current_sections",_get_current_sections)def_get_current_ui_context(instance:PythonScriptingInstance):ifbinaryninja.core_ui_enabled():try:frombinaryninjauiimportUIContextreturnUIContext.activeContext()exceptImportError:passreturnNonePythonScriptingProvider.register_magic_variable("current_ui_context",_get_current_ui_context)def_get_current_ui_action_handler(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_context"]isnotNone:returninstance.interpreter.locals["current_ui_context"].getCurrentActionHandler()returnNonePythonScriptingProvider.register_magic_variable("current_ui_action_handler",_get_current_ui_action_handler,depends_on=["current_ui_context"])def_get_current_ui_view_frame(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_context"]isnotNone:returninstance.interpreter.locals["current_ui_context"].getCurrentViewFrame()returnNonePythonScriptingProvider.register_magic_variable("current_ui_view_frame",_get_current_ui_view_frame,depends_on=["current_ui_context"])def_get_current_ui_view(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_context"]isnotNone:returninstance.interpreter.locals["current_ui_context"].getCurrentView()returnNonePythonScriptingProvider.register_magic_variable("current_ui_view",_get_current_ui_view,depends_on=["current_ui_context"])def_get_current_ui_view_location(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_view_frame"]isnotNone:returninstance.interpreter.locals["current_ui_view_frame"].getViewLocation()returnNonePythonScriptingProvider.register_magic_variable("current_ui_view_location",_get_current_ui_view_location,depends_on=["current_ui_view_frame"])def_get_current_ui_action_context(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_view"]isnotNone:returninstance.interpreter.locals["current_ui_view"].actionContext()ifinstance.interpreter.locals["current_ui_action_handler"]isnotNone:returninstance.interpreter.locals["current_ui_action_handler"].actionContext()returnNonePythonScriptingProvider.register_magic_variable("current_ui_action_context",_get_current_ui_action_context,depends_on=["current_ui_view","current_ui_action_handler"])def_get_current_ui_token_state(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_action_context"]isnotNone:returninstance.interpreter.locals["current_ui_action_context"].tokenreturnNonePythonScriptingProvider.register_magic_variable("current_ui_token_state",_get_current_ui_token_state,depends_on=["current_ui_action_context"])def_get_current_token(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_token_state"]isnotNone:ifinstance.interpreter.locals["current_ui_token_state"].tokenIndex!=0xffffffff:# BN_INVALID_OPERANDreturninstance.interpreter.locals["current_ui_token_state"].tokenreturnNonePythonScriptingProvider.register_magic_variable("current_token",_get_current_token,depends_on=["current_ui_token_state"])def_get_current_variable(instance:PythonScriptingInstance):frombinaryninjaimportVariableifinstance.interpreter.locals["current_ui_token_state"]isnotNone:ifinstance.interpreter.locals["current_ui_token_state"].localVarValid:var=instance.interpreter.locals["current_ui_token_state"].localVarifvarisnotNoneandinstance.interpreter.active_func:returnVariable.from_core_variable(instance.interpreter.active_func,var)returnNonePythonScriptingProvider.register_magic_variable("current_variable",_get_current_variable,depends_on=["current_ui_token_state"])def_get_current_il_index(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_ui_view_location"]isnotNone:returninstance.interpreter.locals["current_ui_view_location"].getInstrIndex()returnNonePythonScriptingProvider.register_magic_variable("current_il_index",_get_current_il_index,depends_on=["current_ui_view_location"])def_get_current_il_expr_index(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_token"]isnotNone:returninstance.interpreter.locals["current_token"].il_expr_indexreturnNonePythonScriptingProvider.register_magic_variable("current_il_expr_index",_get_current_il_expr_index,depends_on=["current_token"])def_get_current_il_function(instance:PythonScriptingInstance):frombinaryninjaimportFunctionGraphTypeifinstance.interpreter.locals["current_ui_view_location"]isnotNone:ilType=instance.interpreter.locals["current_ui_view_location"].getILViewType()ifilType.view_type==FunctionGraphType.LowLevelILFunctionGraph:returninstance.interpreter.locals["current_llil"]elifilType.view_type==FunctionGraphType.LiftedILFunctionGraph:returninstance.interpreter.locals["current_lifted_il"]elifilType.view_type==FunctionGraphType.LowLevelILSSAFormFunctionGraph:returninstance.interpreter.locals["current_llil_ssa"]elifilType.view_type==FunctionGraphType.MappedMediumLevelILFunctionGraph:returninstance.interpreter.locals["current_mapped_mlil"]elifilType.view_type==FunctionGraphType.MappedMediumLevelILSSAFormFunctionGraph:returninstance.interpreter.locals["current_mapped_mlil_ssa"]elifilType.view_type==FunctionGraphType.MediumLevelILFunctionGraph:returninstance.interpreter.locals["current_mlil"]elifilType.view_type==FunctionGraphType.MediumLevelILSSAFormFunctionGraph:returninstance.interpreter.locals["current_mlil_ssa"]elifilType.view_type==FunctionGraphType.HighLevelILFunctionGraphorilType.view_type==FunctionGraphType.HighLevelLanguageRepresentationFunctionGraph:returninstance.interpreter.locals["current_hlil"]elifilType.view_type==FunctionGraphType.HighLevelILSSAFormFunctionGraph:returninstance.interpreter.locals["current_hlil_ssa"]returnNonePythonScriptingProvider.register_magic_variable("current_il_function",_get_current_il_function,depends_on=["current_ui_view_location","current_llil","current_lifted_il","current_llil_ssa","current_mapped_mlil","current_mapped_mlil_ssa","current_mlil","current_mlil_ssa","current_hlil","current_hlil_ssa",])def_get_current_il_instruction(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_il_function"]isnotNone \andinstance.interpreter.locals["current_il_index"]isnotNone:returninstance.interpreter.locals["current_il_function"][instance.interpreter.locals["current_il_index"]]returnNonePythonScriptingProvider.register_magic_variable("current_il_instruction",_get_current_il_instruction,depends_on=["current_il_index","current_il_function"])def_get_current_il_expr(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_il_function"]isnotNone \andinstance.interpreter.locals["current_il_expr_index"]isnotNone:returninstance.interpreter.locals["current_il_function"].get_expr(instance.interpreter.locals["current_il_expr_index"])returnNonePythonScriptingProvider.register_magic_variable("current_il_expr",_get_current_il_expr,depends_on=["current_il_expr_index","current_il_function"])def_get_current_il_basic_block(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_il_instruction"]isnotNone:returninstance.interpreter.locals["current_il_instruction"].il_basic_blockreturnNonePythonScriptingProvider.register_magic_variable("current_il_basic_block",_get_current_il_basic_block,depends_on=["current_il_instruction"])def_get_current_il_instructions(instance:PythonScriptingInstance):ifinstance.interpreter.locals["current_il_index"]isnotNone \andinstance.interpreter.locals["current_il_function"]isnotNone \andinstance.interpreter.locals["current_ui_view"]isnotNone:start_index=instance.interpreter.locals["current_ui_view"].getSelectionStartILInstructionIndex()current_index=instance.interpreter.locals["current_il_index"]il_function=instance.interpreter.locals["current_il_function"]invalid_il_index=0xffffffffffffffffifinvalid_il_indexnotin(current_index,start_index):il_start=min(current_index,start_index)il_end=max(current_index,start_index)return(il_function[i]foriinrange(il_start,il_end+1))returnNonePythonScriptingProvider.register_magic_variable("current_il_instructions",_get_current_il_instructions,depends_on=["current_il_index","current_il_function","current_ui_view"])