Overhaul IDA script output and add progress waitbox

This commit is contained in:
LukeFZ
2024-02-13 06:48:36 +01:00
parent 6b060c274a
commit 55532fdc8a
5 changed files with 341 additions and 192 deletions

View File

@@ -38,13 +38,15 @@ namespace Il2CppInspector.Outputs
using var fs = new FileStream(typeHeaderFile, FileMode.Create); using var fs = new FileStream(typeHeaderFile, FileMode.Create);
_writer = new StreamWriter(fs, Encoding.ASCII); _writer = new StreamWriter(fs, Encoding.ASCII);
const string decompilerIfDef = "#if !defined(_GHIDRA_) && !defined(_IDA_) && !defined(_IDACLANG_)";
using (_writer) using (_writer)
{ {
writeHeader(); writeHeader();
// Write primitive type definitions for when we're not including other headers // Write primitive type definitions for when we're not including other headers
writeCode($$""" writeCode($"""
#if defined(_GHIDRA_) || defined(_IDA_) #if defined(_GHIDRA_) || defined(_IDA_) || defined(_IDACLANG_)
typedef unsigned __int8 uint8_t; typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
@@ -55,13 +57,16 @@ namespace Il2CppInspector.Outputs
typedef __int64 int64_t; typedef __int64 int64_t;
#endif #endif
#if defined(_GHIDRA_) || defined(_IDACLANG_)
typedef int{_model.Package.BinaryImage.Bits}_t intptr_t;
typedef uint{_model.Package.BinaryImage.Bits}_t uintptr_t;
#endif
#if defined(_GHIDRA_) #if defined(_GHIDRA_)
typedef __int{{_model.Package.BinaryImage.Bits}} size_t; typedef uint{_model.Package.BinaryImage.Bits}_t size_t;
typedef size_t intptr_t;
typedef size_t uintptr_t;
#endif #endif
#if !defined(_GHIDRA_) && !defined(_IDA_) {decompilerIfDef}
#define _CPLUSPLUS_ #define _CPLUSPLUS_
#endif #endif
"""); """);
@@ -101,7 +106,7 @@ namespace Il2CppInspector.Outputs
} }
// C does not support namespaces // C does not support namespaces
writeCode("#if !defined(_GHIDRA_) && !defined(_IDA_)"); writeCode($"{decompilerIfDef}");
writeCode("namespace app {"); writeCode("namespace app {");
writeCode("#endif"); writeCode("#endif");
writeLine(""); writeLine("");
@@ -111,7 +116,7 @@ namespace Il2CppInspector.Outputs
writeTypesForGroup("Application types from usages", "types_from_usages"); writeTypesForGroup("Application types from usages", "types_from_usages");
writeTypesForGroup("Application unused value types", "unused_concrete_types"); writeTypesForGroup("Application unused value types", "unused_concrete_types");
writeCode("#if !defined(_GHIDRA_) && !defined(_IDA_)"); writeCode($"{decompilerIfDef}");
writeCode("}"); writeCode("}");
writeCode("#endif"); writeCode("#endif");
} }

View File

