From 580628b3b41c2a7f864dbb86a1f991b4eef81a39 Mon Sep 17 00:00:00 2001 From: Rick Gibbed Date: Sun, 31 Mar 2024 20:42:17 -0500 Subject: [PATCH] Improvements to IDA namer script. - Output a valid standalone script. - Merge base script and IDA 7.7 variant script. - Additional options for script output. - Reduce code duplication. --- reversing/scripts/ida_namer/ida_namer.py | 134 +++++++++++------- .../scripts/ida_namer/ida_namer_ida77.py | 87 ------------ 2 files changed, 81 insertions(+), 140 deletions(-) delete mode 100644 reversing/scripts/ida_namer/ida_namer_ida77.py diff --git a/reversing/scripts/ida_namer/ida_namer.py b/reversing/scripts/ida_namer/ida_namer.py index cb4e18ed3..35b91eb38 100644 --- a/reversing/scripts/ida_namer/ida_namer.py +++ b/reversing/scripts/ida_namer/ida_namer.py @@ -5,30 +5,88 @@ import fire import os -def main(il2cpp_path=None, out_path=None, imagebase = None, new_imagebase = None): - if il2cpp_path is None: +def main(il2cpp_path = None, out_path = None, imagebase = None, new_imagebase = None, no_reflection = None, ida77 = None, undefine = None): + if not il2cpp_path: print("--il2cpp_path not specified") return - - if out_path is None: + elif not out_path: print("--out_path not specified") return - - if not os.path.exists(il2cpp_path): + elif imagebase and not new_imagebase: + print("--imagebase specified but --new_imagebase not specified") + return + elif not imagebase and new_imagebase: + print("--new_imagebase specified but --imagebase not specified") + return + elif not os.path.exists(il2cpp_path): print("--il2cpp_path does not exist") return + if imagebase and isinstance(imagebase, str): + imagebase = int(imagebase, 16) + + if new_imagebase and isinstance(new_imagebase, str): + new_imagebase = int(new_imagebase, 16) + with open(il2cpp_path, "r", encoding="utf8") as f: il2cpp_dump = json.load(f) - out_str = "" - bad_chars = ['<', '>', '`', ".", ",", "[", "]", "|", ' ', '='] + out_lines = [] + seen_functions = set() + + def output_code_old(address, name): + nonlocal out_lines, undefine + + if undefine: + out_lines.append("MakeUnkn(%s, BADADDR);\n" % (address)) + out_lines.append("MakeNameEx(%s, \"%s\", SN_CHECK);\n" % (address, name)) + if undefine: + out_lines.append("MakeFunction(%s, BADADDR);\n" % (address)) + + def output_code_new(address, name): + nonlocal out_lines, undefine + if undefine: + out_lines.append("del_items(%s);\n" % (address)) + out_lines.append("set_name(%s, \"%s\", SN_CHECK);\n" % (address, name)) + if undefine: + out_lines.append("add_func(%s);\n" % (address)) + + def output_code(address, name): + nonlocal out_lines, imagebase, new_imagebase, undefine, ida77 + + if address == 0 or address in seen_functions: + return False + + seen_functions.add(address) + + if imagebase is not None and new_imagebase is not None: + address = address - imagebase + address = address + new_imagebase + + address = str(hex(address)) + + if ida77: + output_code_new(address, name) + else: + output_code_old(address, name) + + return True + + bad_chars = ['<', '>', '`', '.', ',', '[', ']', '|', ' ', '='] + + def filter_name(name): + nonlocal bad_chars + for bad_char in bad_chars: + name = name.replace(bad_char, "_") + return name + + out_lines.append("#include \n") + out_lines.append("static main()\n") + out_lines.append("{\n") num_methods_found = 0 num_reflection_methods_found = 0 - seen_functions = set() - for class_name, entry in il2cpp_dump.items(): try: for bad_char in bad_chars: @@ -39,66 +97,36 @@ def main(il2cpp_path=None, out_path=None, imagebase = None, new_imagebase = None if method_entry is None: continue - # filter the method name and class name for bad chars - for bad_char in bad_chars: - method_name = method_name.replace(bad_char, "_") + address = int("0x" + method_entry["function"], 16) # is a string not an int - #print(hex(int("0x" + method_entry["function"], 16))) - address = str(hex(int("0x" + method_entry["function"], 16))) # is a string not an int + if output_code(address, filter_name(class_name) + "__" + filter_name(method_name)): + num_methods_found = num_methods_found + 1 - if address == "0" or address in seen_functions: + if not no_reflection and "reflection_methods" in entry: + for method_name, method_entry in entry["reflection_methods"].items(): + if method_entry is None: continue - seen_functions.add(address) - - if imagebase is not None and new_imagebase is not None: - address_int = int("0x" + method_entry["function"], 16) - address_int = address_int - imagebase - address_int = address_int + new_imagebase - address = str(hex(address_int)) + address = int(method_entry["function"], 16) # is a string not an int - out_str = out_str + "idc.MakeName(%s, '%s__%s')\n" % (address, class_name, method_name) - num_methods_found = num_methods_found + 1 - - if "reflection_methods" in entry: - try: - for method_name, method_entry in entry["reflection_methods"].items(): - if method_entry is None: - continue - - for bad_char in bad_chars: - method_name = method_name.replace(bad_char, "_") - - address = str(hex(int("0x" + method_entry["function"], 16))) # is a string not an int - - if address == "0" or address in seen_functions: - continue - - seen_functions.add(address) - - if imagebase is not None and new_imagebase is not None: - address_int = int("0x" + method_entry["function"], 16) - address_int = address_int - imagebase - address_int = address_int + new_imagebase - address = str(hex(address_int)) - - out_str = out_str + "idc.MakeName(%s, 'reflection_methods_%s')\n" % (address, method_name) + if output_code(address, "reflection_methods_" + filter_name(method_name)): num_reflection_methods_found = num_reflection_methods_found + 1 - except: - continue + except (KeyError, TypeError): print("Error processing class %s" % class_name) continue + out_lines.append("}\n") + print("Found %d methods" % num_methods_found) print("Found %d reflection methods" % num_reflection_methods_found) print("Writing to %s..." % out_path) with open(out_path, "w", encoding="utf8") as f: - f.write(out_str) + f.writelines(out_lines) print("Done!") if __name__ == '__main__': - fire.Fire(main) \ No newline at end of file + fire.Fire(main) diff --git a/reversing/scripts/ida_namer/ida_namer_ida77.py b/reversing/scripts/ida_namer/ida_namer_ida77.py deleted file mode 100644 index b8441b015..000000000 --- a/reversing/scripts/ida_namer/ida_namer_ida77.py +++ /dev/null @@ -1,87 +0,0 @@ -# Script to generate an IDA python script to name all of the -# Functions in the IL2CPP Dump. -# partial credits to deepdarkkapustka for the script this is based off of (@muhopensores on github) -import json -import fire -import os - -def main(il2cpp_path="", out_path=""): - if il2cpp_path is None: - print("--il2cpp_path not specified") - return - - if out_path is None: - print("--out_path not specified") - return - - if not os.path.exists(il2cpp_path): - print("--il2cpp_path does not exist") - return - - with open(il2cpp_path, "r", encoding="utf8") as f: - il2cpp_dump = json.load(f) - - out_str = "" - bad_chars = ['<', '>', '`', ".", ","] - - num_methods_found = 0 - num_reflection_methods_found = 0 - - seen_functions = set() - - for class_name, entry in il2cpp_dump.items(): - try: - for bad_char in bad_chars: - class_name = class_name.replace(bad_char, "_") - - if "methods" in entry: - for method_name, method_entry in entry["methods"].items(): - if method_entry is None: - continue - - # filter the method name and class name for bad chars - for bad_char in bad_chars: - method_name = method_name.replace(bad_char, "_") - - address = method_entry["function"] # is a string not an int - - if address == "0" or address in seen_functions: - continue - - seen_functions.add(address) - - out_str = out_str + "idc.set_name(0x%s, '%s__%s', SN_CHECK)\n" % (address, class_name, method_name) - num_methods_found = num_methods_found + 1 - - if "reflection_methods" in entry: - for method_name, method_entry in entry["reflection_methods"].items(): - if method_entry is None: - continue - - for bad_char in bad_chars: - method_name = method_name.replace(bad_char, "_") - - if address == "0" or address in seen_functions: - continue - - seen_functions.add(address) - - address = method_entry["function"] # is a string not an int - out_str = out_str + "idc.set_name(0x%s, 'reflection_methods_%s', SN_CHECK)\n" % (address, method_name) - num_reflection_methods_found = num_reflection_methods_found + 1 - except (KeyError, TypeError): - print("Error processing class %s" % class_name) - continue - - print("Found %d methods" % num_methods_found) - print("Found %d reflection methods" % num_reflection_methods_found) - print("Writing to %s..." % out_path) - - with open(out_path, "w", encoding="utf8") as f: - f.write(out_str) - - print("Done!") - - -if __name__ == '__main__': - fire.Fire(main) \ No newline at end of file