IL2CPP: Refactor loaders in Il2CppBinary

This commit is contained in:
Katy Coe
2020-12-05 17:21:20 +01:00
parent 21cb7f9f80
commit aaa90370d1
2 changed files with 68 additions and 38 deletions

View File

@@ -105,12 +105,13 @@ namespace Il2CppInspector
return (Il2CppBinary) Activator.CreateInstance(type, stream[0]); return (Il2CppBinary) Activator.CreateInstance(type, stream[0]);
} }
// Load binary without a global-metadata.dat available
public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion) { public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion) {
var inst = LoadImpl(stream); var inst = LoadImpl(stream);
// Try to process the IL2CPP image; return the instance if succeeded, otherwise null return inst.Initialize(metadataVersion) ? inst : null;
return inst.InitializeWithoutMetadata(metadataVersion) ? inst : null;
} }
// Load binary with a global-metadata.dat available
// Supplying the Metadata class when loading a binary is optional // Supplying the Metadata class when loading a binary is optional
// If it is specified and both symbol table and function scanning fail, // If it is specified and both symbol table and function scanning fail,
// Metadata will be used to try to find the required structures with data analysis // Metadata will be used to try to find the required structures with data analysis
@@ -120,32 +121,30 @@ namespace Il2CppInspector
return inst.Initialize(metadata) ? inst : null; return inst.Initialize(metadata) ? inst : null;
} }
// Architecture-specific search function // Initialize binary without a global-metadata.dat available
protected abstract (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc); public bool Initialize(double metadataVersion) {
Image.Version = metadataVersion;
// Try to find data structures via symbol table lookup, init function analysis and data heuristics if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode()) is var ptrs))
return false;
Configure(ptrs.Value.Item1, ptrs.Value.Item2);
return true;
}
// Initialize binary with a global-metadata.dat available
public bool Initialize(Metadata metadata) { public bool Initialize(Metadata metadata) {
Image.Version = metadata.Version; Image.Version = metadata.Version;
if (InitializeWithoutMetadata(metadata.Version)) if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is var ptrs))
return true;
// Resort to a full scan of the file
var (codePtr, metadataPtr) = ImageScan(metadata);
if (codePtr == 0) {
Console.WriteLine("No matches via data heuristics");
return false; return false;
}
Console.WriteLine("Required structures acquired from data heuristics"); Configure(ptrs.Value.Item1, ptrs.Value.Item2, metadata);
Configure(codePtr, metadataPtr);
return true; return true;
} }
// Try to find data structures via symbol table lookup and init function code analysis // Try to find data structures via symbol table lookup
public bool InitializeWithoutMetadata(double version) { private (ulong, ulong)? FindMetadataFromSymbols() {
Image.Version = version;
// Try searching the symbol table // Try searching the symbol table
var symbols = Image.GetSymbolTable(); var symbols = Image.GetSymbolTable();
@@ -162,20 +161,20 @@ namespace Il2CppInspector
if (code != null && metadata != null) { if (code != null && metadata != null) {
Console.WriteLine("Required structures acquired from symbol lookup"); Console.WriteLine("Required structures acquired from symbol lookup");
Configure(code.VirtualAddress, metadata.VirtualAddress); return (code.VirtualAddress, metadata.VirtualAddress);
return true; } else {
}
else {
Console.WriteLine("No matches in symbol table"); Console.WriteLine("No matches in symbol table");
} }
} } else if (symbols != null) {
else if (symbols != null) {
Console.WriteLine("No symbol table present in binary file"); Console.WriteLine("No symbol table present in binary file");
} } else {
else {
Console.WriteLine("Symbol table search not implemented for this binary format"); Console.WriteLine("Symbol table search not implemented for this binary format");
} }
return null;
}
// Try to find data structures via init function code analysis
private (ulong, ulong)? FindMetadataFromCode() {
// Try searching the function table // Try searching the function table
var addrs = Image.GetFunctionTable(); var addrs = Image.GetFunctionTable();
@@ -187,16 +186,32 @@ namespace Il2CppInspector
if (code != 0) { if (code != 0) {
RegistrationFunctionPointer = loc + Image.GlobalOffset; RegistrationFunctionPointer = loc + Image.GlobalOffset;
Console.WriteLine("Required structures acquired from code heuristics. Initialization function: 0x{0:X16}", RegistrationFunctionPointer); Console.WriteLine("Required structures acquired from code heuristics. Initialization function: 0x{0:X16}", RegistrationFunctionPointer);
Configure(code, metadata); return (code, metadata);
return true;
} }
} }
Console.WriteLine("No matches via code heuristics"); Console.WriteLine("No matches via code heuristics");
return false; return null;
} }
private void Configure(ulong codeRegistration, ulong metadataRegistration) { // Try to find data structures via data heuristics
// Requires succeesful global-metadata.dat analysis first
private (ulong, ulong)? FindMetadataFromData(Metadata metadata) {
var (codePtr, metadataPtr) = ImageScan(metadata);
if (codePtr == 0) {
Console.WriteLine("No matches via data heuristics");
return null;
}
Console.WriteLine("Required structures acquired from data heuristics");
return (codePtr, metadataPtr);
}
// Architecture-specific search function
protected abstract (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc);
// Load all of the discovered metadata in the binary
private void Configure(ulong codeRegistration, ulong metadataRegistration, Metadata metadata = null) {
// Store locations // Store locations
CodeRegistrationPointer = codeRegistration; CodeRegistrationPointer = codeRegistration;
MetadataRegistrationPointer = metadataRegistration; MetadataRegistrationPointer = metadataRegistration;
@@ -209,7 +224,7 @@ namespace Il2CppInspector
MetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration); MetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
// Restore the field order in CodeRegistration and MetadataRegistration if they have been re-ordered for obfuscation // Restore the field order in CodeRegistration and MetadataRegistration if they have been re-ordered for obfuscation
ReconstructMetadata(); ReconstructMetadata(metadata);
// Do basic validatation that MetadataRegistration and CodeRegistration are sane // Do basic validatation that MetadataRegistration and CodeRegistration are sane
/* /*
@@ -226,9 +241,7 @@ namespace Il2CppInspector
|| CodeRegistration.unresolvedVirtualCallCount > 0x4000 // >= 22 || CodeRegistration.unresolvedVirtualCallCount > 0x4000 // >= 22
|| CodeRegistration.interopDataCount > 0x1000 // >= 23 || CodeRegistration.interopDataCount > 0x1000 // >= 23
|| (Image.Version <= 24.1 && CodeRegistration.invokerPointersCount > CodeRegistration.methodPointersCount)) || (Image.Version <= 24.1 && CodeRegistration.invokerPointersCount > CodeRegistration.methodPointersCount))
throw new NotSupportedException("The detected Il2CppCodeRegistration / Il2CppMetadataRegistration structs do not pass validation. This may mean that their fields have been re-ordered as a form of obfuscation - this scenario is not currently supported by Il2CppInspector. Consider re-ordering the fields in Il2CppBinaryClasses.cs and try again."); throw new NotSupportedException("The detected Il2CppCodeRegistration / Il2CppMetadataRegistration structs do not pass validation. This may mean that their fields have been re-ordered as a form of obfuscation and Il2CppInspector has not been able to restore the original order automatically. Consider re-ordering the fields in Il2CppBinaryClasses.cs and try again.");
// TODO: Determine the correct field order for MetadataRegistration and CodeRegistration (#44, #98)
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule // The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
if (Image.Version <= 24.1) if (Image.Version <= 24.1)

View File

@@ -56,7 +56,7 @@ namespace Il2CppInspector
} }
// Reconstruct Il2CppCodeRegistration and Il2CppMetadataRegistration into their original, unobfuscated field order // Reconstruct Il2CppCodeRegistration and Il2CppMetadataRegistration into their original, unobfuscated field order
private void ReconstructMetadata() { private void ReconstructMetadata(Metadata metadata) {
// If the section table is not available, give up and do nothing // If the section table is not available, give up and do nothing
if (!Image.TryGetSections(out var sections)) if (!Image.TryGetSections(out var sections))
return; return;
@@ -201,6 +201,11 @@ namespace Il2CppInspector
CodeRegistration.pmethodPointers = methodPointers.Key; CodeRegistration.pmethodPointers = methodPointers.Key;
CodeRegistration.methodPointersCount = (ulong) methodPointers.Value; CodeRegistration.methodPointersCount = (ulong) methodPointers.Value;
// Force CodeRegistration to pass validation in Il2CppBinary.Configure()
CodeRegistration.reversePInvokeWrapperCount = 0;
CodeRegistration.unresolvedVirtualCallCount = 0;
CodeRegistration.interopDataCount = 0;
// Things we need from Il2CppMetadataRegistration // Things we need from Il2CppMetadataRegistration
// genericInsts -> list of Il2CppGenericInst* (argc is count of Il2CppType* at data pointer argv; datapoint = GenericParameterIndex) // genericInsts -> list of Il2CppGenericInst* (argc is count of Il2CppType* at data pointer argv; datapoint = GenericParameterIndex)
@@ -210,6 +215,18 @@ namespace Il2CppInspector
// methodReferences (<=16) -> list of uint // methodReferences (<=16) -> list of uint
// fieldOffsets (fieldOffsetsArePointers) -> either a list of data pointers (some zero, some VAs not mappable) to list of uints, or a list of uints // fieldOffsets (fieldOffsetsArePointers) -> either a list of data pointers (some zero, some VAs not mappable) to list of uints, or a list of uints
// metadataUsages (>=19, <27) -> list of unmappable data pointers // metadataUsages (>=19, <27) -> list of unmappable data pointers
// We can only perform this re-ordering if we can refer to a loaded global-metadata.dat
if (metadata == null)
return;
// Perform substitution
// TODO
// Force MetadataRegistration to pass validation in Il2CppBinary.Configure()
MetadataRegistration.typeDefinitionsSizesCount = 0;
MetadataRegistration.genericClassesCount = MetadataRegistration.genericInstsCount + 1;
MetadataRegistration.genericMethodTableCount = MetadataRegistration.genericInstsCount + 1;
} }
} }
} }