diff --git a/docs/GHIDRA.md b/docs/GHIDRA.md index f4e431e..f93750f 100644 --- a/docs/GHIDRA.md +++ b/docs/GHIDRA.md @@ -79,7 +79,10 @@ for its own bookkeeping — different thing; don't conflate.) - `ghidra/` is git-ignored (install + project + dumps, all large/regenerable). ## Tooling map (`reverse/`, `ghidra/scripts/`) -- `ghidra/scripts/apply_il2cpp_symbols.py` — headless symbol injector (this doc). +> `ghidra/` is git-ignored, so the **tracked masters** live in `reverse/` (`ghidra_*.py`); copy them +> into `ghidra/scripts/` (where `-scriptPath` points) to run. e.g. +> `cp reverse/ghidra_apply_il2cpp_symbols.py ghidra/scripts/apply_il2cpp_symbols.py`. +- `reverse/ghidra_apply_il2cpp_symbols.py` → `ghidra/scripts/apply_il2cpp_symbols.py` — headless symbol injector (this doc). - `ghidra/scripts/decomp_targets.py` — decompile `targets.txt` → `ghidra/decomp.c`. - `ghidra/scripts/disasm_targets.py` — disassemble `targets.txt` → `ghidra/disasm.txt` (fast, no analysis). - `reverse/il2cpp_re.py` — VA↔file-offset, method index from `dump.cs`, xrefs, body disasm + float consts. diff --git a/reverse/ghidra_apply_il2cpp_symbols.py b/reverse/ghidra_apply_il2cpp_symbols.py new file mode 100644 index 0000000..dd2ad49 --- /dev/null +++ b/reverse/ghidra_apply_il2cpp_symbols.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Headless-adapted Il2CppDumper -> Ghidra symbol applier ("fake PDB" from script.json). +# Names every method, string literal and metadata entry, and creates function boundaries +# from the dumper's address table -- WITHOUT Ghidra having to rediscover them via analysis. +# Light path: names + function starts only (no il2cpp.h struct import, no signatures). +# +# Adapted from yoten/ghidra.py: replaced the interactive askFile() with a script arg / default +# path so it runs under analyzeHeadless. Jython 2.7. +# +# Run (after the program is imported into the project): +# analyzeHeadless ghidra/project SAND -process GameAssembly.dll -noanalysis \ +# -scriptPath ghidra/scripts -postScript apply_il2cpp_symbols.py [path/to/script.json] +# Default script.json: the live yoten dump. +# @category il2cpp +import json + +DEFAULT_SCRIPT_JSON = "/mnt/c/Users/downloadpizza/Downloads/yoten/script.json" + +processFields = ["ScriptMethod", "ScriptString", "ScriptMetadata", "ScriptMetadataMethod", "Addresses"] + +baseAddress = currentProgram.getImageBase() +USER_DEFINED = ghidra.program.model.symbol.SourceType.USER_DEFINED + + +def get_addr(addr): + return baseAddress.add(addr) + + +def set_name(addr, name): + try: + createLabel(addr, name.replace(' ', '-'), True, USER_DEFINED) + except: + pass + + +def make_function(start): + if getFunctionAt(start) is None: + try: + createFunction(start, None) + except: + pass + + +args = getScriptArgs() +path = args[0] if args else DEFAULT_SCRIPT_JSON +print("apply_il2cpp_symbols: loading " + path) +data = json.loads(open(path, 'rb').read().decode('utf-8')) + +if "Addresses" in data and "Addresses" in processFields: + addresses = data["Addresses"] + monitor.initialize(len(addresses)) + monitor.setMessage("Function boundaries") + for index in range(len(addresses) - 1): + make_function(get_addr(addresses[index])) + monitor.incrementProgress(1) + +if "ScriptMethod" in data and "ScriptMethod" in processFields: + scriptMethods = data["ScriptMethod"] + monitor.initialize(len(scriptMethods)) + monitor.setMessage("Methods") + for sm in scriptMethods: + set_name(get_addr(sm["Address"]), sm["Name"].encode("utf-8")) + monitor.incrementProgress(1) + +if "ScriptString" in data and "ScriptString" in processFields: + scriptStrings = data["ScriptString"] + monitor.initialize(len(scriptStrings)) + monitor.setMessage("Strings") + for i, ss in enumerate(scriptStrings, 1): + addr = get_addr(ss["Address"]) + createLabel(addr, "StringLiteral_" + str(i), True, USER_DEFINED) + setEOLComment(addr, ss["Value"].encode("utf-8")) + monitor.incrementProgress(1) + +if "ScriptMetadata" in data and "ScriptMetadata" in processFields: + for md in data["ScriptMetadata"]: + addr = get_addr(md["Address"]) + set_name(addr, md["Name"].encode("utf-8")) + setEOLComment(addr, md["Name"].encode("utf-8")) + +if "ScriptMetadataMethod" in data and "ScriptMetadataMethod" in processFields: + for mdm in data["ScriptMetadataMethod"]: + addr = get_addr(mdm["Address"]) + set_name(addr, mdm["Name"].encode("utf-8")) + setEOLComment(addr, mdm["Name"].encode("utf-8")) + +print("apply_il2cpp_symbols: done")