@@ -5,24 +5,18 @@ from ghidra.app.util.cparser.C import CParserUtils
from ghidra.program.model.data import ArrayDataType from ghidra.program.model.data import ArrayDataType
from ghidra.program.model.symbol import SourceType from ghidra.program.model.symbol import SourceType
def SetName(addr, name): def set_name(addr, name):
createLabel(toAddr(addr), name, True) createLabel(toAddr(addr), name, True)
def MakeFunction(start, name=None, addrMax=None): def make_function(start, end = None):
addr = toAddr(start) addr = toAddr(start)
# Don't override existing functions # Don't override existing functions
fn = getFunctionAt(addr) fn = getFunctionAt(addr)
if fn is not None and name is not None: if fn is None:
# Set existing function name if name available
fn.setName(name, SourceType.USER_DEFINED)
elif fn is None:
# Create new function if none exists # Create new function if none exists
createFunction(addr, name) createFunction(addr, None)
# Set header comment if name available
if name is not None:
setPlateComment(addr, name)
def MakeArray(addr, numItems, cppType): def make_array(addr, numItems, cppType):
if cppType.startswith('struct '): if cppType.startswith('struct '):
cppType = cppType[7:] cppType = cppType[7:]
@@ -32,18 +26,18 @@ def MakeArray(addr, numItems, cppType):
removeDataAt(addr) removeDataAt(addr)
createData(addr, a) createData(addr, a)
def DefineCode(code): def define_code(code):
# Code declarations are not supported in Ghidra # Code declarations are not supported in Ghidra
# This only affects string literals for metadata version < 19 # This only affects string literals for metadata version < 19
# TODO: Replace with creating a DataType for enums # TODO: Replace with creating a DataType for enums
pass pass
def SetFunctionType(addr, sig): def set_function_type(addr, sig):
MakeFunction(addr) make_function(addr)
typeSig = CParserUtils.parseSignature(None, currentProgram, sig) typeSig = CParserUtils.parseSignature(None, currentProgram, sig)
ApplyFunctionSignatureCmd(toAddr(addr), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram) ApplyFunctionSignatureCmd(toAddr(addr), typeSig, SourceType.USER_DEFINED, False, True).applyTo(currentProgram)
def SetType(addr, cppType): def set_type(addr, cppType):
if cppType.startswith('struct '): if cppType.startswith('struct '):
cppType = cppType[7:] cppType = cppType[7:]
@@ -52,13 +46,13 @@ def SetType(addr, cppType):
removeDataAt(addr) removeDataAt(addr)
createData(addr, t) createData(addr, t)
def SetComment(addr, text): def set_comment(addr, text):
setEOLComment(toAddr(addr), text) setEOLComment(toAddr(addr), text)
def SetHeaderComment(addr, text): def set_header_comment(addr, text):
setPlateComment(toAddr(addr), text) setPlateComment(toAddr(addr), text)
def CustomInitializer(): def script_prologue(status):
# Check that the user has parsed the C headers first # Check that the user has parsed the C headers first
if len(getDataTypes('Il2CppObject')) == 0: if len(getDataTypes('Il2CppObject')) == 0:
print('STOP! You must import the generated C header file (%TYPE_HEADER_RELATIVE_PATH%) before running this script.') print('STOP! You must import the generated C header file (%TYPE_HEADER_RELATIVE_PATH%) before running this script.')
@@ -70,5 +64,10 @@ def CustomInitializer():
if currentProgram.getExecutableFormat().endswith('(ELF)'): if currentProgram.getExecutableFormat().endswith('(ELF)'):
currentProgram.setImageBase(toAddr(%IMAGE_BASE%), True) currentProgram.setImageBase(toAddr(%IMAGE_BASE%), True)
def GetScriptDirectory(): def script_epilogue(status):
pass
def get_script_directory():
return getSourceFile().getParentFile().toString() return getSourceFile().getParentFile().toString()
class StatusWrapper(BaseStatusHandler): pass

View File

