def clear_database(self): if ask_yes_no( 'Are you really sure that you want to clear the Classy databse?\n', False): database.get().clear() self.gui.update_fields() idaapi.refresh_idaview_anyway()
def s_create(): db = database.get() name = idaapi.ask_str('', idaapi.HIST_IDENT,'Enter a class name') if name is None: return None if name in database.get().classes_by_name: idaapi.warning('That name is already used.') return None if not Class.s_name_is_valid(name): idaapi.warning('The class name "%s" is invalid.' % name) return None base_class = None base_name = idaapi.ask_str('', idaapi.HIST_IDENT,'Enter a base class name (leave empty for none)') if base_name is None: return None if base_name: if base_name not in db.classes_by_name: idaapi.warning('The class "%s" is not in the database.' % base_name) return None else: base_class = db.classes_by_name[base_name] if not base_class.can_be_derived(): idaapi.warning('The class %s cannot be derived because the VTable is not setup correctly' % base_class.name) return None return Class(name, base_class) '''
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 reload_tree(self): db = database.get() self.items_by_class = {} self.class_tree.clear() for c in db.root_classes: self.add_child_class_item(self.class_tree, c)
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 set_autosave_interval(self): db = database.get() new_interval, ok_pressed = QtWidgets.QInputDialog.getInt( None, 'Set autosave interval', 'Autosave interval [seconds]:', db.autosave_interval, 10) if ok_pressed: db.set_autosave_interval(new_interval)
def handle_remove(self): item = self.list.currentItem() if item is None: return t = item.data(QtCore.Qt.UserRole) del database.get().typedefs[t] self.update_list()
def update_list(self): db = database.get() self.list.clear() for t in db.typedefs: item = QtWidgets.QListWidgetItem('typedef %s %s;' % (db.typedefs[t], t)) item.setData(QtCore.Qt.UserRole, t) self.list.addItem(item)
def export_all_symbols(self): path = QtWidgets.QFileDialog.getSaveFileName( None, 'Export all symbols', '', 'Linker script (*.ld);;All files (*)') if not path[0]: return f = open(path[0], 'w') f.write(database.get().generate_symbols()) f.close()
def set_signature(self, name, args, return_type='void', is_const=False, ctor_type=1, dtor_type=1): signature = Method.s_make_signature(self.owner, name, args, is_const, return_type) itanium_mangler.mangle_function(signature, database.get().typedefs, ctor_type, dtor_type) # throws excption when invalid self.name = name self.args = args self.return_type = return_type self.is_const = is_const self.ctor_type = ctor_type self.dtor_type = dtor_type self.refresh()
def unlink(self): if self.owner and self in self.owner.methods: self.owner.methods.remove(self) self.owner = None if self.ea != idc.BADADDR: del database.get().known_methods[self.ea] idc.set_name(self.ea, '', idc.SN_CHECK) idc.set_func_cmt(self.ea, '', False)
def update_signature(self): self.return_type = self.return_type_w.text().encode( 'ascii', 'replace').strip().decode() or 'void' self.owner_type = self.owner_type_w.text().encode( 'ascii', 'replace').strip().decode() self.name = self.name_w.text().encode('ascii', 'replace').strip().decode() self.args = self.args_w.text().encode('ascii', 'replace').strip().decode() self.is_const = self.is_const_w.isChecked() self.ctor_type = self.ctor_type_w.currentIndex() + 1 self.dtor_type = self.dtor_type_w.currentIndex() # ctors and dtors shouldn't have a return type, dtors shouldn't have args if self.owner_type: owner_last_type = self.owner_type.split('::')[-1] if self.name == owner_last_type: self.return_type = '' elif self.name == '~' + owner_last_type: self.return_type = '' self.args = '' signature_segs = [] if self.return_type: signature_segs.append(self.return_type) signature_segs.append(' ') if self.owner_type: signature_segs.append(self.owner_type) signature_segs.append('::') signature_segs.append(self.name) signature_segs.append('(') signature_segs.append(self.args) signature_segs.append(')') if self.is_const: signature_segs.append(' const') self.signature = ''.join(signature_segs) self.signature_w.setText(self.signature) self.is_signature_valid = False self.mangled = None try: if not self.name or (' ' in self.name): raise ValueError('Name is invalid') self.mangled = itanium_mangler.mangle_function( self.signature, database.get().typedefs, self.ctor_type, self.dtor_type) self.is_signature_valid = True self.status = '' self.status_w.setText('Valid') except (ValueError, NotImplementedError) as e: self.status = str(e) self.status_w.setText('Invalid: ' + self.status) self.mangled_w.setText(str(self.mangled))
def __init__(self, ea, owner, name): self.ea = ea self.owner = owner self.name = name self.args = '' self.return_type = 'void' self.is_const = False self.ctor_type = 1 self.dtor_type = 1 if ea != idc.BADADDR: database.get().known_methods[ea] = self
def create_open_database(self): db = database.get() try: db.open() except Exception as e: idaapi.warning('Creating/opening Classy database failed: %s' % str(e)) if db.is_open: self.menumgr.set_state(MenuState.DATABASE_OPENED) else: self.menumgr.set_state(MenuState.DATABASE_CLOSED)
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 try_set_typedef(self, t): val = idaapi.ask_str('', idaapi.HIST_IDENT, 'Enter typedef value') if val is None: return val_segs = val.split() itanium_mangler.fix_multi_seg_types(val_segs) if len(val_segs) != 1 or ( val_segs[0] not in itanium_mangler.BUILTIN_TYPES and not itanium_mangler.check_identifier(val_segs[0])): idaapi.warning('That value is invalid.') return database.get().typedefs[t] = val.strip() self.update_list()
def save_as(self): db = database.get() path = QtWidgets.QFileDialog.getSaveFileName( None, 'Export Classy database', '', 'Classy database (*.cdb)') if not path[0]: return # Check for user idiocy if os.path.normpath(path[0]) == os.path.normpath(db.path): idaapi.warning( 'You cannot overwrite the currently active Classy database.') return db.save_as(path[0])
def set_struct_id(self, new_struct_id, delete_orphaned=False): db = database.get() if self.struct_id == new_struct_id: return if new_struct_id in db.classes_by_struct_id: raise ValueError('The struct is already assigned to the class %s' % db.classes_by_struct_id[new_struct_id]).name self.unlink_struct(delete_orphaned) self.struct_id = new_struct_id if self.struct_id != idc.BADADDR: db.classes_by_struct_id[self.struct_id] = self self.refresh()
def handle_add(self): t = idaapi.ask_str('', idaapi.HIST_IDENT, 'Enter typedef name') if t is None: return if t in database.get().typedefs: idaapi.warning('That name is already used.') return if not itanium_mangler.check_identifier(t): idaapi.warning('That name is invalid.') return # Todo: prevent overwriting builtins self.try_set_typedef(t)
def term(self): try: db = database.get() if db.is_open and ask_yes_no( 'Do you want to save the classy database?', True): db.save() db.close() database.destroy_instance() except ValueError: # Database instance might not be created pass self.menumgr.cleanup() log('Unloaded')
def handle_remove_method(self): db = database.get() if self.edit_class is None: return row_item = self.methods.item(self.methods.currentRow(), 0) if row_item is None: return m = row_item.data(QtCore.Qt.UserRole) if type( m ) != database_entries.Method or m not in self.edit_class.methods: return m.unlink() self.update_fields()
def unlink(self, delete_orphaned_struct=False): if len(self.derived) > 0: raise ValueError('Cannot unlink classes with derived classes') for m in self.methods: m.unlink() for vm in self.vmethods: if vm.owner == self: vm.unlink() self.unlink_struct(delete_orphaned_struct) if self.base is not None: self.base.derived.remove(self) db = database.get() del db.classes_by_name[self.name] if self.base is None: db.root_classes.remove(self)
def handle_set_name(self): if self.edit_class is None: return new_name = idaapi.ask_str(self.edit_class.name, idaapi.HIST_IDENT, 'Enter a class name') if new_name is None or new_name == self.edit_class.name: return if new_name in database.get().classes_by_name: idaapi.warning('That name is already used.') return if not database_entries.Class.s_name_is_valid(new_name): idaapi.warning('The class name "%s" is invalid.' % new_name) return self.edit_class.rename(new_name) self.update_fields() self.parent_gui.update_class(self.edit_class)
def edit_deleted_virtual_vals(self): db = database.get() txt = idaapi.ask_str( ', '.join([('0x%X' % x) for x in db.deleted_virtual_vals]), idaapi.HIST_IDENT, "Enter deleted virtual values") if txt is None or not txt.strip(): return new_deleted_virtual_vals = [] for s in txt.split(','): try: new_deleted_virtual_vals.append(int(s, 0)) except ValueError: idaapi.warning( 'Parsing "%s" failed. Deleted virtual values were not modified.' % s) return db.deleted_virtual_vals = new_deleted_virtual_vals
def handle_add_method(self): db = database.get() if self.edit_class is None: return sel_ea = idc.get_screen_ea() if sel_ea == idc.BADADDR: return existing_method = None if sel_ea in db.known_methods: existing_method = db.known_methods[sel_ea] if type(existing_method) != database_entries.Method: idaapi.warning("Cannot unlink function that is in a VTable") return name = idc.get_name(sel_ea, 0) if name.startswith('_Z'): # Ignore already mangled names name = '' if not name: name = 'sub_%X' % sel_ea dlg = SignatureDialog(name=name, owner_type=self.edit_class.name, fixed_owner_type=True) if dlg.exec_() != QtWidgets.QDialog.Accepted: return if existing_method is not None: existing_method.unlink() method = database_entries.Method(sel_ea, self.edit_class, dlg.name) method.set_signature(dlg.name, dlg.args, dlg.return_type, dlg.is_const, dlg.ctor_type, dlg.dtor_type) self.edit_class.methods.append(method) method.refresh() self.update_fields()
def __init__(self, name, base): self.name = name self.base = base self.derived = [] self.struct_id = idc.BADADDR if self.base is not None: self.base.derived.append(self) self.methods = [] self.vtable_start = None self.vtable_end = None self.vmethods = [] self.reset_vtable() db = database.get() db.classes_by_name[name] = self if self.base is None: db.root_classes.append(self)
def save(self): database.get().save()
def s_is_pure_virtual_dst(dst): return dst in database.get().pure_virtual_vals
def s_is_deleted_virtual_dst(dst): return dst in database.get().deleted_virtual_vals
def refresh_all(): db = database.get() for c in db.classes_by_name.values(): c.refresh()