angr/analyses/backward_slice.py
def _find_exits(self, src_block, target_block):
        """
        Source block has more than one exit, and through some of those exits, the control flow can eventually go to
        the target block. This method returns exits that lead to the target block.

        :param src_block:       The block that has multiple exits.
        :param target_block:    The target block to reach.
        :returns: a dict of statement ID -> a list of target IPs (or None if the exit should not be taken), each
                corresponds to an exit to take in order to reach the target.
                For example, it returns the following dict:
                {
                    'default': None, # It has a default exit, but shouldn't be taken
                    15: [ 0x400080 ], # Statement 15 is an exit statement, and should be taken when the target is
                                      # 0x400080
                    28: None  # Statement 28 is an exit statement, but shouldn't be taken
                }
        """

        # Enumerate all statements and find exit statements
        # Since we don't have a state, we have to rely on the pyvex block instead of SimIRSB
        # Just create the block from pyvex again - not a big deal

        if self.project.is_hooked(src_block.addr):
            # Just return all exits for now
            return { -1: [ target_block.addr ] }

        block = self.project.factory.block(src_block.addr)
        vex_block = block.vex

        exit_stmt_ids = { }

        for stmt_idx, stmt in enumerate(vex_block.statements):
            if isinstance(stmt, pyvex.IRStmt.Exit):
                exit_stmt_ids[stmt_idx] = None

        # And of course, it has a default exit
        # Don't forget about it.
        exit_stmt_ids[DEFAULT_STATEMENT] = None

        # Find all paths from src_block to target_block
        # FIXME: This is some crappy code written in a hurry. Replace the all_simple_paths() later.
        all_simple_paths = list(networkx.all_simple_paths(self._cfg.graph, src_block, target_block, cutoff=3))

        for simple_path in all_simple_paths:
            if len(simple_path) <= 1:
                # Oops, it looks that src_block and target_block are the same guy?
                continue

            if self._same_function:
                # Examine this path and make sure it does not have call or return edge
                for i in range(len(simple_path) - 1):
                    jumpkind = self._cfg.graph[simple_path[i]][simple_path[i + 1]]['jumpkind']
                    if jumpkind in ('Ijk_Call', 'Ijk_Ret'):
                        return {  }

            # Get the first two nodes
            a, b = simple_path[0], simple_path[1]
            # Get the exit statement ID from CFG
            exit_stmt_id = self._cfg.model.get_exit_stmt_idx(a, b)
            if exit_stmt_id is None:
                continue

            # Mark it!
            if exit_stmt_ids[exit_stmt_id] is None:
                exit_stmt_ids[exit_stmt_id] = [ b.addr ]
            else:
                exit_stmt_ids[exit_stmt_id].append(b.addr)

        return exit_stmt_ids

        Source block has more than one exit, and through some of those exits, the control flow can eventually go to
        the target block. This method returns exits that lead to the target block.

        :param src_block:       The block that has multiple exits.
        :param target_block:    The target block to reach.
        :returns: a dict of statement ID -> a list of target IPs (or None if the exit should not be taken), each
                corresponds to an exit to take in order to reach the target.
                For example, it returns the following dict:
                {
                    'default': None, # It has a default exit, but shouldn't be taken
                    15: [ 0x400080 ], # Statement 15 is an exit statement, and should be taken when the target is
                                      # 0x400080
                    28: None  # Statement 28 is an exit statement, but shouldn't be taken
                }
        
Source block has more than one exit, and through some of those exits, the control flow can eventually go to
the target block. This method returns exits that lead to the target block.
Source block has more than one exit and through some of those exits the control flow can eventually go to the target block . This method returns exits that lead to the target block .
def _find_exits(self, src_block, target_block):
        if self.project.is_hooked(src_block.addr):
            return { -1: [ target_block.addr ] }
        block = self.project.factory.block(src_block.addr)
        vex_block = block.vex
        exit_stmt_ids = { }
        for stmt_idx, stmt in enumerate(vex_block.statements):
            if isinstance(stmt, pyvex.IRStmt.Exit):
                exit_stmt_ids[stmt_idx] = None
        exit_stmt_ids[DEFAULT_STATEMENT] = None
        all_simple_paths = list(networkx.all_simple_paths(self._cfg.graph, src_block, target_block, cutoff=3))
        for simple_path in all_simple_paths:
            if len(simple_path) <= 1:
                continue
            if self._same_function:
                for i in range(len(simple_path) - 1):
                    jumpkind = self._cfg.graph[simple_path[i]][simple_path[i + 1]]['jumpkind']
                    if jumpkind in ('Ijk_Call', 'Ijk_Ret'):
                        return {  }
            a, b = simple_path[0], simple_path[1]
            exit_stmt_id = self._cfg.model.get_exit_stmt_idx(a, b)
            if exit_stmt_id is None:
                continue
            if exit_stmt_ids[exit_stmt_id] is None:
                exit_stmt_ids[exit_stmt_id] = [ b.addr ]
            else:
                exit_stmt_ids[exit_stmt_id].append(b.addr)
        return exit_stmt_ids
