def __check_dont_skip_exception(dont_skip_exception): ''' Check if option is turned on and warn user ''' if dont_skip_exception: clilog.info('''"dont_skip_exception" is turned on. This might lead to wrong results! If any exception occurs while analyzing a method, the process will be continued!''' )
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 log_n_read_superclasses(self): ''' Read and log the superclass information ''' # reading superclasses is only supported for x86_64 if is_x86_64(): clilog.info('reading superclasses') self.superclass_dict = self.read_superclasses() log_info( Util.format_dict_as_table(self.superclass_dict, 'subclass', 'base class')) clilog.info('')
def _read_superclasses(self, section_it): ''' Helper method for `read_superclasses`. Parameters ---------- section_it: iterator<tuple<int, string>> iterator over the sections where the superclass infos are stored ''' segments = Segments.SEGMENTS_SUPERCLASS_INFOS clilog.info('reading from segments %s' % segments) superclazz_dict = AsmAnalyzerBase.__read_superclasses_from_sections( section_it) return superclazz_dict
def _print_info(self, start, cnt_filtered_messages, cnt_total_messages): ''' Print some statistics after the file has been analyzed ''' duration = time.time() - start clilog.info("\nfiltered function calls: %d" % cnt_filtered_messages) clilog.info("total number of function calls read: %d" % cnt_total_messages) clilog.info('took: %dm, %fs' % (duration / 60, duration % 60)) clilog.info('done')
def __load_filters(filtername_list, use_all_std_filters, arch): ''' Load all standard filters as well as the user supplied ones. They are assumed to be in the directory where the `SecurityFilter` class is located. Parameters ---------- filtername_list: list<str> list of filter names use_all_std_filters: boolean load all standard filters arch_str: string (see `Archs`) architecture Returns ------- installed_filters: list<SecurityFilter> all loaded filters [] if no filter has been loaded ''' flist = [] if filtername_list: flist = [] for f in filtername_list: base_fqn = SecurityFilter.__package__ f = '%s.%s' % (base_fqn, Util.remove_py_extension(f)) try: clazz = Util.class_for_fqn_mod_eq_class(f) fclass = clazz() flist.append(fclass) except (ImportError, ModuleNotSameClassNameException) as e: raise CLIError(str(e)), None, sys.exc_info()[2] if use_all_std_filters: # use all standard filters # do not take duplicates flist = list( set( map(lambda f: f(), SecurityFilters.security_filters(arch)) + flist)) fnames = map(lambda f: f.name, flist) if not fnames: clilog.info('no filters enabled') else: clilog.info('installed filters: %s' % ', '.join(fnames)) return flist
def run_hopper(asmfile_iterator, superclass_dict=None): ''' Use this method to run VizAsm from Hopper. Parameters ---------- asmfile_iterator: iterator<tuple<int, string>> iterator over the lines superclass_dict: dict<ObjcClass, ObjcClass>, optional (default is {}) a dictionary holding the base classes as values ''' # run program asm_ana = AsmAnalyzerHopper(asmfile_iterator, superclass_dict=superclass_dict) clilog.info( 'Hopper reads the whole asm file into memory first and freezes while its doing this. So do not wonder!' ) asm_ana.analyze()
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 main(argv=None): # IGNORE:C0111 '''Command line options.''' if argv is None: argv = sys.argv else: sys.argv.extend(argv) program_version = "v%s" % __version__ program_build_date = str(__updated__) program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date) program_license = ''' Copyright 2013 Nils Schmidt This file is part of VizAsm. VizAsm is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. VizAsm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with VizAsm. If not, see <http://www.gnu.org/licenses/>. ''' try: # Setup argument parser action_parser = __create_action_parser() action_args, _ = action_parser.parse_known_args() # None value indicates to list filters but real value is arch list_filters_arch = action_args.list_filters if action_args.list_filters is not None: print SecurityFilters.format_available_filters(list_filters_arch) else: parser = __create_argument_parser(program_license, program_version_message) # process arguments args = parser.parse_args() arch_str = args.arch filters = init(arch_str, args.filters, args.all_filters, args.verbosity, args.quiet, args.graph, args.vlog, parser) # store settings asmfile = args.asmfile SETTINGS = { SETTINGS_ASM_FILEPATH: asmfile, SETTINGS_OUTPUT_FILEPATH: args.output, SETTINGS_GRAPH_FILEPATH: args.graph, SETTINGS_ARCHITECTURE: arch_str, SETTINGS_C_FUNC_HEURISTIC: args.c_func_heuristic, SETTINGS_CNT_SURROUNDING_LINES: args.surrounding_lines, SETTINGS_FILTERS: filters, SETTINGS_READ_ALL_METHODS: args.read_all_methods, SETTINGS_READ_SINGLE_PROCEDURE: args.read_single_procedure, SETTINGS_DONT_SKIP_EXCEPTION: args.dont_skip_exception } set_defaul_settings(SETTINGS) if DEBUG: print Util.pretty_format_dict(SETTINGS) # run program clilog.info('architecture: %s' % arch_str) clilog.info('analyzing file %s ...\n' % asmfile) asm_ana = AsmAnalyzerCli() asm_ana.analyze() return 0 except KeyboardInterrupt: ### handle keyboard interrupt ### return 0 except CLIError as e: clilog.exception(e) except Exception, e: log.exception(e) clilog.exception(e) return 2
def _read_meth_impl(self, asmline): ''' Read a line like e.g. "methImpl_AppDelegate_applicationDidFinishLaunching_" and detect the current class (AppDelegate) as well as the current method (applicationDidFinishLaunching_) If the `Cpu` does not fetch all of its arguments from stack, self and _cmd will be set to the `Register`s defined by `CallingConventionsInterface`. Otherwise implement `store_self_cmd_for_stack_fetching_cpu` in your `Cpu`. Raises ------ CpuCouldNotGetSelfref raised if the self reference could not be detected SelectorOverloadedException raised if the selector has more arguments than it needs SelectorUnderloadedException raised if the selector has less arguments than it needs ''' method_implementation, match = self.parse_util.parse_any_method_implementation( asmline) is_meth_impl, is_own_c_method_def, is_c_method, is_category = method_implementation method_impl = None if any([is_meth_impl, is_category]): method_impl = match selector = match.fst_selector() objc_class = match.msg_receiver if not self.fetches_all_arguments_from_stack(): selfref_reg = self.destination_register() if selfref_reg is not None: # store class for self reference self.set_selfref_reg_value(objc_class) else: raise CpuCouldNotGetSelfref( self, selfref_reg, '%s.%s' % (objc_class, selector)) else: # set self and _cmd for cpu fetching its args from stack self.objc_runtime.store_self_cmd_for_stack_fetching_cpu( objc_class, selector) self.objc_runtime.create_and_store_method_selector_arguments( selector) # set method to use it in _try_log_reading_meth_impl self.method = method_impl # log method self._try_log_reading_meth_impl(selector) self.set_method_selector_reg_value(selector) elif is_c_method or is_own_c_method_def: log.debug('reading method: %s', match) method_impl = match self.create_and_store_c_func_arguments(method_impl) if any(method_implementation): clilog.info('reading method: %s', method_impl) # set method and sender for `MethodCall` self.method = method_impl self.method_call.sender = method_impl