angr/analyses/binary_optimizer.py
def _redundant_stack_variable_removal(self, function, data_graph):
        """
        If an argument passed from the stack (i.e. dword ptr [ebp+4h]) is saved to a local variable on the stack at the
        beginning of the function, and this local variable was never modified anywhere in this function, and no pointer
        of any stack variable is saved in any register, then we can replace all references to this local variable to
        that argument instead.

        :param function:
        :param networkx.MultiDiGraph data_graph:
        :return:
        """

        # check if there is any stack pointer being stored into any register other than esp
        # basically check all consumers of stack pointers
        stack_ptrs = [ ]
        sp_offset = self.project.arch.registers['esp'][0]
        bp_offset = self.project.arch.registers['ebp'][0]
        for n in data_graph.nodes():
            if isinstance(n.variable, SimRegisterVariable) and n.variable.reg in (sp_offset, bp_offset):
                stack_ptrs.append(n)

        # for each stack pointer variable, make sure none of its consumers is a general purpose register
        for stack_ptr in stack_ptrs:
            out_edges = data_graph.out_edges(stack_ptr, data=True)
            for _, dst, data in out_edges:
                if 'type' in data and data['type'] == 'kill':
                    # we don't care about killing edges
                    continue
                if isinstance(dst.variable, SimRegisterVariable) and dst.variable.reg < 40 and \
                        dst.variable.reg not in (sp_offset, bp_offset):
                    # oops
                    l.debug('Function %s does not satisfy requirements of redundant stack variable removal.',
                            repr(function)
                            )
                    return

        argument_variables = [ ]

        for n in data_graph.nodes():
            if isinstance(n.variable, SimStackVariable) and n.variable.base == 'bp' and n.variable.offset >= 0:
                argument_variables.append(n)

        if not argument_variables:
            return

        #print function
        #print argument_variables

        argument_to_local = { }
        argument_register_as_retval = set()

        # for each argument, find its correspondence on the local stack frame

        for argument_variable in argument_variables:
            # is it copied to the stack?
            successors0 = list(data_graph.successors(argument_variable))

            if not successors0:
                continue

            if len(successors0) != 1:
                continue

            if isinstance(successors0[0].variable, SimRegisterVariable):
                # argument -> register -> stack
                out_edges = data_graph.out_edges(successors0[0], data=True)
                successors1 = [ s for _, s, data in out_edges if 'type' not in data or data['type'] != 'kill' ]
                if len(successors1) == 1:
                    successor1 = successors1[0]
                    if isinstance(successor1.variable, SimStackVariable):
                        if (successor1.variable.base == 'sp' and successor1.variable.offset > 0) or \
                                (successor1.variable.base == 'bp' and successor1.variable.offset < 0):
                            # yes it's copied onto the stack!
                            argument_to_local[argument_variable] = successor1

                # if the register is eax, and it's not killed later, it might be the return value of this function
                # in that case, we cannot eliminate the instruction that moves stack argument to that register
                if successors0[0].variable.reg == self.project.arch.registers['eax'][0]:
                    killers = [ s for _, s, data in out_edges if 'type' in data and data['type'] == 'kill']
                    if not killers:
                        # it might be the return value
                        argument_register_as_retval.add(argument_variable)

            else:
                # TODO:
                import ipdb; ipdb.set_trace()

        #import pprint
        #pprint.pprint(argument_to_local, width=160)

        # find local correspondence that are not modified throughout this function
        redundant_stack_variables = [ ]

        for argument, local_var in argument_to_local.items():
            # local_var cannot be killed anywhere
            out_edges = data_graph.out_edges(local_var, data=True)

            consuming_locs = [ ]

            for _, consumer, data in out_edges:
                consuming_locs.append(consumer.location)
                if 'type' in data and data['type'] == 'kill':
                    break
            else:
                # no killing edges. the value is not changed!
                rsv = RedundantStackVariable(argument, local_var, consuming_locs)
                if argument in argument_register_as_retval:
                    rsv.argument_register_as_retval = True
                redundant_stack_variables.append(rsv)

        self.redundant_stack_variables.extend(redundant_stack_variables)

        If an argument passed from the stack (i.e. dword ptr [ebp+4h]) is saved to a local variable on the stack at the
        beginning of the function, and this local variable was never modified anywhere in this function, and no pointer
        of any stack variable is saved in any register, then we can replace all references to this local variable to
        that argument instead.

        :param function:
        :param networkx.MultiDiGraph data_graph:
        :return:
        
