(self, cfg, addr, func_addr, b)
return False, None
Internal method for resolving jump tables.

        :param cfg:             A CFG instance.
        :param int addr:        Address of the block where the indirect jump is.
        :param int func_addr:   Address of the function.
        :param Blade b:         The generated backward slice.
        :return:                A bool indicating whether the indirect jump is resolved successfully, and a list of
                                resolved targets.
        :rtype:                 tuple
Internal method for resolving jump tables.
Internal method for resolving jump tables .
def _resolve(self, cfg, addr, func_addr, b):
        """
        Internal method for resolving jump tables.

        :param cfg:             A CFG instance.
        :param int addr:        Address of the block where the indirect jump is.
        :param int func_addr:   Address of the function.
        :param Blade b:         The generated backward slice.
        :return:                A bool indicating whether the indirect jump is resolved successfully, and a list of
                                resolved targets.
        :rtype:                 tuple
        """

        project = self.project  # short-hand

        stmt_loc = (addr, DEFAULT_STATEMENT)
        if stmt_loc not in b.slice:
            return False, None

        load_stmt_loc, load_stmt, load_size, stmts_to_remove, stmts_adding_base_addr, all_addr_holders = \
            self._find_load_statement(b, stmt_loc)
        ite_stmt, ite_stmt_loc = None, None

        if load_stmt_loc is None:
            # the load statement is not found
            # maybe it's a typical ARM-style jump table like the following:
            #   SUB    R3, R5, #34
            #   CMP    R3, #28
            #   ADDLS  PC, PC, R3,LSL#2
            if is_arm_arch(self.project.arch):
                ite_stmt, ite_stmt_loc, stmts_to_remove = self._find_load_pc_ite_statement(b, stmt_loc)
            if ite_stmt is None:
                return False, None

        try:
            jump_target = self._try_resolve_single_constant_loads(load_stmt, cfg, addr)
        except NotAJumpTableNotification:
            return False, None
        if jump_target is not None:
            if self._is_target_valid(cfg, jump_target):
                ij = cfg.indirect_jumps[addr]
                ij.jumptable = False
                ij.resolved_targets = { jump_target }
                return True, [ jump_target ]
            else:
                return False, None

        # Well, we have a real jump table to resolve!

        # skip all statements after the load statement
        # We want to leave the final loaded value as symbolic, so we can
        # get the full range of possibilities
        b.slice.remove_nodes_from(stmts_to_remove)

        try:
            stmts_to_instrument, regs_to_initialize = self._jumptable_precheck(b)
        except NotAJumpTableNotification:
            l.debug("Indirect jump at %#x does not look like a jump table. Skip.", addr)
            return False, None

        # Debugging output
        if l.level == logging.DEBUG:
            self._dbg_repr_slice(b)

        # Get all sources
        sources = [ n_ for n_ in b.slice.nodes() if b.slice.in_degree(n_) == 0 ]

        # Create the annotated CFG
        annotatedcfg = AnnotatedCFG(project, None, detect_loops=False)
        annotatedcfg.from_digraph(b.slice)

        # pylint: disable=too-many-nested-blocks
        for src_irsb, _ in sources:
            # Use slicecutor to execute each one, and get the address
            # We simply give up if any exception occurs on the way
            start_state = self._initial_state(src_irsb)
            # Keep IP symbolic to avoid unnecessary concretization
            start_state.options.add(o.KEEP_IP_SYMBOLIC)
            start_state.options.add(o.NO_IP_CONCRETIZATION)
            # be quiet!!!!!!
            start_state.options.add(o.SYMBOL_FILL_UNCONSTRAINED_REGISTERS)
            start_state.options.add(o.SYMBOL_FILL_UNCONSTRAINED_MEMORY)

            # any read from an uninitialized segment should be unconstrained
            if self._bss_regions:
                bss_hook = BSSHook(self.project, self._bss_regions)
                bss_memory_write_bp = BP(when=BP_AFTER, enabled=True, action=bss_hook.bss_memory_write_hook)
                start_state.inspect.add_breakpoint('mem_write', bss_memory_write_bp)
                bss_memory_read_bp = BP(when=BP_BEFORE, enabled=True, action=bss_hook.bss_memory_read_hook)
                start_state.inspect.add_breakpoint('mem_read', bss_memory_read_bp)

            # instrument specified store/put/load statements
            self._instrument_statements(start_state, stmts_to_instrument, regs_to_initialize)

            # FIXME:
            # this is a hack: for certain architectures, we do not initialize the base pointer, since the jump table on
            # those architectures may use the bp register to store value
            if not self.project.arch.name in {'S390X'}:
                start_state.regs.bp = start_state.arch.initial_sp + 0x2000

            self._cached_memread_addrs.clear()
            init_registers_on_demand_bp = BP(when=BP_BEFORE, enabled=True, action=self._init_registers_on_demand)
            start_state.inspect.add_breakpoint('mem_read', init_registers_on_demand_bp)

            # use Any as the concretization strategy
            start_state.memory.read_strategies = [SimConcretizationStrategyAny()]
            start_state.memory.write_strategies = [SimConcretizationStrategyAny()]

            # Create the slicecutor
            simgr = self.project.factory.simulation_manager(start_state, resilience=True)
            slicecutor = Slicecutor(annotatedcfg, force_taking_exit=True)
            simgr.use_technique(slicecutor)
            if load_stmt is not None:
                explorer = Explorer(find=load_stmt_loc[0])
            elif ite_stmt is not None:
                explorer = Explorer(find=ite_stmt_loc[0])
            else:
                raise TypeError("Unsupported type of jump table.")
            simgr.use_technique(explorer)

            # Run it!
            try:
                simgr.run()
            except KeyError as ex:
                # This is because the program slice is incomplete.
                # Blade will support more IRExprs and IRStmts in the future
                l.debug("KeyError occurred due to incomplete program slice.", exc_info=ex)
                continue

            # Get the jumping targets
            for r in simgr.found:
                if load_stmt is not None:
                    ret = self._try_resolve_targets_load(r, addr, cfg, annotatedcfg, load_stmt, load_size,
                                                         stmts_adding_base_addr, all_addr_holders)
                    if ret is None:
                        # Try the next state
                        continue
                    jump_table, jumptable_addr, entry_size, jumptable_size, all_targets, sort = ret
                    if sort == "jumptable":
                        ij_type = IndirectJumpType.Jumptable_AddressLoadedFromMemory
                    elif sort == "vtable":
                        ij_type = IndirectJumpType.Vtable
                    else:
                        ij_type = IndirectJumpType.Unknown
                elif ite_stmt is not None:
                    ret = self._try_resolve_targets_ite(r, addr, cfg, annotatedcfg, ite_stmt)
                    if ret is None:
                        # Try the next state
                        continue
                    jumptable_addr = None
                    jump_table, jumptable_size, entry_size = ret
                    all_targets = jump_table
                    ij_type = IndirectJumpType.Jumptable_AddressComputed
                else:
                    raise TypeError("Unsupported type of jump table.")

                assert ret is not None

                # finally, we filter jump targets according to the alignment of the architecture
                if is_arm_arch(self.project.arch):
                    alignment = 4 if addr % 2 == 0 else 2
                else:
                    alignment = self.project.arch.instruction_alignment
                if alignment != 1:
                    if is_arm_arch(self.project.arch) and addr % 2 == 1:
                        # Special logic for handling THUMB addresses
                        all_targets = [t_ for t_ in all_targets if (t_ - 1) % alignment == 0]
                    else:
                        all_targets = [ t_ for t_ in all_targets if t_ % alignment == 0 ]

                l.info("Resolved %d targets from %#x.", len(all_targets), addr)

                # write to the IndirectJump object in CFG
                ij: IndirectJump = cfg.indirect_jumps[addr]
                if len(all_targets) > 1:
                    # It can be considered a jump table only if there are more than one jump target
                    if ij_type in (IndirectJumpType.Jumptable_AddressComputed, IndirectJumpType.Jumptable_AddressLoadedFromMemory):
                        ij.jumptable = True
                    else:
                        ij.jumptable = False
                    ij.jumptable_addr = jumptable_addr
                    ij.jumptable_size = jumptable_size
                    ij.jumptable_entry_size = entry_size
                    ij.resolved_targets = set(jump_table)
                    ij.jumptable_entries = jump_table
                    ij.type = ij_type
                else:
                    ij.jumptable = False
                    ij.resolved_targets = set(jump_table)

                return True, all_targets

        l.info("Could not resolve indirect jump %#x in function %#x.", addr, func_addr)
        return False, None
