1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
| import atexit import json import os CLI_AVAILABLE = True try: import idapro except ImportError: CLI_AVAILABLE = False import idaapi import ida_bytes import ida_funcs import ida_name import ida_typeinf import ida_kernwin
def iterable(obj): if obj is None: return False
try: iter(obj) except Exception: return False else: return True
def resync_local_types(): def is_autosync(name, tif): return idaapi.get_ordinal_from_idb_type(name, tif.get_decltype().to_bytes(1, "little")) != -1
for ord in range(1, idaapi.get_ordinal_qty(None)): t = idaapi.tinfo_t() t.get_numbered_type(None, ord) typename = t.get_type_name() if typename.startswith("#"): continue
autosync = is_autosync(typename, t) idaapi.import_type(None, -1, typename, idaapi.IMPTYPE_OVERRIDE) if autosync: continue struc = idaapi.get_struc(idaapi.get_struc_id(typename)) if not struc: continue struc.ordinal = -1 idaapi.save_struc(struc, False)
def get_type_by_name(name): t = idaapi.tinfo_t() t.get_named_type(None, name) return t
def set_function_signature(ea, typedef): idaapi.apply_type(ea, ida_typeinf.parse_decl(typedef, ida_typeinf.PT_SIL), idaapi.TINFO_DEFINITE)
def import_primitives(): type_map = { "BUILTIN_STRING": "string", "uint8_t": "uint8", "uint16_t": "uint16", "uint32_t": "uint32", "uint64_t": "uint64", "int8_t": "int8", "int16_t": "int16", "int32_t": "int32", "double": "float64", "float": "float32", "complex64_t": "complex64", "complex128_t": "complex128", "void*": "uintptr", "uint8": "byte", "int32": "rune", "int": "void*", }
ida_typeinf.idc_parse_types("struct BUILTIN_INTERFACE{void *tab;void *data;};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL) ida_typeinf.idc_parse_types("struct BUILTIN_STRING{char *ptr;size_t len;};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL)
ida_typeinf.idc_parse_types("struct complex64_t{float real;float imag;};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL) ida_typeinf.idc_parse_types("struct complex128_t{double real;double imag;};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL)
for ida_type, gotype in type_map.items(): ida_typeinf.idc_parse_types(f"typedef {ida_type} {gotype};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL)
def forward_declare_structs(types): for typ in types: if typ["Kind"] == "Struct": ida_typeinf.idc_parse_types(f"struct {typ['CStr']};", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL)
def main(json_file): with open(json_file, "r", encoding="utf-8") as rp: buf = rp.read()
hints = json.loads(buf) if iterable(hints["UserFunctions"]): for func in hints["UserFunctions"]: ida_bytes.del_items(func["Start"]) ida_funcs.add_func(func["Start"]) print("Renaming %s to %s" % (hex(func["Start"]), func["FullName"])) idaapi.add_func(func["Start"], func["End"]) idaapi.set_name(func["Start"], func["FullName"], idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
if iterable(hints["StdFunctions"]): for func in hints["StdFunctions"]: print("Renaming %s to %s" % (hex(func["Start"]), func["FullName"])) ida_bytes.del_items(func["Start"]) ida_funcs.add_func(func["Start"]) idaapi.add_func(func["Start"], func["End"]) idaapi.set_name(func["Start"], func["FullName"], idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
if iterable(hints["Types"]): import_primitives()
forward_declare_structs(hints["Types"])
for typ in hints["Types"][::-1]: if typ.get("CReconstructed"): errors = ida_typeinf.idc_parse_types(typ["CReconstructed"] + ";", ida_typeinf.HTI_PAKDEF | ida_typeinf.HTI_DCL) if errors > 0: print(typ["CReconstructed"], "failed to import")
for typ in hints["Types"]: print("Renaming %s to %s" % (hex(typ["VA"]), typ["Str"])) idaapi.set_name(typ["VA"], typ["Str"], idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
ida_bytes.del_items(typ["VA"], 0, 4) abi_typ = get_type_by_name("abi_Type") idaapi.apply_tinfo(typ["VA"], abi_typ, idaapi.TINFO_DEFINITE)
if iterable(hints["Interfaces"]): for typ in hints["Interfaces"]: print("Renaming %s to %s" % (hex(typ["VA"]), typ["Str"])) idaapi.set_name(typ["VA"], typ["Str"], idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
ida_bytes.del_items(typ["VA"], 0, 4) abi_typ = get_type_by_name("abi_Type") idaapi.apply_tinfo(typ["VA"], abi_typ, idaapi.TINFO_DEFINITE)
if hints["TabMeta"] is not None: tabmeta = hints["TabMeta"] va = tabmeta["VA"] if va is not None and va != 0: idaapi.set_name(va, "runtime_pclntab", idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
if hints["ModuleMeta"] is not None: modmeta = hints["ModuleMeta"] va = modmeta["VA"] if va is not None and va != 0: idaapi.set_name(va, "runtime_firstmoduledata", idaapi.SN_NOWARN | idaapi.SN_NOCHECK | ida_name.SN_FORCE)
def getargs() -> str: import argparse
parser = argparse.ArgumentParser(description="Apply GoReSym renaming and type hints to an IDA database.") parser.add_argument("binary", help="Path to the Go binary file.") parser.add_argument("json_file", help="Path to the GoReSym output JSON file.") args = parser.parse_args() assert os.path.isfile(args.json_file) assert os.path.isfile(args.binary) idapro.open_database(args.binary, run_auto_analysis=True) atexit.register(idapro.close_database, True) return args.json_file
if __name__ == "__main__": json_path = None if CLI_AVAILABLE and ida_kernwin.is_ida_library(None, 0, None): json_path = getargs() else: json_path = ida_kernwin.ask_file(0, "*.json", "GoReSym output file") assert json_path is not None and os.path.isfile(json_path)
main(json_path)
|