IL2CPP: Refactor loaders in Il2CppBinary
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user