def _resolve ( self , cfg , addr , func_addr , b ) : project = self . project # short-hand stmt_loc = ( addr , DEFAULT_STATEMENT ) if stmt_loc not in b . slice : return False , None load_stmt_loc , load_stmt , load_size , stmts_to_remove , stmts_adding_base_addr , all_addr_holders = self . _find_load_statement ( b , stmt_loc ) ite_stmt , ite_stmt_loc = None , None if load_stmt_loc is None : # the load statement is not found # maybe it's a typical ARM-style jump table like the following: #   SUB    R3, R5, #34 #   CMP    R3, #28 #   ADDLS  PC, PC, R3,LSL#2 if is_arm_arch ( self . project . arch ) : ite_stmt , ite_stmt_loc , stmts_to_remove = self . _find_load_pc_ite_statement ( b , stmt_loc ) if ite_stmt is None : return False , None try : jump_target = self . _try_resolve_single_constant_loads ( load_stmt , cfg , addr ) except NotAJumpTableNotification : return False , None if jump_target is not None : if self . _is_target_valid ( cfg , jump_target ) : ij = cfg . indirect_jumps [ addr ] ij . jumptable = False ij . resolved_targets = { jump_target } return True , [ jump_target ] else : return False , None # Well, we have a real jump table to resolve! # skip all statements after the load statement # We want to leave the final loaded value as symbolic, so we can # get the full range of possibilities b . slice . remove_nodes_from ( stmts_to_remove ) try : stmts_to_instrument , regs_to_initialize = self . _jumptable_precheck ( b ) except NotAJumpTableNotification : l . debug ( "Indirect jump at %#x does not look like a jump table. Skip." , addr ) return False , None # Debugging output if l . level == logging . DEBUG : self . _dbg_repr_slice ( b ) # Get all sources sources = [ n_ for n_ in b . slice . nodes ( ) if b . slice . in_degree ( n_ ) == 0 ] # Create the annotated CFG annotatedcfg = AnnotatedCFG ( project , None , detect_loops = False ) annotatedcfg . from_digraph ( b . slice ) # pylint: disable=too-many-nested-blocks for src_irsb , _ in sources : # Use slicecutor to execute each one, and get the address # We simply give up if any exception occurs on the way start_state = self . _initial_state ( src_irsb ) # Keep IP symbolic to avoid unnecessary concretization start_state . options . add ( o . KEEP_IP_SYMBOLIC ) start_state . options . add ( o . NO_IP_CONCRETIZATION ) # be quiet!!!!!! start_state . options . add ( o . SYMBOL_FILL_UNCONSTRAINED_REGISTERS ) start_state . options . add ( o . SYMBOL_FILL_UNCONSTRAINED_MEMORY ) # any read from an uninitialized segment should be unconstrained if self . _bss_regions : bss_hook = BSSHook ( self . project , self . _bss_regions ) bss_memory_write_bp = BP ( when = BP_AFTER , enabled = True , action = bss_hook . bss_memory_write_hook ) start_state . inspect . add_breakpoint ( 'mem_write' , bss_memory_write_bp ) bss_memory_read_bp = BP ( when = BP_BEFORE , enabled = True , action = bss_hook . bss_memory_read_hook ) start_state . inspect . add_breakpoint ( 'mem_read' , bss_memory_read_bp ) # instrument specified store/put/load statements self . _instrument_statements ( start_state , stmts_to_instrument , regs_to_initialize ) # FIXME: # this is a hack: for certain architectures, we do not initialize the base pointer, since the jump table on # those architectures may use the bp register to store value if not self . project . arch . name in { 'S390X' } : start_state . regs . bp = start_state . arch . initial_sp + 0x2000 self . _cached_memread_addrs . clear ( ) init_registers_on_demand_bp = BP ( when = BP_BEFORE , enabled = True , action = self . _init_registers_on_demand ) start_state . inspect . add_breakpoint ( 'mem_read' , init_registers_on_demand_bp ) # use Any as the concretization strategy start_state . memory . read_strategies = [ SimConcretizationStrategyAny ( ) ] start_state . memory . write_strategies = [ SimConcretizationStrategyAny ( ) ] # Create the slicecutor simgr = self . project . factory . simulation_manager ( start_state , resilience = True ) slicecutor = Slicecutor ( annotatedcfg , force_taking_exit = True ) simgr . use_technique ( slicecutor ) if load_stmt is not None : explorer = Explorer ( find = load_stmt_loc [ 0 ] ) elif ite_stmt is not None : explorer = Explorer ( find = ite_stmt_loc [ 0 ] ) else : raise TypeError ( "Unsupported type of jump table." ) simgr . use_technique ( explorer ) # Run it! try : simgr . run ( ) except KeyError as ex : # This is because the program slice is incomplete. # Blade will support more IRExprs and IRStmts in the future l . debug ( "KeyError occurred due to incomplete program slice." , exc_info = ex ) continue # Get the jumping targets for r in simgr . found : if load_stmt is not None : ret = self . _try_resolve_targets_load ( r , addr , cfg , annotatedcfg , load_stmt , load_size , stmts_adding_base_addr , all_addr_holders ) if ret is None : # Try the next state continue jump_table , jumptable_addr , entry_size , jumptable_size , all_targets , sort = ret if sort == "jumptable" : ij_type = IndirectJumpType . Jumptable_AddressLoadedFromMemory elif sort == "vtable" : ij_type = IndirectJumpType . Vtable else : ij_type = IndirectJumpType . Unknown elif ite_stmt is not None : ret = self . _try_resolve_targets_ite ( r , addr , cfg , annotatedcfg , ite_stmt ) if ret is None : # Try the next state continue jumptable_addr = None jump_table , jumptable_size , entry_size = ret all_targets = jump_table ij_type = IndirectJumpType . Jumptable_AddressComputed else : raise TypeError ( "Unsupported type of jump table." ) assert ret is not None # finally, we filter jump targets according to the alignment of the architecture if is_arm_arch ( self . project . arch ) : alignment = 4 if addr % 2 == 0 else 2 else : alignment = self . project . arch . instruction_alignment if alignment != 1 : if is_arm_arch ( self . project . arch ) and addr % 2 == 1 : # Special logic for handling THUMB addresses all_targets = [ t_ for t_ in all_targets if ( t_ - 1 ) % alignment == 0 ] else : all_targets = [ t_ for t_ in all_targets if t_ % alignment == 0 ] l . info ( "Resolved %d targets from %#x." , len ( all_targets ) , addr ) # write to the IndirectJump object in CFG ij : IndirectJump = cfg . indirect_jumps [ addr ] if len ( all_targets ) > 1 : # It can be considered a jump table only if there are more than one jump target if ij_type in ( IndirectJumpType . Jumptable_AddressComputed , IndirectJumpType . Jumptable_AddressLoadedFromMemory ) : ij . jumptable = True else : ij . jumptable = False ij . jumptable_addr = jumptable_addr ij . jumptable_size = jumptable_size ij . jumptable_entry_size = entry_size ij . resolved_targets = set ( jump_table ) ij . jumptable_entries = jump_table ij . type = ij_type else : ij . jumptable = False ij . resolved_targets = set ( jump_table ) return True , all_targets l . info ( "Could not resolve indirect jump %#x in function %#x." , addr , func_addr ) return False , None