diff --git a/Il2CppInspector.Common/Il2CppInspector.csproj b/Il2CppInspector.Common/Il2CppInspector.csproj
index 3d897c5..bc34099 100644
--- a/Il2CppInspector.Common/Il2CppInspector.csproj
+++ b/Il2CppInspector.Common/Il2CppInspector.csproj
@@ -16,6 +16,7 @@
+
diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/ghidra-api.py b/Il2CppInspector.Common/Outputs/ScriptResources/ghidra-api.py
new file mode 100644
index 0000000..7a98459
--- /dev/null
+++ b/Il2CppInspector.Common/Outputs/ScriptResources/ghidra-api.py
@@ -0,0 +1,55 @@
+# Ghidra-specific implementation
+from ghidra.app.cmd.function import ApplyFunctionSignatureCmd
+from ghidra.app.script import GhidraScriptUtil
+from ghidra.app.util.cparser.C import CParserUtils
+from ghidra.program.model.symbol import SourceType
+
+def SetName(addr, name):
+ createLabel(toAddr(addr), name, True)
+
+def MakeFunction(start, name=None):
+ addr = toAddr(start)
+ # Don't override existing functions
+ fn = getFunctionAt(addr)
+ if fn is not None and name is not None:
+ # Set existing function name if name available
+ fn.setName(name, SourceType.USER_DEFINED)
+ elif fn is None:
+ # Create new function if none exists
+ createFunction(addr, name)
+ # Set header comment if name available
+ if name is not None:
+ setPlateComment(addr, name)
+
+def DefineCode(code):
+ # Code declarations are not supported in Ghidra
+ # This only affects string literals for metadata version < 19
+ # TODO: Replace with creating a DataType for enums
+ pass
+
+def SetFunctionType(addr, sig):
+ typeSig = CParserUtils.parseSignature(None, currentProgram, sig)
+ ApplyFunctionSignatureCmd(toAddr(addr), typeSig, SourceType.USER_DEFINED).applyTo(currentProgram)
+
+def SetType(addr, type):
+ if type.startswith('struct '):
+ type = type[7:]
+
+ t = getDataTypes(type)[0]
+ addr = toAddr(addr)
+ removeDataAt(addr)
+ createData(addr, t)
+
+def SetComment(addr, text):
+ setEOLComment(toAddr(addr), text)
+
+def SetHeaderComment(addr, text):
+ setPlateComment(toAddr(addr), text)
+
+def CustomInitializer():
+ # Do we need this for PE/MachO?
+ currentProgram.setImageBase(toAddr(0), True)
+
+def GetScriptDirectory():
+ # Ghidra doesn't define __file__ so we have to iterate all the scripts
+ return next(iter(filter(lambda x: x.getName() == '%SCRIPTFILENAME%', GhidraScriptUtil.getAllScripts())), None).getParentFile().toString()
diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/ida-api.py b/Il2CppInspector.Common/Outputs/ScriptResources/ida-api.py
new file mode 100644
index 0000000..7d7ffbe
--- /dev/null
+++ b/Il2CppInspector.Common/Outputs/ScriptResources/ida-api.py
@@ -0,0 +1,39 @@
+# IDA-specific implementation
+import idaapi
+
+def SetName(addr, name):
+ ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)
+ if ret == 0:
+ new_name = name + '_' + str(addr)
+ ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)
+
+def MakeFunction(start):
+ ida_funcs.add_func(start)
+
+def DefineCode(code):
+ idc.parse_decls(code)
+
+def SetFunctionType(addr, sig):
+ SetType(addr, sig)
+
+def SetType(addr, type):
+ ret = idc.SetType(addr, type)
+ if ret is None:
+ print('SetType(0x%x, %r) failed!' % (addr, type))
+
+def SetComment(addr, text):
+ idc.set_cmt(addr, text, 1)
+
+def SetHeaderComment(addr, text):
+ SetComment(addr, text)
+
+def CustomInitializer():
+ print('Processing Types')
+
+ original_macros = ida_typeinf.get_c_macros()
+ ida_typeinf.set_c_macros(original_macros + ";_IDA_=1")
+ idc.parse_decls("%TYPE_HEADER_RELATIVE_PATH%", idc.PT_FILE)
+ ida_typeinf.set_c_macros(original_macros)
+
+def GetScriptDirectory():
+ return os.path.dirname(os.path.realpath(__file__))
diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/shared-main.py b/Il2CppInspector.Common/Outputs/ScriptResources/shared-main.py
new file mode 100644
index 0000000..0a63b1f
--- /dev/null
+++ b/Il2CppInspector.Common/Outputs/ScriptResources/shared-main.py
@@ -0,0 +1,113 @@
+# Shared interface
+def ParseAddress(d):
+ return int(d['virtualAddress'], 0)
+
+def DefineILMethod(jsonDef):
+ addr = ParseAddress(jsonDef)
+ SetName(addr, jsonDef['name'].encode('utf-8'))
+ SetFunctionType(addr, jsonDef['signature'].encode('utf-8'))
+ SetHeaderComment(addr, jsonDef['dotNetSignature'].encode('utf-8'))
+
+def DefineILMethodInfo(jsonDef):
+ addr = ParseAddress(jsonDef)
+ SetName(addr, jsonDef['name'].encode('utf-8'))
+ SetType(addr, r'struct MethodInfo *')
+ SetComment(addr, jsonDef['dotNetSignature'].encode('utf-8'))
+
+def DefineCppFunction(jsonDef):
+ addr = ParseAddress(jsonDef)
+ SetName(addr, jsonDef['name'].encode('utf-8'))
+ SetFunctionType(addr, jsonDef['signature'].encode('utf-8'))
+
+def DefineString(jsonDef):
+ addr = ParseAddress(jsonDef)
+ SetName(addr, jsonDef['name'].encode('utf-8'))
+ SetType(addr, r'struct String *')
+ SetComment(addr, jsonDef['string'].encode('utf-8'))
+
+def DefineFieldFromJson(jsonDef):
+ DefineField(jsonDef['virtualAddress'], jsonDef['name'], jsonDef['type'], jsonDef['dotNetType'])
+
+def DefineField(addr, name, type, ilType = None):
+ addr = int(addr, 0)
+ SetName(addr, name.encode('utf-8'))
+ SetType(addr, type.encode('utf-8'))
+ if (ilType is not None):
+ SetComment(addr, ilType.encode('utf-8'))
+
+# Process JSON
+def ProcessJSON(jsonData):
+
+ # Method definitions
+ print('Processing method definitions')
+ for d in jsonData['methodDefinitions']:
+ DefineILMethod(d)
+
+ # Constructed generic methods
+ print('Processing constructed generic methods')
+ for d in jsonData['constructedGenericMethods']:
+ DefineILMethod(d)
+
+ # Custom attributes generators
+ print('Processing custom attributes generators')
+ for d in jsonData['customAttributesGenerators']:
+ DefineCppFunction(d)
+
+ # Method.Invoke thunks
+ print('Processing Method.Invoke thunks')
+ for d in jsonData['methodInvokers']:
+ DefineCppFunction(d)
+
+ # String literals for version >= 19
+ print('Processing string literals')
+ if 'virtualAddress' in jsonData['stringLiterals'][0]:
+ for d in jsonData['stringLiterals']:
+ DefineString(d)
+
+ # String literals for version < 19
+ else:
+ litDecl = 'enum StringLiteralIndex {\n'
+ for d in jsonData['stringLiterals']:
+ litDecl += " " + d['name'].encode('utf-8') + ",\n"
+ litDecl += '};\n'
+ DefineCode(litDecl)
+
+ # Il2CppClass (TypeInfo) pointers
+ print('Processing Il2CppClass (TypeInfo) pointers')
+ for d in jsonData['typeInfoPointers']:
+ DefineFieldFromJson(d)
+
+ # Il2CppType (TypeRef) pointers
+ print('Processing Il2CppType (TypeRef) pointers')
+ for d in jsonData['typeRefPointers']:
+ DefineField(d['virtualAddress'], d['name'], r'struct Il2CppType *', d['dotNetType'])
+
+ # MethodInfo pointers
+ print('Processing MethodInfo pointers')
+ for d in jsonData['methodInfoPointers']:
+ DefineILMethodInfo(d)
+
+ # Function boundaries
+ print('Processing function boundaries')
+ for d in jsonData['functionAddresses']:
+ MakeFunction(int(d, 0))
+
+ # IL2CPP type metadata
+ print('Processing IL2CPP type metadata')
+ for d in jsonData['typeMetadata']:
+ DefineField(d['virtualAddress'], d['name'], d['type'])
+
+ # IL2CPP function metadata
+ print('Processing IL2CPP function metadata')
+ for d in jsonData['functionMetadata']:
+ DefineCppFunction(d)
+
+# Entry point
+print('Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty')
+CustomInitializer()
+
+with open(os.path.join(GetScriptDirectory(), "%JSON_METADATA_RELATIVE_PATH%"), "r") as jsonFile:
+ jsonData = json.load(jsonFile)['addressMap']
+ ProcessJSON(jsonData)
+
+print('Script execution complete.')
diff --git a/Il2CppInspector.Common/Outputs/ScriptResources/shared-preamble.py b/Il2CppInspector.Common/Outputs/ScriptResources/shared-preamble.py
new file mode 100644
index 0000000..a77c19d
--- /dev/null
+++ b/Il2CppInspector.Common/Outputs/ScriptResources/shared-preamble.py
@@ -0,0 +1,3 @@
+# Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty
+import json
+import os