IL2CPP: Refactor reconstructor for single data read with multiple passes
This commit is contained in:
@@ -221,11 +221,10 @@ namespace Il2CppInspector
|
|||||||
if (metadata == null)
|
if (metadata == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
(ulong ptr, int count) types = (0, 0);
|
// Read in all the required data once since we'll be using nested loops
|
||||||
|
var metaPtrData = new List<(ulong, int, ulong[], ulong[], int, int, int)>();
|
||||||
|
|
||||||
// Determine what each pointer is
|
|
||||||
for (var i = 0; i < metaPtrsOrdered.Count; i++) {
|
for (var i = 0; i < metaPtrsOrdered.Count; i++) {
|
||||||
|
|
||||||
// Pointers in this list
|
// Pointers in this list
|
||||||
var ptrs = Image.ReadMappedArray<ulong>(metaPtrsOrdered[i], metaCountLimits[i]);
|
var ptrs = Image.ReadMappedArray<ulong>(metaPtrsOrdered[i], metaCountLimits[i]);
|
||||||
|
|
||||||
@@ -240,53 +239,91 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// First set of pointers that can be mapped into a data section in the image
|
// First set of pointers that can be mapped into a data section in the image
|
||||||
var ptrsMappableData = ptrs.Take(foundMappableCount)
|
var ptrsMappableData = ptrs.Take(foundMappableCount)
|
||||||
.TakeWhile(p => dataSections.Any(s => Image.MapVATR(p) >= s.ImageStart && Image.MapVATR(p) <= s.ImageEnd))
|
.TakeWhile(p => dataSections.Any(s => Image.MapVATR(p) >= s.ImageStart && Image.MapVATR(p) <= s.ImageEnd))
|
||||||
.ToList();
|
.ToArray();
|
||||||
|
|
||||||
var foundMappableDataCount = ptrsMappableData.Count;
|
var foundMappableDataCount = ptrsMappableData.Length;
|
||||||
|
|
||||||
// Test for Il2CppType**
|
metaPtrData.Add((metaPtrsOrdered[i], metaCountLimits[i], ptrs, ptrsMappableData, foundCount, foundMappableCount, foundMappableDataCount));
|
||||||
// We don't ever expect there to be less than 0x1000 types
|
}
|
||||||
if (foundMappableDataCount >= 0x1000) {
|
|
||||||
// This statement is quite slow. We could speed it up with a two-stage approach
|
|
||||||
var testTypes = Image.ReadMappedObjectPointerArray<Il2CppType>(metaPtrsOrdered[i], foundMappableDataCount);
|
|
||||||
|
|
||||||
var foundTypes = 0;
|
// Items we need to search for
|
||||||
foreach (var testType in testTypes) {
|
var types = (ptr: 0ul, count: -1);
|
||||||
// TODO: v27 will fail this because of the bit shifting in Il2CppType.bits
|
var genericInsts = (ptr: 0ul, count: -1);
|
||||||
if (testType.num_mods != 0)
|
|
||||||
break;
|
|
||||||
if (!Enum.IsDefined(typeof(Il2CppTypeEnum), testType.type))
|
|
||||||
break;
|
|
||||||
if (testType.type == Il2CppTypeEnum.IL2CPP_TYPE_END)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Test datapoint
|
// Determine what each pointer is
|
||||||
if (testType.type switch {
|
// We need to do this in a certain order because validating some items relies on earlier items
|
||||||
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE || t is Il2CppTypeEnum.IL2CPP_TYPE_CLASS)
|
while (metaPtrData.Any()) {
|
||||||
&& testType.datapoint >= (ulong) metadata.Types.Length => false,
|
|
||||||
|
|
||||||
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_VAR || t is Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
|
var foundTarget = 0ul;
|
||||||
&& testType.datapoint >= (ulong) metadata.GenericParameters.Length => false,
|
|
||||||
|
|
||||||
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_PTR || t is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
|
// We loop repeatedly through every set of data looking for our next target item,
|
||||||
&& !ptrsMappableData.Contains(testType.datapoint) => false,
|
// remove the matching set from the list and then repeat the outer while loop
|
||||||
|
// until there is nothing left to find
|
||||||
|
foreach (var (ptr, count, ptrs, ptrsMappableData, foundCount, foundMappableCount, foundMappableDataCount) in metaPtrData) {
|
||||||
|
|
||||||
// Untested cases, we could add more here (IL2CPP_TYPE_ARRAY, IL2CPP_TYPE_GENERICINST)
|
// Test for Il2CppType**
|
||||||
_ => true
|
// ---------------------
|
||||||
})
|
if (types.ptr == 0) {
|
||||||
foundTypes++;
|
|
||||||
else
|
// We don't ever expect there to be less than 0x1000 types
|
||||||
break;
|
if (foundMappableDataCount >= 0x1000) {
|
||||||
}
|
|
||||||
if (foundTypes >= 0x1000) {
|
// This statement is quite slow. We could speed it up with a two-stage approach
|
||||||
types = (metaPtrsOrdered[i], foundTypes);
|
var testTypes = Image.ReadMappedObjectPointerArray<Il2CppType>(ptr, foundMappableDataCount);
|
||||||
|
|
||||||
|
var foundTypes = 0;
|
||||||
|
foreach (var testType in testTypes) {
|
||||||
|
// TODO: v27 will fail this because of the bit shifting in Il2CppType.bits
|
||||||
|
if (testType.num_mods != 0)
|
||||||
|
break;
|
||||||
|
if (!Enum.IsDefined(typeof(Il2CppTypeEnum), testType.type))
|
||||||
|
break;
|
||||||
|
if (testType.type == Il2CppTypeEnum.IL2CPP_TYPE_END)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Test datapoint
|
||||||
|
if (testType.type switch {
|
||||||
|
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE || t is Il2CppTypeEnum.IL2CPP_TYPE_CLASS)
|
||||||
|
&& testType.datapoint >= (ulong) metadata.Types.Length => false,
|
||||||
|
|
||||||
|
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_VAR || t is Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
|
||||||
|
&& testType.datapoint >= (ulong) metadata.GenericParameters.Length => false,
|
||||||
|
|
||||||
|
var t when (t is Il2CppTypeEnum.IL2CPP_TYPE_PTR || t is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
|
||||||
|
&& !ptrsMappableData.Contains(testType.datapoint) => false,
|
||||||
|
|
||||||
|
// Untested cases, we could add more here (IL2CPP_TYPE_ARRAY, IL2CPP_TYPE_GENERICINST)
|
||||||
|
_ => true
|
||||||
|
})
|
||||||
|
foundTypes++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (foundTypes >= 0x1000) {
|
||||||
|
types = (ptr, foundTypes);
|
||||||
|
foundTarget = ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for Il2CppGenericInst**
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Successfully found the item we were looking for; remove it from the list
|
||||||
|
if (foundTarget != 0ul)
|
||||||
|
metaPtrData = metaPtrData.Where(m => foundTarget != m.Item1).ToList();
|
||||||
|
|
||||||
|
// We didn't find anything - break to avoid an infinite loop
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Debugging validation checks
|
#region Debugging validation checks
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// Used on non-obfuscated binaries during development to confirm the output is correct
|
// Used on non-obfuscated binaries during development to confirm the output is correct
|
||||||
if (types.ptr != MetadataRegistration.ptypes)
|
if (types.ptr != MetadataRegistration.ptypes)
|
||||||
throw new Exception("Il2CppType** incorrect");
|
throw new Exception("Il2CppType** incorrect");
|
||||||
@@ -299,6 +336,8 @@ namespace Il2CppInspector
|
|||||||
// Perform substitution
|
// Perform substitution
|
||||||
MetadataRegistration.ptypes = types.ptr;
|
MetadataRegistration.ptypes = types.ptr;
|
||||||
MetadataRegistration.typesCount = types.count;
|
MetadataRegistration.typesCount = types.count;
|
||||||
|
MetadataRegistration.genericInsts = genericInsts.ptr;
|
||||||
|
MetadataRegistration.genericInstsCount = genericInsts.count;
|
||||||
|
|
||||||
// Force MetadataRegistration to pass validation in Il2CppBinary.Configure()
|
// Force MetadataRegistration to pass validation in Il2CppBinary.Configure()
|
||||||
MetadataRegistration.typeDefinitionsSizesCount = 0;
|
MetadataRegistration.typeDefinitionsSizesCount = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user