def handle_set_struct(self): if self.edit_class is None: return default_struct_name = idc.get_struc_name(self.edit_class.struct_id) \ if self.edit_class.struct_id != idc.BADADDR else \ self.edit_class.name dlg = ChooseStructDialog(default_struct_name, has_none_btn=True) if dlg.exec_() != QtWidgets.QDialog.Accepted: return if dlg.struct_id == self.edit_class.struct_id: return db = database.get() if dlg.struct_id in db.classes_by_struct_id: idaapi.warning( 'The struct "%s" is already linked to the class "%s"' % (idc.get_struc_name( dlg.struct_id), b.classes_by_struct_id[dlg.struct_id])) return delete_orphaned = False if self.edit_class.struct_id != idc.BADADDR: delete_orphaned = util.ask_yes_no( 'Do you want to delete the orphaned class', False) self.edit_class.set_struct_id(dlg.struct_id, delete_orphaned) self.update_fields()
def rename(self, new_name): old_name = self.name db = database.get() del db.classes_by_name[old_name] db.classes_by_name[new_name] = self self.name = new_name # Try to rename the struct if self.struct_id != idc.BADADDR: struct_name = idc.get_struc_name(self.struct_id) if struct_name == Class.s_safe_name(old_name): idc.set_struc_name(self.struct_id, self.safe_name()) # Rename ctors and dtors for vm in self.vmethods: if vm.name == old_name: vm.name = new_name if vm.name == '~' + old_name: vm.name = '~' + new_name for m in self.methods: if m.name == old_name: m.name = new_name if m.name == '~' + old_name: m.name = '~' + new_name self.refresh()
def Structs(): """ Get a list of structures @return: List of tuples (idx, sid, name) """ idx = idc.get_first_struc_idx() while idx != ida_idaapi.BADADDR: sid = idc.get_struc_by_idx(idx) yield (idx, sid, idc.get_struc_name(sid)) idx = idc.get_next_struc_idx(idx)
def unlink_struct(self, delete_orphaned=False): if self.struct_id == idc.BADADDR: return del database.get().classes_by_struct_id[self.struct_id] if delete_orphaned: idc.del_struc(self.struct_id) else: struct_name = idc.get_struc_name(self.struct_id) idc.set_struc_cmt(self.struct_id, 'Orphaned from %s' % self.name, False) idc.set_struc_name(self.struct_id, '%s_orphaned' % struct_name) self.struct_id = idc.BADADDR
def create_structs(self): self.struct_id = utils.add_struc_retry(self.name) if self.struct_id == BADADDR: return False self.name = idc.get_struc_name(self.struct_id) self.struct_ptr = ida_struct.get_struc(self.struct_id) if self.struct_ptr is None: log.exception("self.struct_ptr is None at %s", self.name) previous_parent_offset = 0 previous_parent_size = 0 previous_parent_struct_id = BADADDR for parent_name, parent_offset in self.updated_parents: if ( parent_offset - previous_parent_offset > previous_parent_size and previous_parent_struct_id != BADADDR ): utils.expand_struct( previous_parent_struct_id, parent_offset - previous_parent_offset, ) baseclass_id = ida_struct.get_struc_id(parent_name) baseclass_size = ida_struct.get_struc_size(baseclass_id) if baseclass_id == BADADDR or baseclass_size == 0: log.warning( "bad struct id or size: %s(0x%X:%s) - 0x%X, %d", self.name, parent_offset, parent_name, baseclass_id, baseclass_size, ) cpp_utils.add_baseclass(self.name, parent_name, parent_offset) previous_parent_offset = parent_offset previous_parent_size = baseclass_size previous_parent_struct_id = baseclass_id if self.updated_parents: utils.refresh_struct(self.struct_ptr) return True
def read_struct(ea, struct=None, sid=None, members=None, asobject=False): """Read a structure from the given address. This function reads the structure at the given address and converts it into a dictionary or accessor object. Arguments: ea: The linear address of the start of the structure. Options: sid: The structure ID of the structure type to read. struct: The name of the structure type to read. members: A list of the names of the member fields to read. If members is None, then all members are read. Default is None. asobject: If True, then the struct is returned as a Python object rather than a dict. One of sid and struct must be specified. """ # Handle sid/struct. if struct is not None: sid2 = idc.get_struc_id(struct) if sid2 == idc.BADADDR: raise ValueError('Invalid struc name {}'.format(struct)) if sid is not None and sid2 != sid: raise ValueError('Invalid arguments: sid={}, struct={}'.format( sid, struct)) sid = sid2 else: if sid is None: raise ValueError('Invalid arguments: sid={}, struct={}'.format( sid, struct)) if idc.get_struc_name(sid) is None: raise ValueError('Invalid struc id {}'.format(sid)) # Iterate through the members and add them to the struct. union = idc.is_union(sid) struct = {} for offset, name, size in idautils.StructMembers(sid): if members is not None and name not in members: continue _read_struct_member(struct, sid, union, ea, offset, name, size, asobject) if asobject: struct = objectview(struct, ea, idc.get_struc_size(sid)) return struct
def update_fields(self): if self.edit_class is None: self.setDisabled(True) self.name.setText('Name: -') self.base_class.setText('Base class: -') self.derived_classes.setText('Derived classes: -') self.struct.setText('Struct: -') self.vtable_range.setText('VTable: -') self.vtable.setRowCount(0) self.methods.setRowCount(0) else: self.setEnabled(True) self.name.setText('Name: %s' % self.edit_class.name) self.base_class.setText( 'Base class: %s' % (self.edit_class.base.name if self.edit_class.base is not None else 'None')) derived_classes_txts = [] for dc in self.edit_class.derived: derived_classes_txts.append(dc.name) derived_classes_txt = ', '.join(derived_classes_txts) if not derived_classes_txt: derived_classes_txt = 'None' self.derived_classes.setText('Derived classes: %s' % derived_classes_txt) if self.edit_class.struct_id == idc.BADADDR: struct_txt = 'Not set' else: struct_txt = '%s (%d)' % ( idc.get_struc_name(self.edit_class.struct_id), idc.get_struc_idx(self.edit_class.struct_id)) self.struct.setText('Struct: %s' % struct_txt) if self.edit_class.vtable_start is None or self.edit_class.vtable_end is None: vtable_range_txt = 'Not set' else: vtable_range_txt = '0x%X - 0x%X' % ( self.edit_class.vtable_start, self.edit_class.vtable_end) self.vtable_range.setText('VTable: %s' % vtable_range_txt) self.vtable.setRowCount(len(self.edit_class.vmethods)) for idx, vm in enumerate(self.edit_class.vmethods): self.vtable.setItem(idx, 0, QtWidgets.QTableWidgetItem(str(idx))) self.vtable.setItem( idx, 1, QtWidgets.QTableWidgetItem(( "0x%X" % vm.ea) if vm.ea != idc.BADADDR else '-')) self.vtable.setItem( idx, 2, QtWidgets.QTableWidgetItem(vm.get_signature())) self.vtable.setItem(idx, 3, QtWidgets.QTableWidgetItem(vm.type_name())) # This way of doing won't work when allowing sorting self.methods.setRowCount(len(self.edit_class.methods)) for idx, m in enumerate(self.edit_class.methods): address_item = QtWidgets.QTableWidgetItem(m.ea) address_item.setData(QtCore.Qt.DisplayRole, "0x%X" % m.ea) address_item.setData(QtCore.Qt.UserRole, m) self.methods.setItem(idx, 0, address_item) self.methods.setItem( idx, 1, QtWidgets.QTableWidgetItem(m.get_signature()))