def init(self): self.arch = Architecture['EVM'] self.platform = Architecture['EVM'].standalone_platform self.max_function_size_for_analysis = 0 file_size = len(self.raw) # Find swarm hashes and make them data evm_bytes = self.raw.read(0, file_size) # code is everything that isn't a swarm hash code = IntervalSet([Interval(0, file_size)]) log_debug('Finding swarm hashes') swarm_hashes = self.find_swarm_hashes(evm_bytes) for start, sz in swarm_hashes: self.add_auto_segment( start, sz, start, sz, (SegmentFlag.SegmentContainsData | SegmentFlag.SegmentDenyExecute | SegmentFlag.SegmentReadable | SegmentFlag.SegmentDenyWrite)) code -= IntervalSet([Interval(start, start + sz)]) for interval in code: if isinstance(interval, int): continue self.add_auto_segment( interval.lower_bound, interval.upper_bound, interval.lower_bound, interval.upper_bound, (SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)) log_debug('Building CFG with evm_cfg_builder') cfg = CFG(evm_bytes, remove_metadata=False) log_debug('Finished building CFG with evm_cfg_builder') Function.set_default_session_data('cfg', cfg) log_debug("registering VsaNotification") self.register_notification(VsaNotification()) log_debug("specifiying entry point and functions") self.add_entry_point(0) for function in cfg.functions: function_start = (function._start_addr + 1 if function._start_addr != 0 else 0) self.define_auto_symbol( Symbol(SymbolType.FunctionSymbol, function_start, function.name)) self.add_function(function_start) # disable linear sweep Settings().set_bool('analysis.linearSweep.autorun', False, view=self, scope=SettingsScope.SettingsUserScope) return True
def _translate_parameter(self, param: Parameter, binja_function: bn.Function, locals: VariableSet): num_resolved = 0 for loc in param.locations: # Resolve the location to a MLIL variable. binja_var, preexists = locals.add(param.name, loc) if binja_var is None: continue if preexists: continue if isinstance(binja_var, bn.DataVariable): continue num_resolved += 1 binja_type = self._construct_binja_type(param.type, as_specifier=True) # Set the name and type. new_name = param.name if param.name else binja_var.name if binja_var.source_type == bn.VariableSourceType.StackVariableSourceType: # self._log.debug(f'stack user var: storage {binja_var.storage}, name {new_name}') binja_function.create_user_stack_var(binja_var.storage, binja_type, new_name) else: # self._log.debug(str(binja_var)+' '+str(binja_type)+' '+new_name) binja_function.create_user_var(binja_var, binja_type, new_name) if binja_var.name != new_name: binja_var.name = new_name if num_resolved == 0: # Don't report errors translating the functions of inlined subroutines. if not isinstance(param.function.owner, Function): issues = [] for loc in param.locations: assert (loc.type == LocationType.STATIC_LOCAL) # was the specified location actually in this subroutine? if loc.begin != 0 and binja_function in self._binary_view.get_functions_containing( loc.begin): issues.append(loc) if issues: self.statistics['num_parameters_unresolved'] += 1 self._log.debug( f'In {binja_function.symbol.short_name}(): unable to resolve parameter ("{param.name}")' ) for loc in param.locations: self._log.debug( f' (0x{loc.begin:08x}, 0x{loc.end:08x}, {loc.expr})' ) else: if len(param.locations) > 0: self.statistics['num_parameters_other'] += 1 else: self.statistics['num_parameters_resolved'] += 1
def _translate_function_type(self, function: Function, binja_function: bn.Function): # Memoize if function.has_attribute('function_type'): function_type = function.get_attribute('function_type') if function_type != binja_function.function_type: binja_function.function_type = function_type return try: locals = VariableSet(binja_function, self._log) function_type = self._create_function_type(function, binja_function, locals) if function_type is not None: binja_function.function_type = function_type except: self._log.warning(f'while creating function type', exc_info=sys.exc_info())
def _translate_function_type(self, function: Function, binja_function: bn.Function): try: local_vars = LocationIndex(binja_function, None, self._log) function_type = self._create_function_type(function, binja_function, local_vars) if function_type is not None: binja_function.function_type = function_type except Exception: self._log.warning('while creating function type', exc_info=sys.exc_info())
def _is_call_site(self, func: bn.Function, ea: int) -> bool: inst_il = func.get_low_level_il_at(ea) if is_function_call(self._bv, inst_il): return True return False
def _translate_local_variable(self, var: LocalVariable, binja_function: bn.Function, locals: VariableSet): num_resolved = 0 num_preexists = 0 for loc in var.locations: # Resolve the location to a MLIL variable. binja_var, preexists = locals.add(var.name, loc) if binja_var is None: continue if preexists: num_preexists += 1 continue if isinstance(binja_var, bn.DataVariable): # A static (local scope) variable. binja_type = self._construct_binja_type(var.type, as_specifier=True) # Set the name of the symbol. symbol: bn.Symbol = self._binary_view.get_symbol_at( binja_var.address) if symbol is None or symbol.short_name != var.name: name = '::'.join(var.name) if isinstance( var.name, tuple) else var.name self._binary_view.define_user_symbol( bn.Symbol(bn.SymbolType.DataSymbol, binja_var.address, name)) num_resolved += 1 continue num_resolved += 1 binja_type = self._construct_binja_type(var.type, as_specifier=True) # Coerce to a reference type, as needed if (binja_var.source_type == bn.VariableSourceType.RegisterVariableSourceType and var.type.composite_type is not None and var.type.byte_size is not None and var.type.byte_size > self._binary_view.arch.address_size): binja_type = bn.Type.pointer( self._binary_view.arch, binja_type, ref_type=bn.ReferenceType.ReferenceReferenceType) self._log.debug( f'in {binja_function.symbol.short_name}, coercing to a reference: {binja_type}' ) # Then set the name and type. new_name = var.name if var.name is not None else binja_var.name if binja_var.source_type == bn.VariableSourceType.StackVariableSourceType: binja_function.create_user_stack_var(binja_var.storage, binja_type, new_name) else: # self._log.debug(f'Creating user variable {binja_var} with name {new_name}') binja_function.create_user_var(binja_var, binja_type, new_name) binja_var.name = var.name binja_var.type = binja_type if num_resolved == 0: issues = [] for loc in var.locations: assert (loc.type == LocationType.STATIC_LOCAL) if loc.begin != 0 and binja_function in self._binary_view.get_functions_containing( loc.begin): issues.append(loc) if issues: self.statistics['num_variables_unresolved'] += 1 self._log.debug( f'In {binja_function.symbol.short_name}()@{binja_function.start:x}: unable to resolve variable ("{var.name}"), # of locations already assigned = {num_preexists}' ) for loc in issues: self._log.debug( f' (0x{loc.begin:08x}, 0x{loc.end:08x}, {loc.expr})' ) else: if len(var.locations) > 0: self.statistics['num_variables_other'] += 1 else: self.statistics['num_variables_resolved'] += 1
def return_and_reanalyze(function: Function, result=None): function.reanalyze() return result