Add embedded resources for universal script handling (ScriptResources)

This commit is contained in:
Katy Coe
2020-08-04 01:52:43 +02:00
parent 160569f239
commit dea29751ef
5 changed files with 211 additions and 0 deletions

View File

@@ -16,6 +16,7 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Cpp\UnityHeaders\**" /> <EmbeddedResource Include="Cpp\UnityHeaders\**" />
<EmbeddedResource Include="Cpp\Il2CppAPIHeaders\**" /> <EmbeddedResource Include="Cpp\Il2CppAPIHeaders\**" />
<EmbeddedResource Include="Outputs\ScriptResources\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -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()

View File

@@ -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__))

View File

@@ -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.')

View File

@@ -0,0 +1,3 @@
# Generated script file by Il2CppInspector - http://www.djkaty.com - https://github.com/djkaty
import json
import os