@@ -1,58 +1,174 @@
# IDA-specific implementation # IDA-specific implementation
import idaapi import ida_kernwin
import ida_name
import ida_idaapi
import ida_typeinf
import ida_bytes
import ida_nalt
import ida_ida
import ida_ua
def SetName(addr, name): try: # 7.7+
ret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK) import ida_srclang
if ret == 0: IDACLANG_AVAILABLE = True
new_name = name + '_' + str(addr) except ImportError:
ret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK) IDACLANG_AVAILABLE = False
def MakeFunction(start, name=None, addrMax=None): import datetime
ida_funcs.add_func(start)
#limit end function to maxAddr if any def set_name(addr, name):
if addrMax is None: ida_name.set_name(addr, name, ida_name.SN_NOWARN | ida_name.SN_NOCHECK | ida_name.SN_FORCE)
def make_function(start, end = None):
ida_bytes.del_items(start, ida_bytes.DELIT_SIMPLE, 12) # Undefine x bytes which should hopefully be enough for the first instruction
ida_ua.create_insn(start) # Create instruction at start
if not ida_funcs.add_func(start, end if end is not None else ida_idaapi.BADADDR): # This fails if the function doesn't start with an instruction
print(f"failed to mark function {hex(start)}-{hex(end) if end is not None else '???'} as function")
TYPE_CACHE = {}
def get_type(typeName):
if typeName not in TYPE_CACHE:
info = ida_typeinf.idc_parse_decl(None, typeName, ida_typeinf.PT_RAWARGS)
if info is None:
print(f"Failed to create type {typeName}.")
return None
TYPE_CACHE[typeName] = info[1:]
return TYPE_CACHE[typeName]
TINFO_DEFINITE = 0x0001 # These only exist in idc for some reason, so we redefine it here
def set_type(addr, cppType):
cppType += ';'
info = get_type(cppType)
if info is None:
return return
addrEnd = idc.get_func_attr(start,FUNCATTR_END)
if addrEnd == idaapi.BADADDR: if ida_typeinf.apply_type(None, info[0], info[1], addr, TINFO_DEFINITE) is None:
print(f"set_type({hex(addr)}, {cppType}); failed!")
def set_function_type(addr, sig):
set_type(addr, sig)
def make_array(addr, numItems, cppType):
set_type(addr, cppType)
flags = ida_bytes.get_flags(addr)
if ida_bytes.is_struct(flags):
opinfo = ida_nalt.opinfo_t()
ida_bytes.get_opcode(opinfo, addr, 0, flags)
entrySize = ida_bytes.get_data_elsize(addr, flags, opinfo)
tid = opinfo.tid
else:
entrySize = ida_bytes.get_item_size(addr)
tid = ida_idaapi.BADADDR
ida_bytes.create_data(addr, flags, numItems * entrySize, tid)
def define_code(code):
ida_typeinf.idc_parse_types(code)
def set_comment(addr, comment, repeatable = True):
ida_bytes.set_cmt(addr, comment, repeatable)
def set_header_comment(addr, comment):
func = ida_funcs.get_func(addr)
if func is None:
return return
if addrEnd > addrMax:
idc.set_func_end(start,addrMax)
def MakeArray(addr, numItems, cppType): ida_funcs.set_func_cmt(func, comment, True)
SetType(addr, cppType)
idc.make_array(addr, numItems)
def DefineCode(code): cached_genflags = 0
idc.parse_decls(code)
def SetFunctionType(addr, sig): def script_prologue(status):
SetType(addr, sig) global cached_genflags
# Disable autoanalysis
cached_genflags = ida_ida.inf_get_genflags()
ida_ida.inf_set_genflags(cached_genflags & ~ida_ida.INFFL_AUTO)
def SetType(addr, cppType): # Unload type libraries we know to cause issues - like the c++ linux one
if not cppType.endswith(';'): PLATFORMS = ["x86", "x64", "arm", "arm64"]
cppType += ';' PROBLEMATIC_TYPELIBS = ["gnulnx"]
tinfo = idc.parse_decl(cppType,idaapi.PT_RAWARGS)
ret = None
if not(tinfo is None):
ret = idc.apply_type(addr,tinfo)
if ret is None:
ret = idc.SetType(addr, cppType)
if ret is None:
print('SetType(0x%x, %r) failed!' % (addr, cppType))
def SetComment(addr, text): for lib in PROBLEMATIC_TYPELIBS:
idc.set_cmt(addr, text, 1) for platform in PLATFORMS:
ida_typeinf.del_til(f"{lib}_{platform}")
def SetHeaderComment(addr, text): # Set name mangling to GCC 3.x and display demangled as default
SetComment(addr, text) ida_ida.inf_set_demnames(ida_ida.DEMNAM_GCC3 | ida_ida.DEMNAM_NAME)
def CustomInitializer(): status.update_step('Processing Types')
print('Processing Types')
original_macros = ida_typeinf.get_c_macros() if IDACLANG_AVAILABLE:
ida_typeinf.set_c_macros(original_macros + ";_IDA_=1") header_path = os.path.join(get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%")
idc.parse_decls(os.path.join(GetScriptDirectory(), "%TYPE_HEADER_RELATIVE_PATH%"), idc.PT_FILE) ida_srclang.set_parser_argv("clang", "-x c++ -D_IDACLANG_=1")
ida_typeinf.set_c_macros(original_macros) ida_srclang.parse_decls_with_parser("clang", None, header_path, True)
else:
original_macros = ida_typeinf.get_c_macros()
ida_typeinf.set_c_macros(original_macros + ";_IDA_=1")
ida_typeinf.idc_parse_types(os.path.join(get_script_directory(), "%TYPE_HEADER_RELATIVE_PATH%"), ida_typeinf.PT_FILE)
ida_typeinf.set_c_macros(original_macros)
def GetScriptDirectory(): def script_epilogue(status):
# Reenable auto-analysis
global cached_genflags
ida_ida.inf_set_genflags(cached_genflags)
def get_script_directory():
return os.path.dirname(os.path.realpath(__file__)) return os.path.dirname(os.path.realpath(__file__))
class StatusHandler(BaseStatusHandler):
def __init__(self):
self.step = "Initializing"
self.max_items = 0
self.current_items = 0
self.start_time = datetime.datetime.now()
self.step_start_time = self.start_time
self.last_updated_time = datetime.datetime.min
def initialize(self):
ida_kernwin.show_wait_box("Processing")
def update(self):
if self.was_cancelled():
raise RuntimeError("Cancelled script.")
current_time = datetime.datetime.now()
if 0.5 > (current_time - self.last_updated_time).total_seconds():
return
self.last_updated_time = current_time
step_time = current_time - self.step_start_time
total_time = current_time - self.start_time
message = f"""
Running IL2CPP script.
Current Step: {self.step}
Progress: {self.current_items}/{self.max_items}
Elapsed: {step_time} ({total_time})
"""
ida_kernwin.replace_wait_box(message)
def update_step(self, step, max_items = 0):
print(step)
self.step = step
self.max_items = max_items
self.current_items = 0
self.step_start_time = datetime.datetime.now()
self.last_updated_time = datetime.datetime.min
self.update()
def update_progress(self, new_progress = 1):
self.current_items += new_progress
self.update()
def was_cancelled(self):
return ida_kernwin.user_cancelled()
def close(self):
ida_kernwin.hide_wait_box()

View File

@@ -1,155 +1,177 @@
# Shared interface # Shared interface
def AsUTF8(s): def from_hex(addr): return int(addr, 0)
return s if sys.version_info[0] > 2 else s.encode('utf-8')
def ParseAddress(d): def parse_address(d): return from_hex(d['virtualAddress'])
return int(d['virtualAddress'], 0)
def DefineILMethod(jsonDef): def define_il_method(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
SetFunctionType(addr, AsUTF8(jsonDef['signature'])) set_function_type(addr, jsonDef['signature'])
SetHeaderComment(addr, AsUTF8(jsonDef['dotNetSignature'])) set_header_comment(addr, jsonDef['dotNetSignature'])
def DefineILMethodInfo(jsonDef): def define_il_method_info(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
SetType(addr, r'struct MethodInfo *') set_type(addr, r'struct MethodInfo *')
SetComment(addr, AsUTF8(jsonDef['dotNetSignature'])) set_comment(addr, jsonDef['dotNetSignature'])
def DefineCppFunction(jsonDef): def define_cpp_function(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
SetFunctionType(addr, AsUTF8(jsonDef['signature'])) set_function_type(addr, jsonDef['signature'])
def DefineString(jsonDef): def define_string(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
SetType(addr, r'struct String *') set_type(addr, r'struct String *')
SetComment(addr, AsUTF8(jsonDef['string'])) set_comment(addr, jsonDef['string'])
def DefineFieldFromJson(jsonDef): def define_field(addr, name, type, ilType = None):
DefineField(jsonDef['virtualAddress'], jsonDef['name'], jsonDef['type'], jsonDef['dotNetType']) addr = from_hex(addr)
set_name(addr, name)
set_type(addr, type)
if ilType is not None:
set_comment(addr, ilType)
def DefineField(addr, name, type, ilType = None): def define_field_from_json(jsonDef):
addr = int(addr, 0) define_field(jsonDef['virtualAddress'], jsonDef['name'], jsonDef['type'], jsonDef['dotNetType'])
SetName(addr, AsUTF8(name))
SetType(addr, AsUTF8(type))
if (ilType is not None):
SetComment(addr, AsUTF8(ilType))
def DefineArray(jsonDef): def define_array(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
MakeArray(addr, int(jsonDef['count']), AsUTF8(jsonDef['type'])) make_array(addr, int(jsonDef['count']), jsonDef['type'])
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
def DefineFieldWithValue(jsonDef): def define_field_with_value(jsonDef):
addr = ParseAddress(jsonDef) addr = parse_address(jsonDef)
SetName(addr, AsUTF8(jsonDef['name'])) set_name(addr, jsonDef['name'])
SetComment(addr, AsUTF8(jsonDef['value'])) set_comment(addr, jsonDef['value'])
# Process JSON # Process JSON
def ProcessJSON(jsonData): def process_json(jsonData, status):
# 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 += " " + AsUTF8(d['name']) + ",\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)
# FieldInfo pointers, add the contents as a comment
print('Processing FieldInfo pointers')
for d in jsonData['fields']:
DefineFieldWithValue(d)
# FieldRva pointers, add the contents as a comment
print('Processing FieldRva pointers')
for d in jsonData['fieldRvas']:
DefineFieldWithValue(d)
# Function boundaries # Function boundaries
print('Processing function boundaries')
functionAddresses = jsonData['functionAddresses'] functionAddresses = jsonData['functionAddresses']
functionAddresses.sort() functionAddresses.sort()
count = len(functionAddresses) count = len(functionAddresses)
status.update_step('Processing function boundaries', count)
for i in range(count): for i in range(count):
addrStart = int(functionAddresses[i],0) start = from_hex(functionAddresses[i])
if addrStart == 0: if start == 0:
status.update_progress()
continue continue
addrNext = None
if i != count -1: end = from_hex(functionAddresses[i + 1]) if i + 1 != count else None
addrNext = int(functionAddresses[i+1],0)
MakeFunction(addrStart,None,addrNext) make_function(start, end)
status.update_progress()
# Method definitions
status.update_step('Processing method definitions', len(jsonData['methodDefinitions']))
for d in jsonData['methodDefinitions']:
define_il_method(d)
status.update_progress()
# Constructed generic methods
status.update_step('Processing constructed generic methods', len(jsonData['constructedGenericMethods']))
for d in jsonData['constructedGenericMethods']:
define_il_method(d)
status.update_progress()
# Custom attributes generators
status.update_step('Processing custom attributes generators', len(jsonData['customAttributesGenerators']))
for d in jsonData['customAttributesGenerators']:
define_cpp_function(d)
status.update_progress()
# Method.Invoke thunks
status.update_step('Processing Method.Invoke thunks', len(jsonData['methodInvokers']))
for d in jsonData['methodInvokers']:
define_cpp_function(d)
status.update_progress()
# String literals for version >= 19
if 'virtualAddress' in jsonData['stringLiterals'][0]:
status.update_step('Processing string literals (V19+)', len(jsonData['stringLiterals']))
for d in jsonData['stringLiterals']:
define_string(d)
status.update_progress()
# String literals for version < 19
else:
status.update_step('Processing string literals (pre-V19)')
litDecl = 'enum StringLiteralIndex {\n'
for d in jsonData['stringLiterals']:
litDecl += " " + d['name'] + ",\n"
litDecl += '};\n'
define_code(litDecl)
# Il2CppClass (TypeInfo) pointers
status.update_step('Processing Il2CppClass (TypeInfo) pointers', len(jsonData['typeInfoPointers']))
for d in jsonData['typeInfoPointers']:
define_field_from_json(d)
status.update_progress()
# Il2CppType (TypeRef) pointers
status.update_step('Processing Il2CppType (TypeRef) pointers', len(jsonData['typeRefPointers']))
for d in jsonData['typeRefPointers']:
define_field(d['virtualAddress'], d['name'], r'struct Il2CppType *', d['dotNetType'])
status.update_progress()
# MethodInfo pointers
status.update_step('Processing MethodInfo pointers', len(jsonData['methodInfoPointers']))
for d in jsonData['methodInfoPointers']:
define_il_method_info(d)
status.update_progress()
# FieldInfo pointers, add the contents as a comment
status.update_step('Processing FieldInfo pointers', len(jsonData['fields']))
for d in jsonData['fields']:
define_field_with_value(d)
status.update_progress()
# FieldRva pointers, add the contents as a comment
status.update_step('Processing FieldRva pointers', len(jsonData['fieldRvas']))
for d in jsonData['fieldRvas']:
define_field_with_value(d)
status.update_progress()
# IL2CPP type metadata # IL2CPP type metadata
print('Processing IL2CPP type metadata') status.update_step('Processing IL2CPP type metadata', len(jsonData['typeMetadata']))
for d in jsonData['typeMetadata']: for d in jsonData['typeMetadata']:
DefineField(d['virtualAddress'], d['name'], d['type']) define_field(d['virtualAddress'], d['name'], d['type'])
# IL2CPP function metadata # IL2CPP function metadata
print('Processing IL2CPP function metadata') status.update_step('Processing IL2CPP function metadata', len(jsonData['functionMetadata']))
for d in jsonData['functionMetadata']: for d in jsonData['functionMetadata']:
DefineCppFunction(d) define_cpp_function(d)
# IL2CPP array metadata # IL2CPP array metadata
print('Processing IL2CPP array metadata') status.update_step('Processing IL2CPP array metadata', len(jsonData['arrayMetadata']))
for d in jsonData['arrayMetadata']: for d in jsonData['arrayMetadata']:
DefineArray(d) define_array(d)
# IL2CPP API functions # IL2CPP API functions
print('Processing IL2CPP API functions') status.update_step('Processing IL2CPP API functions', len(jsonData['apis']))
for d in jsonData['apis']: for d in jsonData['apis']:
DefineCppFunction(d) define_cpp_function(d)
# Entry point # Entry point
print('Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty') print('Generated script file by Il2CppInspectorRedux - https://github.com/LukeFZ (Original Il2CppInspector by http://www.djkaty.com - https://github.com/djkaty)')
CustomInitializer() status = StatusHandler()
status.initialize()
with open(os.path.join(GetScriptDirectory(), "%JSON_METADATA_RELATIVE_PATH%"), "r") as jsonFile: try:
jsonData = json.load(jsonFile)['addressMap'] status.update_step("Running script prologue")
ProcessJSON(jsonData) script_prologue(status)
print('Script execution complete.') with open(os.path.join(get_script_directory(), "%JSON_METADATA_RELATIVE_PATH%"), "r") as jsonFile:
status.update_step("Loading JSON metadata")
jsonData = json.load(jsonFile)['addressMap']
process_json(jsonData, status)
status.update_step("Running script epilogue")
script_epilogue(status)
status.update_step('Script execution complete.')
except RuntimeError: pass
finally: status.close()

View File

@@ -1,6 +1,13 @@
# Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty # Generated script file by Il2CppInspectorRedux - https://github.com/LukeFZ (Original Il2CppInspector by http://www.djkaty.com - https://github.com/djkaty)
# Target Unity version: %TARGET_UNITY_VERSION% # Target Unity version: %TARGET_UNITY_VERSION%
import json import json
import os import os
import sys import sys
class BaseStatusHandler:
def initialize(self): pass
def update_step(self, name, max_items = 0): print(name)
def update_progress(self, progress = 1): pass
def was_cancelled(self): return False
def close(self): pass