(self)
return True
Remove CGC attachments.

        :return: True if CGC attachments are found and removed, False otherwise
        :rtype: bool
Remove CGC attachments.
Remove CGC attachments .
def remove_cgc_attachments(self):
        """
        Remove CGC attachments.

        :return: True if CGC attachments are found and removed, False otherwise
        :rtype: bool
        """

        cgc_package_list = None
        cgc_extended_application = None

        for data in self.data:
            if data.sort == 'cgc-package-list':
                cgc_package_list = data
            elif data.sort == 'cgc-extended-application':
                cgc_extended_application = data

        if not cgc_package_list or not cgc_extended_application:
            return False

        if cgc_package_list.skip or cgc_extended_application.skip:
            # they have already been removed
            # so we still return True to indicate that CGC attachments have been removed
            return True

        # there is a single function referencing them
        cgcpl_memory_data = self.cfg.memory_data.get(cgc_package_list.addr, None)
        cgcea_memory_data = self.cfg.memory_data.get(cgc_extended_application.addr, None)
        refs = self.cfg.kb.xrefs

        if cgcpl_memory_data is None or cgcea_memory_data is None:
            return False

        if len(refs.get_xrefs_by_dst(cgcpl_memory_data.addr)) != 1:
            return False
        if len(refs.get_xrefs_by_dst(cgcea_memory_data.addr)) != 1:
            return False

        # check if the irsb addresses are the same
        if next(iter(refs.get_xrefs_by_dst(cgcpl_memory_data.addr))).block_addr != \
                next(iter(refs.get_xrefs_by_dst(cgcea_memory_data.addr))).block_addr:
            return False

        insn_addr = next(iter(refs.get_xrefs_by_dst(cgcpl_memory_data.addr))).ins_addr
        # get the basic block
        cfg_node = self.cfg.model.get_any_node(insn_addr, anyaddr=True)
        if not cfg_node:
            return False

        func_addr = cfg_node.function_address

        # this function should be calling another function
        sub_func_addr = None
        if func_addr not in self.cfg.functions:
            return False
        function = self.cfg.functions[func_addr]
        # traverse the graph and make sure there is only one call edge
        calling_targets = [ ]
        for _, dst, data in function.transition_graph.edges(data=True):
            if 'type' in data and data['type'] == 'call':
                calling_targets.append(dst.addr)

        if len(calling_targets) != 1:
            return False

        sub_func_addr = calling_targets[0]

        # alright. We want to nop this function, as well as the subfunction
        proc = next((p for p in self.procedures if p.addr == func_addr), None)
        if proc is None:
            return False

        subproc = next((p for p in self.procedures if p.addr == sub_func_addr), None)
        if subproc is None:
            return False

        # if those two data entries have any label, we should properly modify them
        # at this point, we are fairly confident that none of those labels are direct data references to either package
        # list or extended application
        has_label = True
        lowest_address = min(cgc_package_list.addr, cgc_extended_application.addr)
        for obj in (cgc_package_list, cgc_extended_application):
            labels = obj.labels
            for addr, label in labels:
                if addr != lowest_address:
                    label.base_addr = lowest_address

        if has_label:
            # is there any memory data entry that ends right at the lowest address?
            data = next((d for d in self.data if d.addr is not None and d.addr + d.size == lowest_address), None)
            if data is None:
                # since there is no gap between memory data entries (we guarantee that), this can only be that no other
                # data resides in the same memory region that CGC attachments are in
                pass
            else:
                lbl = self.symbol_manager.addr_to_label[lowest_address][0]
                if lbl not in data.end_labels:
                    data.end_labels.append(lbl)

        # practically nop the function
        proc.asm_code = "\tret\n"
        subproc.asm_code = "\tret\n"

        # remove those two data entries
        cgc_package_list.skip = True
        cgc_extended_application.skip = True

        l.info('CGC attachments are removed.')

        return True
def remove_cgc_attachments ( self ) : cgc_package_list = None cgc_extended_application = None for data in self . data : if data . sort == 'cgc-package-list' : cgc_package_list = data elif data . sort == 'cgc-extended-application' : cgc_extended_application = data if not cgc_package_list or not cgc_extended_application : return False if cgc_package_list . skip or cgc_extended_application . skip : # they have already been removed # so we still return True to indicate that CGC attachments have been removed return True # there is a single function referencing them cgcpl_memory_data = self . cfg . memory_data . get ( cgc_package_list . addr , None ) cgcea_memory_data = self . cfg . memory_data . get ( cgc_extended_application . addr , None ) refs = self . cfg . kb . xrefs if cgcpl_memory_data is None or cgcea_memory_data is None : return False if len ( refs . get_xrefs_by_dst ( cgcpl_memory_data . addr ) ) != 1 : return False if len ( refs . get_xrefs_by_dst ( cgcea_memory_data . addr ) ) != 1 : return False # check if the irsb addresses are the same if next ( iter ( refs . get_xrefs_by_dst ( cgcpl_memory_data . addr ) ) ) . block_addr != next ( iter ( refs . get_xrefs_by_dst ( cgcea_memory_data . addr ) ) ) . block_addr : return False insn_addr = next ( iter ( refs . get_xrefs_by_dst ( cgcpl_memory_data . addr ) ) ) . ins_addr # get the basic block cfg_node = self . cfg . model . get_any_node ( insn_addr , anyaddr = True ) if not cfg_node : return False func_addr = cfg_node . function_address # this function should be calling another function sub_func_addr = None if func_addr not in self . cfg . functions : return False function = self . cfg . functions [ func_addr ] # traverse the graph and make sure there is only one call edge calling_targets = [ ] for _ , dst , data in function . transition_graph . edges ( data = True ) : if 'type' in data and data [ 'type' ] == 'call' : calling_targets . append ( dst . addr ) if len ( calling_targets ) != 1 : return False sub_func_addr = calling_targets [ 0 ] # alright. We want to nop this function, as well as the subfunction proc = next ( ( p for p in self . procedures if p . addr == func_addr ) , None ) if proc is None : return False subproc = next ( ( p for p in self . procedures if p . addr == sub_func_addr ) , None ) if subproc is None : return False # if those two data entries have any label, we should properly modify them # at this point, we are fairly confident that none of those labels are direct data references to either package # list or extended application has_label = True lowest_address = min ( cgc_package_list . addr , cgc_extended_application . addr ) for obj in ( cgc_package_list , cgc_extended_application ) : labels = obj . labels for addr , label in labels : if addr != lowest_address : label . base_addr = lowest_address if has_label : # is there any memory data entry that ends right at the lowest address? data = next ( ( d for d in self . data if d . addr is not None and d . addr + d . size == lowest_address ) , None ) if data is None : # since there is no gap between memory data entries (we guarantee that), this can only be that no other # data resides in the same memory region that CGC attachments are in pass else : lbl = self . symbol_manager . addr_to_label [ lowest_address ] [ 0 ] if lbl not in data . end_labels : data . end_labels . append ( lbl ) # practically nop the function proc . asm_code = "\tret\n" subproc . asm_code = "\tret\n" # remove those two data entries cgc_package_list . skip = True cgc_extended_application . skip = True l . info ( 'CGC attachments are removed.' ) return True