IL2CPP: Refactor loaders in Il2CppBinary
This commit is contained in:
@@ -105,12 +105,13 @@ namespace Il2CppInspector
|
||||
return (Il2CppBinary) Activator.CreateInstance(type, stream[0]);
|
||||
}
|
||||
|
||||
// Load binary without a global-metadata.dat available
|
||||
public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion) {
|
||||
var inst = LoadImpl(stream);
|
||||
// Try to process the IL2CPP image; return the instance if succeeded, otherwise null
|
||||
return inst.InitializeWithoutMetadata(metadataVersion) ? inst : null;
|
||||
return inst.Initialize(metadataVersion) ? inst : null;
|
||||
}
|
||||
|
||||
// Load binary with a global-metadata.dat available
|
||||
// Supplying the Metadata class when loading a binary is optional
|
||||
// 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
|
||||
@@ -120,32 +121,30 @@ namespace Il2CppInspector
|
||||
return inst.Initialize(metadata) ? inst : null;
|
||||
}
|
||||
|
||||
// Architecture-specific search function
|
||||
protected abstract (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc);
|
||||
// Initialize binary without a global-metadata.dat available
|
||||
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) {
|
||||
Image.Version = metadata.Version;
|
||||
|
||||
if (InitializeWithoutMetadata(metadata.Version))
|
||||
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");
|
||||
if (!((FindMetadataFromSymbols() ?? FindMetadataFromCode() ?? FindMetadataFromData(metadata)) is var ptrs))
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine("Required structures acquired from data heuristics");
|
||||
Configure(codePtr, metadataPtr);
|
||||
Configure(ptrs.Value.Item1, ptrs.Value.Item2, metadata);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to find data structures via symbol table lookup and init function code analysis
|
||||
public bool InitializeWithoutMetadata(double version) {
|
||||
Image.Version = version;
|
||||
|
||||
// Try to find data structures via symbol table lookup
|
||||
private (ulong, ulong)? FindMetadataFromSymbols() {
|
||||
// Try searching the symbol table
|
||||
var symbols = Image.GetSymbolTable();
|
||||
|
||||
@@ -162,20 +161,20 @@ namespace Il2CppInspector
|
||||
|
||||
if (code != null && metadata != null) {
|
||||
Console.WriteLine("Required structures acquired from symbol lookup");
|
||||
Configure(code.VirtualAddress, metadata.VirtualAddress);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return (code.VirtualAddress, metadata.VirtualAddress);
|
||||
} else {
|
||||
Console.WriteLine("No matches in symbol table");
|
||||
}
|
||||
}
|
||||
else if (symbols != null) {
|
||||
} else if (symbols != null) {
|
||||
Console.WriteLine("No symbol table present in binary file");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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
|
||||
var addrs = Image.GetFunctionTable();
|
||||
|
||||
@@ -187,16 +186,32 @@ namespace Il2CppInspector
|
||||
if (code != 0) {
|
||||
RegistrationFunctionPointer = loc + Image.GlobalOffset;
|
||||
Console.WriteLine("Required structures acquired from code heuristics. Initialization function: 0x{0:X16}", RegistrationFunctionPointer);
|
||||
Configure(code, metadata);
|
||||
return true;
|
||||
return (code, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
CodeRegistrationPointer = codeRegistration;
|
||||
MetadataRegistrationPointer = metadataRegistration;
|
||||
@@ -209,7 +224,7 @@ namespace Il2CppInspector
|
||||
MetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
|
||||
// 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
|
||||
/*
|
||||
@@ -226,9 +241,7 @@ namespace Il2CppInspector
|
||||
|| CodeRegistration.unresolvedVirtualCallCount > 0x4000 // >= 22
|
||||
|| CodeRegistration.interopDataCount > 0x1000 // >= 23
|
||||
|| (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.");
|
||||
|
||||
// TODO: Determine the correct field order for MetadataRegistration and CodeRegistration (#44, #98)
|
||||
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.");
|
||||
|
||||
// The global method pointer list was deprecated in v24.2 in favour of Il2CppCodeGenModule
|
||||
if (Image.Version <= 24.1)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Il2CppInspector
|
||||
}
|
||||
|
||||
// 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 (!Image.TryGetSections(out var sections))
|
||||
return;
|
||||
@@ -201,6 +201,11 @@ namespace Il2CppInspector
|
||||
CodeRegistration.pmethodPointers = methodPointers.Key;
|
||||
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
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user