If an argument passed from the stack  is saved to a local variable on the stack at the
beginning of the function, and this local variable was never modified anywhere in this function, and no pointer
of any stack variable is saved in any register, then we can replace all references to this local variable to
that argument instead.
If an argument passed from the stack is saved to a local variable on the stack at the beginning of the function and this local variable was never modified anywhere in this function and no pointer of any stack variable is saved in any register then we can replace all references to this local variable to that argument instead .
def _redundant_stack_variable_removal(self, function, data_graph):
        stack_ptrs = [ ]
        sp_offset = self.project.arch.registers['esp'][0]
        bp_offset = self.project.arch.registers['ebp'][0]
        for n in data_graph.nodes():
            if isinstance(n.variable, SimRegisterVariable) and n.variable.reg in (sp_offset, bp_offset):
                stack_ptrs.append(n)
        for stack_ptr in stack_ptrs:
            out_edges = data_graph.out_edges(stack_ptr, data=True)
            for _, dst, data in out_edges:
                if 'type' in data and data['type'] == 'kill':
                    continue
                if isinstance(dst.variable, SimRegisterVariable) and dst.variable.reg < 40 and \
                        dst.variable.reg not in (sp_offset, bp_offset):
                    l.debug('Function %s does not satisfy requirements of redundant stack variable removal.',
                            repr(function)
                            )
                    return
        argument_variables = [ ]
        for n in data_graph.nodes():
            if isinstance(n.variable, SimStackVariable) and n.variable.base == 'bp' and n.variable.offset >= 0:
                argument_variables.append(n)
        if not argument_variables:
            return
        argument_to_local = { }
        argument_register_as_retval = set()
        for argument_variable in argument_variables:
            successors0 = list(data_graph.successors(argument_variable))
            if not successors0:
                continue
            if len(successors0) != 1:
                continue
            if isinstance(successors0[0].variable, SimRegisterVariable):
                out_edges = data_graph.out_edges(successors0[0], data=True)
                successors1 = [ s for _, s, data in out_edges if 'type' not in data or data['type'] != 'kill' ]
                if len(successors1) == 1:
                    successor1 = successors1[0]
                    if isinstance(successor1.variable, SimStackVariable):
                        if (successor1.variable.base == 'sp' and successor1.variable.offset > 0) or \
                                (successor1.variable.base == 'bp' and successor1.variable.offset < 0):
                            argument_to_local[argument_variable] = successor1
                if successors0[0].variable.reg == self.project.arch.registers['eax'][0]:
                    killers = [ s for _, s, data in out_edges if 'type' in data and data['type'] == 'kill']
                    if not killers:
                        argument_register_as_retval.add(argument_variable)
            else:
                import ipdb; ipdb.set_trace()
        redundant_stack_variables = [ ]
        for argument, local_var in argument_to_local.items():
            out_edges = data_graph.out_edges(local_var, data=True)
            consuming_locs = [ ]
            for _, consumer, data in out_edges:
                consuming_locs.append(consumer.location)
                if 'type' in data and data['type'] == 'kill':
                    break
            else:
                rsv = RedundantStackVariable(argument, local_var, consuming_locs)
                if argument in argument_register_as_retval:
                    rsv.argument_register_as_retval = True
                redundant_stack_variables.append(rsv)
        self.redundant_stack_variables.extend(redundant_stack_variables)
