From a3da0245598e94598e37a347e50aaba3cc5049bb Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 18 Aug 2020 11:55:15 -0400 Subject: [PATCH 1/3] Helper.py: Fix error when get_array_element returns int. --- HexRaysPyTools/core/helper.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/HexRaysPyTools/core/helper.py b/HexRaysPyTools/core/helper.py index 20275d3..055305a 100644 --- a/HexRaysPyTools/core/helper.py +++ b/HexRaysPyTools/core/helper.py @@ -337,7 +337,12 @@ def load_long_str_from_idb(array_name): if id == -1: return None max_idx = idc.get_last_index(idc.AR_STR, id) - result = [idc.get_array_element(idc.AR_STR, id, idx) for idx in range(max_idx + 1)] + result = [] + for idx in range(max_idx + 1): + e = idc.get_array_element(idc.AR_STR, id, idx) + if type(e) == int: + e = e.to_bytes((e.bit_length() + 7) // 8, 'little') + result.append(e) return b"".join(result).decode("utf-8") def create_padding_udt_member(offset, size): From 1486c64eae2fe7333c66c94070605917256c077d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20C=C3=B4t=C3=A9?= Date: Wed, 11 Jun 2025 22:28:01 +0200 Subject: [PATCH 2/3] Port to IDA 9.x. --- HexRaysPyTools/callbacks/scanners.py | 2 +- HexRaysPyTools/core/const.py | 2 +- HexRaysPyTools/core/helper.py | 5 +++-- readme.md | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/HexRaysPyTools/callbacks/scanners.py b/HexRaysPyTools/callbacks/scanners.py index c32a948..9d818d5 100644 --- a/HexRaysPyTools/callbacks/scanners.py +++ b/HexRaysPyTools/callbacks/scanners.py @@ -127,7 +127,7 @@ def activate(self, ctx): NewDeepSearchVisitor(cfunc, 0, obj, cache.temporary_structure).process() def update(self, ctx): - if ctx.form_type == idaapi.BWN_FUNCS: + if ctx.widget_type == idaapi.BWN_FUNCS: idaapi.attach_action_to_popup(ctx.widget, None, self.name) return idaapi.AST_ENABLE_FOR_WIDGET return idaapi.AST_DISABLE_FOR_WIDGET diff --git a/HexRaysPyTools/core/const.py b/HexRaysPyTools/core/const.py index 389bc50..c72c26b 100644 --- a/HexRaysPyTools/core/const.py +++ b/HexRaysPyTools/core/const.py @@ -33,7 +33,7 @@ def init(): PX_WORD_TINFO, DUMMY_FUNC, CONST_PCHAR_TINFO, CHAR_TINFO, PCHAR_TINFO, CONST_VOID_TINFO, \ WORD_TINFO, PWORD_TINFO, EA64, EA_SIZE - EA64 = idaapi.get_inf_structure().is_64bit() + EA64 = idaapi.inf_is_64bit() EA_SIZE = 8 if EA64 else 4 VOID_TINFO = idaapi.tinfo_t(idaapi.BT_VOID) diff --git a/HexRaysPyTools/core/helper.py b/HexRaysPyTools/core/helper.py index 055305a..d58a0d7 100644 --- a/HexRaysPyTools/core/helper.py +++ b/HexRaysPyTools/core/helper.py @@ -2,6 +2,7 @@ import logging import idaapi +import ida_ida import idc import HexRaysPyTools.core.cache as cache @@ -20,7 +21,7 @@ def is_imported_ea(ea): def is_code_ea(ea): - if idaapi.cvar.inf.procname == "ARM": + if ida_ida.inf_get_procname() == "ARM": # In case of ARM code in THUMB mode we sometimes get pointers with thumb bit set flags = idaapi.get_full_flags(ea & -2) # flags_t else: @@ -38,7 +39,7 @@ def get_ptr(ea): if const.EA64: return idaapi.get_64bit(ea) ptr = idaapi.get_32bit(ea) - if idaapi.cvar.inf.procname == "ARM": + if ida_ida.inf_get_procname() == "ARM": ptr &= -2 # Clear thumb bit return ptr diff --git a/readme.md b/readme.md index 1a702ac..31473cf 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ About The plugin assists in the creation of classes/structures and detection of virtual tables. It also facilitates transforming decompiler output faster and allows to do some stuff which is otherwise impossible. -**Note**: The plugin supports IDA Pro 7.x with Python 2/3. +**Note**: The plugin supports IDA Pro 9.x with Python 3. Installation ============ From b19e1bb4e0541098362d70d9802f26e7fa0afc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20C=C3=B4t=C3=A9?= Date: Tue, 15 Jul 2025 15:28:25 -0400 Subject: [PATCH 3/3] Fix issues with import_type being changed in IDA 9. --- HexRaysPyTools/callbacks/negative_offsets.py | 4 ++-- .../callbacks/new_field_creation.py | 4 ++-- HexRaysPyTools/callbacks/recasts.py | 6 ++--- HexRaysPyTools/callbacks/structs_by_size.py | 2 +- HexRaysPyTools/core/classes.py | 22 ++++++++--------- HexRaysPyTools/core/helper.py | 8 +++---- HexRaysPyTools/core/structure_graph.py | 2 +- HexRaysPyTools/core/temporary_structure.py | 24 +++++++++++-------- HexRaysPyTools/core/type_library.py | 12 +++++----- 9 files changed, 44 insertions(+), 40 deletions(-) diff --git a/HexRaysPyTools/callbacks/negative_offsets.py b/HexRaysPyTools/callbacks/negative_offsets.py index 2c5dedc..d6ffc87 100644 --- a/HexRaysPyTools/callbacks/negative_offsets.py +++ b/HexRaysPyTools/callbacks/negative_offsets.py @@ -25,7 +25,7 @@ def _parse_magic_comment(lvar): structure_name, offset = m.group(1).split('+') offset = int(offset) parent_tinfo = idaapi.tinfo_t() - if parent_tinfo.get_named_type(idaapi.cvar.idati, structure_name) and parent_tinfo.get_size() > offset: + if parent_tinfo.get_named_type(idaapi.get_idati(), structure_name) and parent_tinfo.get_size() > offset: member_name = dict(find_deep_members(parent_tinfo, lvar.type().get_pointed_object())).get(offset, None) if member_name: return NegativeLocalInfo(lvar.type().get_pointed_object(), parent_tinfo, offset, member_name) @@ -220,7 +220,7 @@ def visit_expr(self, expression): parent_name = expression.a[1].helper member_name = expression.a[2].helper parent_tinfo = idaapi.tinfo_t() - if not parent_tinfo.get_named_type(idaapi.cvar.idati, parent_name): + if not parent_tinfo.get_named_type(idaapi.get_idati(), parent_name): return 0 udt_data = idaapi.udt_type_data_t() parent_tinfo.get_udt_details(udt_data) diff --git a/HexRaysPyTools/callbacks/new_field_creation.py b/HexRaysPyTools/callbacks/new_field_creation.py index 7112feb..280d13d 100644 --- a/HexRaysPyTools/callbacks/new_field_creation.py +++ b/HexRaysPyTools/callbacks/new_field_creation.py @@ -105,7 +105,7 @@ def activate(self, ctx): udt_data.insert(iterator, helper.create_padding_udt_member(offset, idx)) struct_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) - struct_tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.BTF_STRUCT, struct_name) + struct_tinfo.set_numbered_type(idaapi.get_idati(), ordinal, idaapi.BTF_STRUCT, struct_name) hx_view.refresh_view(True) @staticmethod @@ -127,7 +127,7 @@ def parse_declaration(declaration): _, tp, fld = result tinfo = idaapi.tinfo_t() - tinfo.deserialize(idaapi.cvar.idati, tp, fld, None) + tinfo.deserialize(idaapi.get_idati(), tp, fld, None) if arr_size: assert tinfo.create_array(tinfo, int(arr_size)) return tinfo, field_name diff --git a/HexRaysPyTools/callbacks/recasts.py b/HexRaysPyTools/callbacks/recasts.py index d86b44f..78ebcd3 100644 --- a/HexRaysPyTools/callbacks/recasts.py +++ b/HexRaysPyTools/callbacks/recasts.py @@ -179,8 +179,8 @@ def activate(self, ctx): elif isinstance(ri, RecastStructure): tinfo = idaapi.tinfo_t() - tinfo.get_named_type(idaapi.cvar.idati, ri.structure_name) - ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, ri.structure_name) + tinfo.get_named_type(idaapi.get_idati(), ri.structure_name) + ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), ri.structure_name) if ordinal == 0: return 0 @@ -196,7 +196,7 @@ def activate(self, ctx): tinfo.get_udt_details(udt_data) udt_data[idx].type = ri.recast_tinfo tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) - tinfo.set_numbered_type(idaapi.cvar.idati, ordinal, idaapi.NTF_REPLACE, ri.structure_name) + tinfo.set_numbered_type(idaapi.get_idati(), ordinal, idaapi.NTF_REPLACE, ri.structure_name) else: raise NotImplementedError diff --git a/HexRaysPyTools/callbacks/structs_by_size.py b/HexRaysPyTools/callbacks/structs_by_size.py index 3b2b432..0e98d36 100644 --- a/HexRaysPyTools/callbacks/structs_by_size.py +++ b/HexRaysPyTools/callbacks/structs_by_size.py @@ -57,7 +57,7 @@ def activate(self, ctx): operand_number = number_format_old.opnum number_format_new.opnum = operand_number number_format_new.props = number_format_old.props - number_format_new.type_name = idaapi.get_numbered_type_name(idaapi.cvar.idati, ordinal) + number_format_new.type_name = idaapi.get_numbered_type_name(idaapi.get_idati(), ordinal) c_function = hx_view.cfunc number_formats = c_function.numforms # type: idaapi.user_numforms_t diff --git a/HexRaysPyTools/core/classes.py b/HexRaysPyTools/core/classes.py index e777dc9..59b8ee8 100644 --- a/HexRaysPyTools/core/classes.py +++ b/HexRaysPyTools/core/classes.py @@ -65,7 +65,7 @@ def setData(self, column, value): split = value.split('(') if len(split) == 2: value = split[0] + ' ' + self.name + '(' + split[1] + ';' - if idaapi.parse_decl(tinfo, idaapi.cvar.idati, value, idaapi.PT_TYP) is not None: + if idaapi.parse_decl(tinfo, idaapi.get_idati(), value, idaapi.PT_TYP) is not None: if tinfo.is_func(): tinfo.create_ptr(tinfo) if tinfo.dstr() != self.tinfo.dstr(): @@ -110,7 +110,7 @@ def set_first_argument_type(self, name): func_tinfo = self.tinfo.get_pointed_object() class_tinfo = idaapi.tinfo_t() if func_tinfo.get_func_details(func_data) and func_tinfo.get_nargs() and \ - class_tinfo.get_named_type(idaapi.cvar.idati, name): + class_tinfo.get_named_type(idaapi.get_idati(), name): class_tinfo.create_ptr(class_tinfo) first_arg_tinfo = func_data[0].type if (first_arg_tinfo.is_ptr() and first_arg_tinfo.get_pointed_object().is_udt()) or \ @@ -175,7 +175,7 @@ def update(self): if self.modified: vtable_tinfo = idaapi.tinfo_t() udt_data = idaapi.udt_type_data_t() - vtable_tinfo.get_numbered_type(idaapi.cvar.idati, self.ordinal) + vtable_tinfo.get_numbered_type(idaapi.get_idati(), self.ordinal) vtable_tinfo.get_udt_details(udt_data) self.tinfo = vtable_tinfo self.name = vtable_tinfo.dstr() @@ -197,7 +197,7 @@ def update_local_type(self): udt_member.type = virtual_function.tinfo virtual_function.commit() final_tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) - final_tinfo.set_numbered_type(idaapi.cvar.idati, self.ordinal, idaapi.NTF_REPLACE, self.name) + final_tinfo.set_numbered_type(idaapi.get_idati(), self.ordinal, idaapi.NTF_REPLACE, self.name) self.modified = False else: print("[ERROR] Something have been modified in Local types. Please refresh this view") @@ -219,11 +219,11 @@ def modified(self, value): @staticmethod def create(tinfo, class_): - ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, tinfo.dstr()) + ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), tinfo.dstr()) if ordinal == 0: - if idaapi.import_type(idaapi.cvar.idati, -1, tinfo.dstr(), 0) == idaapi.BADNODE: + if idc.import_type(-1, tinfo.dstr()) == idaapi.BADNODE: raise ImportError("unable to import type to idb ({})".format(tinfo.dstr())) - ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, tinfo.dstr()) + ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), tinfo.dstr()) result = all_virtual_tables.get(ordinal) if result: @@ -291,7 +291,7 @@ def __init__(self, name, tinfo, ordinal): @staticmethod def create_class(ordinal): tinfo = idaapi.tinfo_t() - tinfo.get_numbered_type(idaapi.cvar.idati, ordinal) + tinfo.get_numbered_type(idaapi.get_idati(), ordinal) vtables = {} if tinfo.is_struct(): udt_data = idaapi.udt_type_data_t() @@ -337,7 +337,7 @@ def update_local_type(self): tinfo = idaapi.tinfo_t() self.tinfo.get_udt_details(udt_data) tinfo.create_udt(udt_data, idaapi.BTF_STRUCT) - tinfo.set_numbered_type(idaapi.cvar.idati, self.ordinal, idaapi.NTF_REPLACE, self.name) + tinfo.set_numbered_type(idaapi.get_idati(), self.ordinal, idaapi.NTF_REPLACE, self.name) self.modified = False def set_first_argument_type(self, class_name): @@ -388,7 +388,7 @@ def children(self): @property def tinfo(self): tinfo = idaapi.tinfo_t() - tinfo.get_numbered_type(idaapi.cvar.idati, self.ordinal) + tinfo.get_numbered_type(idaapi.get_idati(), self.ordinal) return tinfo def open_function(self): @@ -450,7 +450,7 @@ def setupModelData(self, root): all_virtual_tables.clear() classes = [] - for ordinal in range(1, idaapi.get_ordinal_qty(idaapi.cvar.idati)): + for ordinal in range(1, idaapi.get_ordinal_qty(idaapi.get_idati())): result = Class.create_class(ordinal) if result: classes.append(result) diff --git a/HexRaysPyTools/core/helper.py b/HexRaysPyTools/core/helper.py index d58a0d7..1cf57df 100644 --- a/HexRaysPyTools/core/helper.py +++ b/HexRaysPyTools/core/helper.py @@ -50,7 +50,7 @@ def get_ordinal(tinfo): if ordinal == 0: t = idaapi.tinfo_t() struct_name = tinfo.dstr().split()[-1] # Get rid of `struct` prefix or something else - t.get_named_type(idaapi.cvar.idati, struct_name) + t.get_named_type(idaapi.get_idati(), struct_name) ordinal = t.get_ordinal() return ordinal @@ -176,7 +176,7 @@ def get_nice_pointed_object(tinfo): name = tinfo.dstr() if name[0] == 'P': pointed_tinfo = idaapi.tinfo_t() - if pointed_tinfo.get_named_type(idaapi.cvar.idati, name[1:]): + if pointed_tinfo.get_named_type(idaapi.get_idati(), name[1:]): if tinfo.get_pointed_object().equals_to(pointed_tinfo): return pointed_tinfo except TypeError: @@ -248,9 +248,9 @@ def import_structure(name, tinfo): if idc.parse_decl(cdecl_typedef, idaapi.PT_TYP) is None: return 0 - previous_ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, name) + previous_ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), name) if previous_ordinal: - idaapi.del_numbered_type(idaapi.cvar.idati, previous_ordinal) + idaapi.del_numbered_type(idaapi.get_idati(), previous_ordinal) ordinal = idaapi.idc_set_local_type(previous_ordinal, cdecl_typedef, idaapi.PT_TYP) else: ordinal = idaapi.idc_set_local_type(-1, cdecl_typedef, idaapi.PT_TYP) diff --git a/HexRaysPyTools/core/structure_graph.py b/HexRaysPyTools/core/structure_graph.py index d64cd39..735ee48 100644 --- a/HexRaysPyTools/core/structure_graph.py +++ b/HexRaysPyTools/core/structure_graph.py @@ -100,7 +100,7 @@ def get_tinfo_by_ordinal(ordinal): if local_typestring: p_type, fields = local_typestring local_tinfo = idaapi.tinfo_t() - local_tinfo.deserialize(idaapi.cvar.idati, p_type, fields) + local_tinfo.deserialize(idaapi.get_idati(), p_type, fields) return local_tinfo return None diff --git a/HexRaysPyTools/core/temporary_structure.py b/HexRaysPyTools/core/temporary_structure.py index 806c6bc..9559b49 100644 --- a/HexRaysPyTools/core/temporary_structure.py +++ b/HexRaysPyTools/core/temporary_structure.py @@ -264,16 +264,16 @@ def import_to_structures(self, ask=False): cdecl_typedef = idaapi.ask_text(0x10000, cdecl_typedef, "The following new type will be created") if not cdecl_typedef: return - previous_ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, self.vtable_name) + previous_ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), self.vtable_name) if previous_ordinal: - idaapi.del_numbered_type(idaapi.cvar.idati, previous_ordinal) + idaapi.del_numbered_type(idaapi.get_idati(), previous_ordinal) ordinal = idaapi.idc_set_local_type(previous_ordinal, cdecl_typedef, idaapi.PT_TYP) else: ordinal = idaapi.idc_set_local_type(-1, cdecl_typedef, idaapi.PT_TYP) if ordinal: print("[Info] Virtual table " + self.vtable_name + " added to Local Types") - return idaapi.import_type(idaapi.cvar.idati, -1, self.vtable_name) + return idc.import_type(-1, self.vtable_name) else: print("[Error] Failed to create virtual table " + self.vtable_name) print("*" * 100) @@ -413,7 +413,7 @@ def activate(self, temp_struct): return _, tp, fld = result tinfo = idaapi.tinfo_t() - tinfo.deserialize(idaapi.cvar.idati, tp, fld, None) + tinfo.deserialize(idaapi.get_idati(), tp, fld, None) self.tinfo = tinfo self.is_array = False @@ -557,8 +557,12 @@ def pack(self, start=0, stop=None): cdecl = idaapi.ask_text(0x10000, '#pragma pack(push, 1)\n' + cdecl, "The following new type will be created") if cdecl: - structure_name = idaapi.idc_parse_decl(idaapi.cvar.idati, cdecl, idaapi.PT_TYP)[0] - previous_ordinal = idaapi.get_type_ordinal(idaapi.cvar.idati, structure_name) + structure = idaapi.idc_parse_decl(idaapi.get_idati(), cdecl, idaapi.PT_TYP) + if structure is None: + print("[Warning] Invalid declaration '{:s}'".format(cdecl)) + return + structure_name = structure[0] + previous_ordinal = idaapi.get_type_ordinal(idaapi.get_idati(), structure_name) if previous_ordinal: reply = QtWidgets.QMessageBox.question( @@ -568,7 +572,7 @@ def pack(self, start=0, stop=None): QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No ) if reply == QtWidgets.QMessageBox.Yes: - idaapi.del_numbered_type(idaapi.cvar.idati, previous_ordinal) + idaapi.del_numbered_type(idaapi.get_idati(), previous_ordinal) ordinal = idaapi.idc_set_local_type(previous_ordinal, cdecl, idaapi.PT_TYP) else: return @@ -576,7 +580,7 @@ def pack(self, start=0, stop=None): ordinal = idaapi.idc_set_local_type(-1, cdecl, idaapi.PT_TYP) if ordinal: print("[Info] New type {0} was added to Local Types".format(structure_name)) - tid = idaapi.import_type(idaapi.cvar.idati, -1, structure_name) + tid = idc.import_type(-1, structure_name) if tid: tinfo = idaapi.create_typedef(structure_name) ptr_tinfo = idaapi.tinfo_t() @@ -657,8 +661,8 @@ def get_recognized_shape(self, start=0, stop=-1): return min_size = enabled_items[-1].offset + enabled_items[-1].size - base tinfo = idaapi.tinfo_t() - for ordinal in range(1, idaapi.get_ordinal_qty(idaapi.cvar.idati)): - tinfo.get_numbered_type(idaapi.cvar.idati, ordinal) + for ordinal in range(1, idaapi.get_ordinal_qty(idaapi.get_idati())): + tinfo.get_numbered_type(idaapi.get_idati(), ordinal) if tinfo.is_udt() and tinfo.get_size() >= min_size: is_found = False for offset in offsets: diff --git a/HexRaysPyTools/core/type_library.py b/HexRaysPyTools/core/type_library.py index e9ed24f..85cc37b 100644 --- a/HexRaysPyTools/core/type_library.py +++ b/HexRaysPyTools/core/type_library.py @@ -40,10 +40,10 @@ def choose_til(): # type: () -> (idaapi.til_t, int, bool) """ Creates a list of loaded libraries, asks user to take one of them and returns it with information about max ordinal and whether it's local or imported library """ - idati = idaapi.cvar.idati + idati = idaapi.get_idati() list_type_library = [(idati, idati.name, idati.desc)] - for idx in range(idaapi.cvar.idati.nbases): - type_library = idaapi.cvar.idati.base(idx) # type: idaapi.til_t + for idx in range(idaapi.get_idati().nbases): + type_library = idaapi.get_idati().base(idx) # type: idaapi.til_t list_type_library.append((type_library, type_library.name, type_library.desc)) library_chooser = forms.MyChoose( @@ -64,8 +64,8 @@ def choose_til(): def import_type(library, name): - if library.name != idaapi.cvar.idati.name: - last_ordinal = idaapi.get_ordinal_qty(idaapi.cvar.idati) - type_id = idaapi.import_type(library, -1, name) # tid_t + if library.name != idaapi.get_idati().name: + last_ordinal = idaapi.get_ordinal_qty(idaapi.get_idati()) + type_id = library.import_type(name) if type_id != idaapi.BADORD: return last_ordinal