def _analyze(self, methods_it): ''' Analyze the assembler file. Parameters ---------- methods_it: iterator<dict<int, string>> ''' start = time.time() AsmAnalyzerBase.__check_dont_skip_exception( setting_for_key(SETTINGS_DONT_SKIP_EXCEPTION)) output_filepath = setting_for_key(SETTINGS_OUTPUT_FILEPATH) graph_filepath = setting_for_key(SETTINGS_GRAPH_FILEPATH) if output_filepath: clilog.info('writing messages to %s' % abspath(output_filepath)) if graph_filepath is not None: clilog.info('writing graph to %s\n' % abspath(graph_filepath)) cnt_filtered_messages = cnt_total_messages = 0 # base classes cannot be resolved if not self.superclass_dict: log.critical( 'No information about superclasses given/read!\n Messages to super cannot be resolved! %s will be assumed as superclass!' % ObjcClass.nsobject) # create cpu cpu = None if is_x86(): cpu = Cpu_x86(self.superclass_dict) elif is_x86_64(): cpu = Cpu_x86_64(self.superclass_dict) elif is_arm(): cpu = Cpu_arm(self.superclass_dict) try: for method_dict in methods_it: try: (cnt1, cnt2) = self.__analyze_inner(cpu, method_dict) cnt_total_messages += cnt1 cnt_filtered_messages += cnt2 except (CpuException, RuntimeError) as e: log.exception(e) finally: # reset cpu to read next method implementation cpu.reset() except Exception: raise finally: if self.filtering_enabled(): self.__write_filter_results() # close file if self.output_file is not None: self.output_file.flush() self.output_file.close() GraphUtil.write_gexf(self.graph, graph_filepath) # print infos self._print_info(start, cnt_filtered_messages, cnt_total_messages)
def __init__(self, superclass_dict=None): if superclass_dict is None: superclass_dict = {} self._superclass_dict = superclass_dict output_file = None output_filepath = setting_for_key(SETTINGS_OUTPUT_FILEPATH) if output_filepath: output_file = open(output_filepath, 'w') self._output_file = output_file self._graph = Graph() # do not forget to set `MethodCall` later filters = setting_for_key(SETTINGS_FILTERS) self._security_analyzer = SecurityAnalyzer(methodcall=None, filters=filters)
def analyze(self): ''' Analyze the assembler file. ''' methods_it = None selected_method_only = setting_for_key(SETTINGS_READ_SINGLE_PROCEDURE) if selected_method_only: methods_it = AsmReader.single_method_it(self.asmline_list) else: read_all_methods = setting_for_key(SETTINGS_READ_ALL_METHODS) self.log_n_read_superclasses() section_it = AsmReader.sections_it(self.asmline_list, [SEGMENT_TEXT]) methods_it = AsmReader.methods_it( section_it, read_all_procedures=read_all_methods) self._analyze(methods_it)
def create_gephi_attr_dicts(self, asm_lines, filtered_methodcall = None): ''' Construct the attribute dictionary describing the graph style. Use the created dictionaries with the `add_to_graph` method. The attributes are: Calling Method: assembler code the method calls (filtered or not) Method: line number in the asm file address in the asm file surrounding lines Parameters ---------- asm_lines: string the assembler method as string filtered_methodcall: MethodCall, optional (default is None) the filtered `MethodCall` Returns ------- methodcall_sender_attr_dict: dict methodcall_calls_attr_list_dict: dict ''' method_lines_list = [str(methodcallitem) for methodcallitem in self.calls] if filtered_methodcall is None: filtered_methodcall = self # construct calls attribute dictionary methodcall_calls_attr_list_dict = [] cnt_surrounding_lines = setting_for_key(SETTINGS_CNT_SURROUNDING_LINES) if cnt_surrounding_lines >= 0: for i, methodcallitem in enumerate(filtered_methodcall.calls): # construct leading and trailing lines # index of the current line (filtered `MethodCall`) in the list of method lines current_line = str(filtered_methodcall.calls[i].call) linenr = methodcallitem.linenr idx_line = self.idx_methodcallitem(linenr) # idx_line = method_lines_list.index(current_line) lines_before, lines_after = Util.surrounding_elements_from_list(method_lines_list, idx_line, cnt_surrounding_lines) surrounding_lines = NodeAttributes.NPATTERN_SURROUND_LINES % (Util.strlist_to_str(lines_before), current_line, Util.strlist_to_str(lines_after)) methodcall_attr_dict = {NodeAttributes.NATTR_METHOD_SURROUNDING_LINES % cnt_surrounding_lines : surrounding_lines} methodcall_attr_dict.update(methodcallitem.get_gexf_viz_attr_dict()) methodcall_calls_attr_list_dict.append(methodcall_attr_dict) # add method signature to list of method lines method_lines_list.insert(0, filtered_methodcall.format_head() + ":\n") # construct sender attribute dictionary method_lines = Util.strlist_to_str(method_lines_list) methodcall_sender_attr_dict = {NodeAttributes.NATTR_METHOD : method_lines, NodeAttributes.NATTR_ASM_CODE : asm_lines} return (methodcall_sender_attr_dict, methodcall_calls_attr_list_dict)
def filter_method_call(self, function): has_format_string = util.mc_has_format_string(function) # only check for exploitable sql statement if the argument of the c function are available if setting_for_key(SETTINGS_C_FUNC_HEURISTIC): is_sqlite_func = util.mc_c_function_has_any_name( function, ['sqlite3_prepare'], search_substring=True) return is_sqlite_func and has_format_string # check for any sqlite3 call is_sqlite_func = util.mc_c_function_has_any_name(function, ['sqlite3'], search_substring=True) return is_sqlite_func
def __init__(self, assignment_matching_system, parse_util, _register_class, superclass_dict=None, objc_runtime=None): self.__assignment_matching_system = assignment_matching_system self._parse_util = parse_util self._register_class = _register_class self._memory = Memory(self) # use standard objective-c runtime if nothing else given if objc_runtime is None: objc_runtime = ObjectiveCRuntime(self, superclass_dict) self._objc_runtime = objc_runtime self._c_func_heuristic = setting_for_key(SETTINGS_C_FUNC_HEURISTIC) self.__init_resetable_stuff()
def __init__(self, asmline_list, superclass_dict=None): AsmAnalyzerBase.__init__(self, superclass_dict) self.__asmline_list = asmline_list selected_method_only = setting_for_key(SETTINGS_READ_SINGLE_PROCEDURE) if selected_method_only: clilog.info('Only analyzing the selected lines!')
def __analyze_inner(self, cpu, method_dict): cnt_filtered_messages = cnt_total_messages = 0 dont_skip_exception = setting_for_key(SETTINGS_DONT_SKIP_EXCEPTION) hopper_annotater = hopanno hopanno.reset() for linenr, line in sorted(method_dict.items()): try: cpu.read_line(line, linenr) if hopper_annotater is not None and hopper_annotater.cur_meth_impl_start is None and cpu.address is not None: hopper_annotater.cur_meth_impl_start = cpu.address except (CpuException, RuntimeError) as e: # annotate exception hopanno.annotate(cpu.address, (HOPANNO_EXCEPTION_STR + (' <- %s: %s ...' % (e.__class__.__name__, str(e))) )[:HOPPER_EXCEPTION_LENGTH]) log.exception(e) if not dont_skip_exception: raise methodcall = cpu.get_method_call() cnt_total_messages += len(methodcall.calls) sa = self.security_analyzer sa.set_methodcall(methodcall) filtered_methodcall = methodcall # build a list of method lines if self.filtering_enabled(): # apply filters # do this after building the list of method lines, # because the lines before and after refer to the unfiltered lines filtered_methodcall = sa.apply_filters() # method as assembler code (string) lines_str_list = list(Util.sorted_dict_values_it(method_dict)) asm_lines = Util.strlist_to_str(lines_str_list) # create attribute dictionaries methodcall_sender_attr_dict, methodcall_calls_attr_list_dict = methodcall.create_gephi_attr_dicts( asm_lines, filtered_methodcall) # add to graph if self.filtering_enabled(): sa.add_to_graph(self.graph, methodcall_sender_attr_dict, methodcall_calls_attr_list_dict, sender_methodcall_edge_attr_dict=None) else: methodcall_sender_attr_dict.update(GraphUtil.viz_dict(size=50.0)) methodcall.add_to_graph(self.graph, methodcall_sender_attr_dict, methodcall_calls_attr_list_dict, sender_methodcall_edge_attr_dict=None) cnt_filtered_messages += len(filtered_methodcall.calls) # write `MethodCall` to file if not self.filtering_enabled(): self.__write_methodcall(filtered_methodcall) # annotate hopper if hopper_annotater is not None: hopper_annotater.annotate_from_methodcall(filtered_methodcall) hopper_annotater.reset() return (cnt_total_messages, cnt_filtered_messages)
def __init__(self, cpu, parse_util): self._cpu = cpu self._parse_util = parse_util self.__init_defaults() self.clear_usage_since_last_call() self._c_func_heuristic = setting_for_key(SETTINGS_C_FUNC_HEURISTIC)