def _redundant_stack_variable_removal ( self , function , data_graph ) : stack_ptrs = [ ] sp_offset = self . project . arch . registers [ 'esp' ] [ 0 ] bp_offset = self . project . arch . registers [ 'ebp' ] [ 0 ] for n in data_graph . nodes ( ) : if isinstance ( n . variable , SimRegisterVariable ) and n . variable . reg in ( sp_offset , bp_offset ) : stack_ptrs . append ( n ) for stack_ptr in stack_ptrs : out_edges = data_graph . out_edges ( stack_ptr , data = True ) for _ , dst , data in out_edges : if 'type' in data and data [ 'type' ] == 'kill' : continue if isinstance ( dst . variable , SimRegisterVariable ) and dst . variable . reg < 40 and dst . variable . reg not in ( sp_offset , bp_offset ) : l . debug ( 'Function %s does not satisfy requirements of redundant stack variable removal.' , repr ( function ) ) return argument_variables = [ ] for n in data_graph . nodes ( ) : if isinstance ( n . variable , SimStackVariable ) and n . variable . base == 'bp' and n . variable . offset >= 0 : argument_variables . append ( n ) if not argument_variables : return argument_to_local = { } argument_register_as_retval = set ( ) for argument_variable in argument_variables : successors0 = list ( data_graph . successors ( argument_variable ) ) if not successors0 : continue if len ( successors0 ) != 1 : continue if isinstance ( successors0 [ 0 ] . variable , SimRegisterVariable ) : out_edges = data_graph . out_edges ( successors0 [ 0 ] , data = True ) successors1 = [ s for _ , s , data in out_edges if 'type' not in data or data [ 'type' ] != 'kill' ] if len ( successors1 ) == 1 : successor1 = successors1 [ 0 ] if isinstance ( successor1 . variable , SimStackVariable ) : if ( successor1 . variable . base == 'sp' and successor1 . variable . offset > 0 ) or ( successor1 . variable . base == 'bp' and successor1 . variable . offset < 0 ) : argument_to_local [ argument_variable ] = successor1 if successors0 [ 0 ] . variable . reg == self . project . arch . registers [ 'eax' ] [ 0 ] : killers = [ s for _ , s , data in out_edges if 'type' in data and data [ 'type' ] == 'kill' ] if not killers : argument_register_as_retval . add ( argument_variable ) else : import ipdb ; ipdb . set_trace ( ) redundant_stack_variables = [ ] for argument , local_var in argument_to_local . items ( ) : out_edges = data_graph . out_edges ( local_var , data = True ) consuming_locs = [ ] for _ , consumer , data in out_edges : consuming_locs . append ( consumer . location ) if 'type' in data and data [ 'type' ] == 'kill' : break else : rsv = RedundantStackVariable ( argument , local_var , consuming_locs ) if argument in argument_register_as_retval : rsv . argument_register_as_retval = True redundant_stack_variables . append ( rsv ) self . redundant_stack_variables . extend ( redundant_stack_variables )
If an argument passed from the stack (i.e.
If an argument passed from the stack ( i . e .
"""
        If an argument passed from the stack (i.e. dword ptr [ebp+4h]) is saved to a local variable on the stack at the
        beginning of the function, and this local variable was never modified anywhere in this function, and no pointer
        of any stack variable is saved in any register, then we can replace all references to this local variable to
        that argument instead.

        :param function:
        :param networkx.MultiDiGraph data_graph:
        :return:
        """ # check if there is any stack pointer being stored into any register other than esp # basically check all consumers of stack pointers # for each stack pointer variable, make sure none of its consumers is a general purpose register # we don't care about killing edges # oops #print function #print argument_variables # for each argument, find its correspondence on the local stack frame # is it copied to the stack? # argument -> register -> stack # yes it's copied onto the stack! # if the register is eax, and it's not killed later, it might be the return value of this function # in that case, we cannot eliminate the instruction that moves stack argument to that register # it might be the return value # TODO: #import pprint #pprint.pprint(argument_to_local, width=160) # find local correspondence that are not modified throughout this function # local_var cannot be killed anywhere # no killing edges. the value is not changed!
None
self
function
None
data_graph
None