Exemplo n.º 1
0
 def _msgsend_from_selector(self, selector, destination):
     ''' Create a MsgSend and store it in the `MethodCall`.
     
     Parameters
     ----------
     selector: Selector
     destination: 
         to which object to send the message
     
     Raises
     ------
     ObjcRuntimeCouldNotReadMsgSendException
         if the msgSend could not be read
         
     Returns
     -------
     MsgSend
         the created `MsgSend`
     '''
     cpu = self.cpu
     try:
         selector.fill_from_cpu(cpu)
     except (SelectorOverloadedException,
             SelectorUnderloadedException) as e:
         log.exception(e)
     msg_send = self.msg_send_from_destination(destination, selector)
     if msg_send is None:
         raise ObjcRuntimeCouldNotReadMsgSendException(
             cpu, destination, selector)
     # save MsgSend in return register
     self.cpu._store_function(msg_send)
     return msg_send
Exemplo n.º 2
0
    def read_selector(self, selector, destination):
        ''' Called is a `Selector`. 
        Create a `MsgSend` and store it in the `MethodCall.
         
        Returns
        -------
        MsgSend
            the created `MsgSend 
        '''
        dest = None
        if selector is not None:
            if isinstance(destination, IVar):
                try:
                    destination.resolve_ivar_ref(self.ivar_lookup)
                except (IvarRefCouldNotBeResolvedException,
                        IvarRefWrongTypeException) as e:
                    log.exception(e)

            if isinstance(destination, FunctionInterface):
                dest = destination
            elif isinstance(destination, NSObjectInterface):
                dest = destination.get_nsobject()

            msg_send = self._msgsend_from_selector(selector, dest)
            return msg_send
        return None
Exemplo n.º 3
0
 def create_msg_send(self, selector, ivar_ref_lookup=None, *args, **kwargs):
     ''' Create a `MsgSend` with the specified `selector`.
     If the `ivar_ref` is not None, this will be used for the `MsgSend`.
     Otherwise the `ivar_class` is used.
     
     Parameters
     ----------
     selector: Selector
         the `Selector` with which the `MsgSend` shall be created.
     ivar_ref_lookup: IVarRefLookup, optional
         if given, the ivar_ref will be resolved
     Returns
     -------
     MsgSend
         the created `MsgSend` with `ivar_ref`  or `ivar_class`  
     '''
     # ivar_ref_lookup = kwargs.get('ivar_ref_lookup')
     if ivar_ref_lookup is not None:
         try:
             self.resolve_ivar_ref(ivar_ref_lookup)
         except (IvarRefCouldNotBeResolvedException,
                 IvarRefWrongTypeException) as e:
             log.exception(e)
     ivar_ref = self.get_ivar_ref()
     if ivar_ref is not None:
         return MsgSend.create_from_msgsend(ivar_ref, selector)
     else:
         return MsgSend(self.get_ivar_class(), [selector])
Exemplo n.º 4
0
    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)
Exemplo n.º 5
0
 def _read_formatstring_log(self, imp):
     ''' Read an NSLog `ImpStub` and add it to the `MethodCall. 
     
     Parameters
     ----------
     imp: Imp
     
     Raises
     ------
     CpuCouldNotReadLogFuncException
         if the NSLog could not be read 
         
     Returns
     -------
     is NSLog
     '''
     if isinstance(imp, ImpStub):
         is_formatstring_log = imp.is_format_string_log()
         log_func_name = imp.imp
         formatstring_log = None
         if is_formatstring_log:
             format_string_args = []
             # check if fst arg is `FormatString` and resolve the other arguments
             try:
                 formatstring_log_string = self.get_current_destination(
                     objc_msgSend_stret=False)
                 format_string_args = [formatstring_log_string]
                 if isinstance(formatstring_log_string, str):
                     formatstring_log_string = NSString(
                         formatstring_log_string)
                 elif isinstance(formatstring_log_string, Arguments):
                     try:
                         formatstring_log_string.fill_from_cpu(self)
                     except (FormatStringOverLoadedException,
                             FormatStringUnderLoadedException) as e:
                         log.exception(e)
                 # fst arg is no format string -> use heuristic for number of arguments
                 elif not isinstance(formatstring_log_string,
                                     (NSString, CString)):
                     # use heuristic from `AssignmentMatchingSystem` to determine the number of arguments for the function
                     format_string_args = self.get_memory(
                     ).get_arguments_from_asm_heuristic()
                     # fill args that can fill themselves from cpu
                     for arg in format_string_args:
                         if isinstance(arg, Arguments):
                             arg.fill_from_cpu(self)
                 formatstring_log = Function(log_func_name,
                                             format_string_args)
                 self._store_function(formatstring_log)
             except CpuCouldNotGetDestination as e:
                 raise CpuCouldNotReadLogFuncException(
                     self, log_func_name, '%s\n%s' %
                     (formatstring_log, e)), None, sys.exc_info()[2]
         return is_formatstring_log
     return False
Exemplo n.º 6
0
 def _read_assignment(self, asmline):
     ''' Read a line of assembler code containing an assignment
     and let the `AssignmentMatchingSystem` process it.
     
     This includes stack operations.
     The assignments being made are stored in the appropriate place (stack or register)
     
     Moreover this method reads a `VarAssignment` and keeps track of the instance variable cache
     as well as setting the superclass if available.
     '''
     try:
         var_assign = self.parse_util.parse_var_assignment(asmline)
         if var_assign is not None:
             self._process_var_assignment(var_assign)
         # CHECK IF ALSO CORRECT OR X86_64
         # consider "str        r0, [r4, r5]" (arm), needed to not set r5 = value(r0)
         else:
             self._process_assignment(asmline)
     except VarAssignmentResolveRegisterException as e:
         log.exception(e)
Exemplo n.º 7
0
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
Exemplo n.º 8
0
    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)