def _find_exits ( self , src_block , target_block ) : if self . project . is_hooked ( src_block . addr ) : return { - 1 : [ target_block . addr ] } block = self . project . factory . block ( src_block . addr ) vex_block = block . vex exit_stmt_ids = { } for stmt_idx , stmt in enumerate ( vex_block . statements ) : if isinstance ( stmt , pyvex . IRStmt . Exit ) : exit_stmt_ids [ stmt_idx ] = None exit_stmt_ids [ DEFAULT_STATEMENT ] = None all_simple_paths = list ( networkx . all_simple_paths ( self . _cfg . graph , src_block , target_block , cutoff = 3 ) ) for simple_path in all_simple_paths : if len ( simple_path ) <= 1 : continue if self . _same_function : for i in range ( len ( simple_path ) - 1 ) : jumpkind = self . _cfg . graph [ simple_path [ i ] ] [ simple_path [ i + 1 ] ] [ 'jumpkind' ] if jumpkind in ( 'Ijk_Call' , 'Ijk_Ret' ) : return { } a , b = simple_path [ 0 ] , simple_path [ 1 ] exit_stmt_id = self . _cfg . model . get_exit_stmt_idx ( a , b ) if exit_stmt_id is None : continue if exit_stmt_ids [ exit_stmt_id ] is None : exit_stmt_ids [ exit_stmt_id ] = [ b . addr ] else : exit_stmt_ids [ exit_stmt_id ] . append ( b . addr ) return exit_stmt_ids
Source block has more than one exit, and through some of those exits, the control flow can eventually go to
the target block.
Source block has more than one exit and through some of those exits the control flow can eventually go to the target block .
"""
        Source block has more than one exit, and through some of those exits, the control flow can eventually go to
        the target block. This method returns exits that lead to the target block.

        :param src_block:       The block that has multiple exits.
        :param target_block:    The target block to reach.
        :returns: a dict of statement ID -> a list of target IPs (or None if the exit should not be taken), each
                corresponds to an exit to take in order to reach the target.
                For example, it returns the following dict:
                {
                    'default': None, # It has a default exit, but shouldn't be taken
                    15: [ 0x400080 ], # Statement 15 is an exit statement, and should be taken when the target is
                                      # 0x400080
                    28: None  # Statement 28 is an exit statement, but shouldn't be taken
                }
        """ # Enumerate all statements and find exit statements # Since we don't have a state, we have to rely on the pyvex block instead of SimIRSB # Just create the block from pyvex again - not a big deal # Just return all exits for now # And of course, it has a default exit # Don't forget about it. # Find all paths from src_block to target_block # FIXME: This is some crappy code written in a hurry. Replace the all_simple_paths() later. # Oops, it looks that src_block and target_block are the same guy? # Examine this path and make sure it does not have call or return edge # Get the first two nodes # Get the exit statement ID from CFG # Mark it!
a dict of statement ID -> a list of target IPs (or None if the exit should not be taken), each
corresponds to an exit to take in order to reach the target.
For example, it returns the following dict:
{
'default': None, # It has a default exit, but shouldn't be taken
15: [ 0x400080 ], # Statement 15 is an exit statement, and should be taken when the target is
0x400080
28: None  # Statement 28 is an exit statement, but shouldn't be taken
}
a dict of statement ID - > a list of target IPs ( or None if the exit should not be taken ) each corresponds to an exit to take in order to reach the target . For example it returns the following dict : { ' default ' : None # It has a default exit but shouldn ' t be taken 15 : [ 0x400080 ] # Statement 15 is an exit statement and should be taken when the target is 0x400080 28 : None # Statement 28 is an exit statement but shouldn ' t be taken }
self
src_block
The block that has multiple exits.
The block that has multiple exits .
target_block
The target block to reach.
The target block to reach .