migrate versioning to StructVersion class, add handling/detection for 29.2/31.2

This commit is contained in:
LukeFZ
2024-08-13 15:00:20 +02:00
parent 22ecdc3612
commit 23e873280d
24 changed files with 181 additions and 84 deletions

View File

@@ -5,6 +5,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -342,10 +343,10 @@ namespace Il2CppInspector
// In v21 and later, R0-R2 + PC will be set and they will be the only registers set
// Pre-v21, R0-R1 + PC will be the only registers set
if (image.Version >= 21 && regs.Count == 4 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1) && regs.TryGetValue(2, out uint _))
if (image.Version >= MetadataVersions.V210 && regs.Count == 4 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1) && regs.TryGetValue(2, out uint _))
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
if (image.Version < 21 && regs.Count == 3 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1))
if (image.Version < MetadataVersions.V210 && regs.Count == 3 && regs.TryGetValue(0, out r0) && regs.TryGetValue(1, out r1))
return (r0 & 0xffff_fffe, r1 & 0xffff_fffe);
return (0, 0);

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Generic;
@@ -168,10 +169,10 @@ namespace Il2CppInspector
// Is it Il2CppCodegenRegistration(void)?
// In v21 and later, X0-X2 will be set and they will be the only registers set
// Pre-v21, X0-X1 will be the only registers set
if (image.Version >= 21 && regs.Count == 3 && regs.TryGetValue(0, out ulong x0) && regs.TryGetValue(1, out x1) && regs.TryGetValue(2, out ulong _))
if (image.Version >= MetadataVersions.V210 && regs.Count == 3 && regs.TryGetValue(0, out ulong x0) && regs.TryGetValue(1, out x1) && regs.TryGetValue(2, out ulong _))
return (x0, x1);
if (image.Version < 21 && regs.Count == 2 && regs.TryGetValue(0, out x0) && regs.TryGetValue(1, out x1))
if (image.Version < MetadataVersions.V210 && regs.Count == 2 && regs.TryGetValue(0, out x0) && regs.TryGetValue(1, out x1))
return (x0, x1);
return (0, 0);

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -216,7 +217,7 @@ namespace Il2CppInspector
offset = nextLea?.foundOffset + leaSize ?? buff2Size;
}
if ((image.Version < 21 && leas.Count == 2) || (image.Version >= 21 && leas.Count == 3)) {
if ((image.Version < MetadataVersions.V210 && leas.Count == 2) || (image.Version >= MetadataVersions.V210 && leas.Count == 3)) {
// Register-based argument passing?
var leaRSI = leas.FirstOrDefault(l => l.Value == RSI).Key.address;
var leaRDI = leas.FirstOrDefault(l => l.Value == RDI).Key.address;

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Linq;
@@ -34,7 +35,7 @@ namespace Il2CppInspector
return (0, 0);
// Jump to Il2CppCodegenRegistration
if(image.Version < 21) {
if(image.Version < MetadataVersions.V210) {
image.Position = image.MapVATR((ulong)pCgr + 1);
metadata = image.ReadUInt32();
image.Position = image.MapVATR((ulong)pCgr + 6);

View File

@@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text.RegularExpressions;
using Il2CppInspector.Next;
using VersionedSerialization;
namespace Il2CppInspector.Cpp.UnityHeaders
{
@@ -19,7 +21,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
public class UnityHeaders : IEquatable<UnityHeaders>
{
// Metadata version for which this group of headers are valid. Multiple headers may have the same metadata version
public double MetadataVersion { get; }
public StructVersion MetadataVersion { get; }
// Range of Unity versions for which this group of headers are valid
public UnityVersionRange VersionRange { get; }
@@ -114,7 +116,7 @@ namespace Il2CppInspector.Cpp.UnityHeaders
if (metadataVersion != binary.Image.Version)
continue;
if (metadataVersion == 21) {
if (metadataVersion == MetadataVersions.V210) {
/* Special version logic for metadata version 21 based on the Il2CppMetadataRegistration.fieldOffsets field */
var headerFieldOffsetsArePointers = r.VersionRange.Min.CompareTo("5.3.7") >= 0 && r.VersionRange.Min.CompareTo("5.4.0") != 0;
var binaryFieldOffsetsArePointers = binary.FieldOffsets == null;
@@ -194,8 +196,8 @@ namespace Il2CppInspector.Cpp.UnityHeaders
}
// Get the metadata version from a type header resource name
private static double GetMetadataVersionFromFilename(string resourceName)
=> double.Parse(resourceName.Substring(typeof(UnityHeaders).Namespace.Length + 1).Split('-')[0], NumberFormatInfo.InvariantInfo);
private static StructVersion GetMetadataVersionFromFilename(string resourceName)
=> resourceName[(typeof(UnityHeaders).Namespace!.Length + 1)..].Split('-')[0];
// Equality comparisons
public static bool operator ==(UnityHeaders first, UnityHeaders second) {

View File

@@ -11,12 +11,13 @@ using System.Linq;
using System.Reflection;
using System.Text;
using NoisyCowStudios.Bin2Object;
using VersionedSerialization;
namespace Il2CppInspector
{
public interface IFileFormatStream
{
double Version { get; set; }
StructVersion Version { get; set; }
long Length { get; }
uint NumImages { get; }
string DefaultFilename { get; }

View File

@@ -5,6 +5,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -12,6 +13,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using VersionedSerialization;
namespace Il2CppInspector
{
@@ -135,7 +137,7 @@ namespace Il2CppInspector
}
// Load binary without a global-metadata.dat available
public static Il2CppBinary Load(IFileFormatStream stream, double metadataVersion, EventHandler<string> statusCallback = null) {
public static Il2CppBinary Load(IFileFormatStream stream, StructVersion metadataVersion, EventHandler<string> statusCallback = null) {
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
var inst = LoadImpl(stream, statusCallback);
if (inst.FindRegistrationStructs(metadataVersion))
@@ -167,7 +169,7 @@ namespace Il2CppInspector
}
// Initialize binary without a global-metadata.dat available
public bool FindRegistrationStructs(double metadataVersion) {
public bool FindRegistrationStructs(StructVersion metadataVersion) {
Image.Version = metadataVersion;
StatusUpdate("Searching for binary metadata");
@@ -282,21 +284,22 @@ namespace Il2CppInspector
// genericAdjustorThunks was inserted before invokerPointersCount in 24.5 and 27.1
// pointer expected if we need to bump version
if (Image.Version == 24.4 && CodeRegistration.invokerPointersCount > 0x50000)
if (Image.Version == MetadataVersions.V244 && CodeRegistration.invokerPointersCount > 0x50000)
{
Image.Version = 24.5;
Image.Version = MetadataVersions.V245;
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
}
if (Image.Version == 24.4 && CodeRegistration.reversePInvokeWrapperCount > 0x50000) {
Image.Version = 24.5;
if (Image.Version == MetadataVersions.V244 && CodeRegistration.reversePInvokeWrapperCount > 0x50000) {
Image.Version = MetadataVersions.V245;
codeRegistration -= 1 * pointerSize;
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
}
if (Image.Version == 29 && (long)CodeRegistration.genericMethodPointersCount - MetadataRegistration.genericMethodTableCount > 0x10000)
if ((Image.Version == MetadataVersions.V290 || Image.Version == MetadataVersions.V310) &&
(long)CodeRegistration.genericMethodPointersCount - MetadataRegistration.genericMethodTableCount > 0x10000)
{
Image.Version = 29.1;
Image.Version = new StructVersion(Image.Version.Major, 1, Image.Version.Tag);
codeRegistration -= 2 * pointerSize;
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
}
@@ -317,21 +320,21 @@ namespace Il2CppInspector
|| CodeRegistration.reversePInvokeWrapperCount > 0x10000
|| CodeRegistration.unresolvedVirtualCallCount > 0x4000 // >= 22
|| CodeRegistration.interopDataCount > 0x1000 // >= 23
|| (Image.Version <= 24.1 && CodeRegistration.invokerPointersCount > CodeRegistration.methodPointersCount))
|| (Image.Version <= MetadataVersions.V241 && 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 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)
if (Image.Version <= MetadataVersions.V241)
GlobalMethodPointers = Image.ReadMappedArray<ulong>(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount);
// After v24 method pointers and RGCTX data were stored in Il2CppCodeGenModules
if (Image.Version >= 24.2) {
if (Image.Version >= MetadataVersions.V242) {
Modules = new Dictionary<string, Il2CppCodeGenModule>();
// In v24.3, windowsRuntimeFactoryTable collides with codeGenModules. So far no samples have had windowsRuntimeFactoryCount > 0;
// if this changes we'll have to get smarter about disambiguating these two.
if (CodeRegistration.codeGenModulesCount == 0) {
Image.Version = 24.3;
Image.Version = MetadataVersions.V243;
CodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
}
@@ -364,10 +367,10 @@ namespace Il2CppInspector
// Field offset data. Metadata <=21.x uses a value-type array; >=21.x uses a pointer array
// Versions from 22 onwards use an array of pointers in Binary.FieldOffsetData
bool fieldOffsetsArePointers = (Image.Version >= 22);
bool fieldOffsetsArePointers = (Image.Version >= MetadataVersions.V220);
// Some variants of 21 also use an array of pointers
if (Image.Version == 21) {
if (Image.Version == MetadataVersions.V210) {
var fieldTest = Image.ReadMappedWordArray(MetadataRegistration.pfieldOffsets, 6);
// We detect this by relying on the fact Module, Object, ValueType, Attribute, _Attribute and Int32
@@ -386,7 +389,7 @@ namespace Il2CppInspector
TypeReferenceIndicesByAddress = typeRefPointers.Zip(Enumerable.Range(0, typeRefPointers.Length), (a, i) => new { a, i }).ToDictionary(x => x.a, x => x.i);
TypeReferences =
Image.Version >= 27.2
Image.Version >= MetadataVersions.V272
? Image.ReadMappedObjectPointerArray<Il2CppTypeV272>(MetadataRegistration.ptypes, (int) MetadataRegistration.typesCount)
.Cast<Il2CppType>()
.ToList()
@@ -394,7 +397,7 @@ namespace Il2CppInspector
// Custom attribute constructors (function pointers)
// This is managed in Il2CppInspector for metadata >= 27
if (Image.Version < 27) {
if (Image.Version < MetadataVersions.V270) {
CustomAttributeGenerators = Image.ReadMappedArray<ulong>(CodeRegistration.customAttributeGenerators, (int) CodeRegistration.customAttributeCount);
}
@@ -408,7 +411,7 @@ namespace Il2CppInspector
// >=22: unresolvedVirtualCallPointers
// >=23: interopData
if (Image.Version < 19) {
if (Image.Version < MetadataVersions.V190) {
VTableMethodReferences = Image.ReadMappedArray<uint>(MetadataRegistration.methodReferences, (int)MetadataRegistration.methodReferencesCount);
}

View File

@@ -60,15 +60,19 @@ namespace Il2CppInspector
[Version(Min = 22, Max = 29)]
public ulong unresolvedVirtualCallCount;
[Version(Min = 29.1)]
[Version(Min = 29.1, Max = 29.2)]
[Version(Min = 31.1, Max = 31.2)]
public ulong unresolvedIndirectCallCount;
[Version(Min = 22)]
public ulong unresolvedVirtualCallPointers;
[Version(Min = 29.1)]
[Version(Min = 29.1, Max = 29.2)]
[Version(Min = 31.1, Max = 31.2)]
public ulong unresolvedInstanceCallPointers;
[Version(Min = 29.1)]
[Version(Min = 29.1, Max = 29.2)]
[Version(Min = 31.1, Max = 31.2)]
public ulong unresolvedStaticCallPointers;
// Added in metadata v23

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using Il2CppInspector.Utils;
using NoisyCowStudios.Bin2Object;
using System;
@@ -12,6 +13,7 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using VersionedSerialization;
namespace Il2CppInspector
{
@@ -31,7 +33,9 @@ namespace Il2CppInspector
public List<MetadataUsage> MetadataUsages { get; }
// Shortcuts
public double Version => Math.Max(Metadata.Version, Binary.Image.Version);
public StructVersion Version => Metadata.Version > Binary.Image.Version
? Metadata.Version
: Binary.Image.Version;
public Dictionary<int, string> Strings => Metadata.Strings;
public string[] StringLiterals => Metadata.StringLiterals;
@@ -93,11 +97,11 @@ namespace Il2CppInspector
private List<MetadataUsage> buildMetadataUsages()
{
// No metadata usages for versions < 19
if (Version < 19)
if (Version < MetadataVersions.V190)
return null;
// Metadata usages are lazily initialized during runtime for versions >= 27
if (Version >= 27)
if (Version >= MetadataVersions.V270)
return buildLateBindingMetadataUsages();
// Version >= 19 && < 27
@@ -217,9 +221,9 @@ namespace Il2CppInspector
}
// Build list of custom attribute generators
if (Version < 27)
if (Version < MetadataVersions.V270)
CustomAttributeGenerators = Binary.CustomAttributeGenerators;
else if (Version < 29)
else if (Version < MetadataVersions.V290)
{
var cagCount = Images.Sum(i => i.customAttributeCount);
CustomAttributeGenerators = new ulong[cagCount];
@@ -243,7 +247,7 @@ namespace Il2CppInspector
// Get sorted list of function pointers from all sources
// TODO: This does not include IL2CPP API functions
var sortedFunctionPointers = (Version <= 24.1)?
var sortedFunctionPointers = (Version <= MetadataVersions.V241) ?
Binary.GlobalMethodPointers.Select(getDecodedAddress).ToList() :
Binary.ModuleMethodPointers.SelectMany(module => module.Value).Select(getDecodedAddress).ToList();
@@ -261,7 +265,7 @@ namespace Il2CppInspector
FunctionAddresses.Add(sortedFunctionPointers[^1], sortedFunctionPointers[^1]);
// Organize custom attribute indices
if (Version >= 24.1) {
if (Version >= MetadataVersions.V241) {
AttributeIndicesByToken = [];
foreach (var image in Images)
{
@@ -269,7 +273,7 @@ namespace Il2CppInspector
for (int i = 0; i < image.customAttributeCount; i++)
{
var index = image.customAttributeStart + i;
var token = Version >= 29 ? AttributeDataRanges[index].token : AttributeTypeRanges[index].token;
var token = Version >= MetadataVersions.V290 ? AttributeDataRanges[index].token : AttributeTypeRanges[index].token;
attsByToken.Add(token, index);
}
@@ -294,13 +298,13 @@ namespace Il2CppInspector
ulong start = 0;
// Global method pointer array
if (Version <= 24.1) {
if (Version <= MetadataVersions.V241) {
start = Binary.GlobalMethodPointers[methodDef.methodIndex];
}
// Per-module method pointer array uses the bottom 24 bits of the method's metadata token
// Derived from il2cpp::vm::MetadataCache::GetMethodPointer
if (Version >= 24.2) {
if (Version >= MetadataVersions.V242) {
var method = (methodDef.token & 0xffffff);
if (method == 0)
return null;
@@ -335,7 +339,7 @@ namespace Il2CppInspector
// Get a method invoker index from a method definition
public int GetInvokerIndex(Il2CppCodeGenModule module, Il2CppMethodDefinition methodDef) {
if (Version <= 24.1) {
if (Version <= MetadataVersions.V241) {
return methodDef.invokerIndex;
}

View File

@@ -9,6 +9,7 @@ using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Il2CppInspector.Next;
namespace Il2CppInspector
{
@@ -120,7 +121,7 @@ namespace Il2CppInspector
// Find CodeRegistration
// >= 24.2
if (metadata.Version >= 24.2) {
if (metadata.Version >= MetadataVersions.V242) {
// < 27: mscorlib.dll is always the first CodeGenModule
// >= 27: mscorlib.dll is always the last CodeGenModule (Assembly-CSharp.dll is always the first but non-Unity builds don't have this DLL)
@@ -137,7 +138,7 @@ namespace Il2CppInspector
// Unwind from string pointer -> CodeGenModule -> CodeGenModules + x
foreach (var potentialCodeGenModules in FindAllPointerChains(imageBytes, va, 2))
{
if (metadata.Version >= 27)
if (metadata.Version >= MetadataVersions.V270)
{
for (int i = imagesCount - 1; i >= 0; i--)
{
@@ -210,16 +211,16 @@ namespace Il2CppInspector
// if this changes we'll have to get smarter about disambiguating these two.
var cr = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
if (Image.Version == 24.2 && cr.interopDataCount == 0) {
Image.Version = 24.3;
if (Image.Version == MetadataVersions.V242 && cr.interopDataCount == 0) {
Image.Version = MetadataVersions.V243;
codeRegistration -= ptrSize * 2; // two extra words for WindowsRuntimeFactory
}
if (Image.Version == 27 && cr.reversePInvokeWrapperCount > 0x30000)
if (Image.Version == MetadataVersions.V270 && cr.reversePInvokeWrapperCount > 0x30000)
{
// If reversePInvokeWrapperCount is a pointer, then it's because we're actually on 27.1 and there's a genericAdjustorThunks pointer interfering.
// We need to bump version to 27.1 and back up one more pointer.
Image.Version = 27.1;
Image.Version = MetadataVersions.V271;
codeRegistration -= ptrSize;
}
}
@@ -259,7 +260,7 @@ namespace Il2CppInspector
vas = FindAllMappedWords(imageBytes, typesLength).Select(a => a - mrSize + ptrSize * 4);
// >= 19 && < 27
if (Image.Version < 27)
if (Image.Version < MetadataVersions.V270)
foreach (var va in vas) {
var mr = Image.ReadMappedObject<Il2CppMetadataRegistration>(va);
if (mr.metadataUsagesCount == (ulong) metadata.MetadataUsageLists.Length)

View File

@@ -10,7 +10,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Il2CppInspector.Next;
using NoisyCowStudios.Bin2Object;
using VersionedSerialization;
namespace Il2CppInspector
{
@@ -86,9 +88,9 @@ namespace Il2CppInspector
}
// Set object versioning for Bin2Object from metadata version
Version = Header.version;
Version = new StructVersion(Header.version);
if (Version < 16 || Version > 31) {
if (Version < MetadataVersions.V160 || Version > MetadataVersions.V310) {
throw new InvalidOperationException($"The supplied metadata file is not of a supported version ({Header.version}).");
}
@@ -108,8 +110,8 @@ namespace Il2CppInspector
var realHeaderLength = Header.stringLiteralOffset;
if (realHeaderLength != Sizeof(typeof(Il2CppGlobalMetadataHeader))) {
if (Version == 24.0) {
Version = 24.2;
if (Version == MetadataVersions.V240) {
Version = MetadataVersions.V242;
Header = ReadObject<Il2CppGlobalMetadataHeader>(0);
}
}
@@ -120,16 +122,16 @@ namespace Il2CppInspector
}
// Load all the relevant metadata using offsets provided in the header
if (Version >= 16)
if (Version >= MetadataVersions.V160)
Images = ReadArray<Il2CppImageDefinition>(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition)));
// As an additional sanity check, all images in the metadata should have Mono.Cecil.MetadataToken == 1
// In metadata v24.1, two extra fields were added which will cause the below test to fail.
// In that case, we can then adjust the version number and reload
// Tokens were introduced in v19 - we don't bother testing earlier versions
if (Version >= 19 && Images.Any(x => x.token != 1))
if (Version == 24.0) {
Version = 24.1;
if (Version >= MetadataVersions.V190 && Images.Any(x => x.token != 1))
if (Version == MetadataVersions.V240) {
Version = MetadataVersions.V241;
// No need to re-read the header, it's the same for both sub-versions
Images = ReadArray<Il2CppImageDefinition>(Header.imagesOffset, Header.imagesCount / Sizeof(typeof(Il2CppImageDefinition)));
@@ -153,44 +155,63 @@ namespace Il2CppInspector
InterfaceOffsets = ReadArray<Il2CppInterfaceOffsetPair>(Header.interfaceOffsetsOffset, Header.interfaceOffsetsCount / Sizeof(typeof(Il2CppInterfaceOffsetPair)));
VTableMethodIndices = ReadArray<uint>(Header.vtableMethodsOffset, Header.vtableMethodsCount / sizeof(uint));
if (Version >= 16) {
if (Version >= MetadataVersions.V160) {
// In v24.4 hashValueIndex was removed from Il2CppAssemblyNameDefinition, which is a field in Il2CppAssemblyDefinition
// The number of images and assemblies should be the same. If they are not, we deduce that we are using v24.4
// Note the version comparison matches both 24.2 and 24.3 here since 24.3 is tested for during binary loading
var assemblyCount = Header.assembliesCount / Sizeof(typeof(Il2CppAssemblyDefinition));
var changedAssemblyDefStruct = false;
if ((Version == 24.1 || Version == 24.2 || Version == 24.3) && assemblyCount < Images.Length)
if ((Version == MetadataVersions.V241 || Version == MetadataVersions.V242 || Version == MetadataVersions.V243) && assemblyCount < Images.Length)
{
if (Version == 24.1)
if (Version == MetadataVersions.V241)
changedAssemblyDefStruct = true;
Version = 24.4;
Version = MetadataVersions.V244;
}
Assemblies = ReadArray<Il2CppAssemblyDefinition>(Header.assembliesOffset, Images.Length);
if (changedAssemblyDefStruct)
Version = 24.1;
Version = MetadataVersions.V241;
ParameterDefaultValues = ReadArray<Il2CppParameterDefaultValue>(Header.parameterDefaultValuesOffset, Header.parameterDefaultValuesCount / Sizeof(typeof(Il2CppParameterDefaultValue)));
}
if (Version >= 19 && Version < 27) {
if (Version >= MetadataVersions.V190 && Version < MetadataVersions.V270) {
MetadataUsageLists = ReadArray<Il2CppMetadataUsageList>(Header.metadataUsageListsOffset, Header.metadataUsageListsCount / Sizeof(typeof(Il2CppMetadataUsageList)));
MetadataUsagePairs = ReadArray<Il2CppMetadataUsagePair>(Header.metadataUsagePairsOffset, Header.metadataUsagePairsCount / Sizeof(typeof(Il2CppMetadataUsagePair)));
}
if (Version >= 19) {
if (Version >= MetadataVersions.V190) {
FieldRefs = ReadArray<Il2CppFieldRef>(Header.fieldRefsOffset, Header.fieldRefsCount / Sizeof(typeof(Il2CppFieldRef)));
}
if (Version >= 21 && Version < 29) {
if (Version >= MetadataVersions.V210 && Version < MetadataVersions.V290) {
AttributeTypeIndices = ReadArray<int>(Header.attributeTypesOffset, Header.attributeTypesCount / sizeof(int));
AttributeTypeRanges = ReadArray<Il2CppCustomAttributeTypeRange>(Header.attributesInfoOffset, Header.attributesInfoCount / Sizeof(typeof(Il2CppCustomAttributeTypeRange)));
}
if (Version >= 29)
if (Version >= MetadataVersions.V290)
{
AttributeDataRanges = ReadArray<Il2CppCustomAttributeDataRange>(Header.attributeDataRangeOffset,
Header.attributeDataRangeSize / Sizeof(typeof(Il2CppCustomAttributeDataRange)));
}
if (Version == MetadataVersions.V290 || Version == MetadataVersions.V310)
{
// 29.2/31.2 added a new isUnmanagedCallersOnly flag to Il2CppMethodDefinition.
// This offsets all subsequent entries by one - we can detect this by checking the
// top token byte (which should always be 0x06).
if (Methods.Length >= 2)
{
var secondToken = Methods[1].token;
if (secondToken >> 24 != 0x6)
{
Version = new StructVersion(Version.Major, 1, Version.Tag);
Methods = ReadArray<Il2CppMethodDefinition>(Header.methodsOffset,
Header.methodsCount / Sizeof(typeof(Il2CppMethodDefinition)));
}
}
}
// Get all metadata strings
var pluginGetStringsResult = PluginHooks.GetStrings(this);
if (pluginGetStringsResult.IsDataModified && !pluginGetStringsResult.IsInvalid)
@@ -229,7 +250,9 @@ namespace Il2CppInspector
public int Sizeof(Type type) => Sizeof(type, Version);
public int Sizeof(Type type, double metadataVersion, int longSizeBytes = 8) {
public int Sizeof(Type type, StructVersion metadataVersion, int longSizeBytes = 8)
{
var doubleRepresentation = metadataVersion.AsDouble;
if (Reader.ObjectMappings.TryGetValue(type, out var streamType))
type = streamType;
@@ -239,7 +262,7 @@ namespace Il2CppInspector
{
// Only process fields for our selected object versioning (always process if none supplied)
var versions = i.GetCustomAttributes<VersionAttribute>(false).Select(v => (v.Min, v.Max)).ToList();
if (versions.Any() && !versions.Any(v => (v.Min <= metadataVersion || v.Min == -1) && (v.Max >= metadataVersion || v.Max == -1)))
if (versions.Any() && !versions.Any(v => (v.Min <= doubleRepresentation || v.Min == -1) && (v.Max >= doubleRepresentation || v.Max == -1)))
continue;
if (i.FieldType == typeof(long) || i.FieldType == typeof(ulong))

View File

@@ -342,7 +342,8 @@ namespace Il2CppInspector
public ushort slot;
public ushort parameterCount;
[Version(Min = 29.2, Max = 31)]
[Version(Min = 29.2, Max = 29.2)]
[Version(Min = 31.2, Max = 31.2)]
public bool isUnmanagedCallersOnly;
}

View File

@@ -6,6 +6,8 @@
All rights reserved.
*/
using Il2CppInspector.Next;
namespace Il2CppInspector
{
public enum MetadataUsageType
@@ -34,7 +36,7 @@ namespace Il2CppInspector
public static MetadataUsage FromEncodedIndex(Il2CppInspector package, uint encodedIndex, ulong virtualAddress = 0) {
uint index;
MetadataUsageType usageType;
if (package.Version < 19) {
if (package.Version < MetadataVersions.V190) {
/* These encoded indices appear only in vtables, and are decoded by IsGenericMethodIndex/GetDecodedMethodIndex */
var isGeneric = encodedIndex & 0x80000000;
index = package.Binary.VTableMethodReferences[encodedIndex & 0x7FFFFFFF];
@@ -46,7 +48,7 @@ namespace Il2CppInspector
index = encodedIndex & 0x1FFFFFFF;
// From v27 the bottom bit is set to indicate the usage token hasn't been replaced with a pointer at runtime yet
if (package.Version >= 27)
if (package.Version >= MetadataVersions.V270)
index >>= 1;
}
return new MetadataUsage(usageType, (int)index, virtualAddress);

View File

@@ -47,6 +47,8 @@
<ItemGroup>
<ProjectReference Include="..\Bin2Object\Bin2Object\Bin2Object.csproj" PrivateAssets="all" />
<ProjectReference Include="..\VersionedSerialization.Generator\VersionedSerialization.Generator.csproj" ReferenceOutputAssembly="false" OutputType="Analyzer" />
<ProjectReference Include="..\VersionedSerialization\VersionedSerialization.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Il2CppInspector.Cpp;
using Il2CppInspector.Next;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Model
@@ -123,7 +124,7 @@ namespace Il2CppInspector.Model
Add(binary.CodeRegistrationPointer, binary.CodeRegistration);
Add(binary.MetadataRegistrationPointer, binary.MetadataRegistration);
if (Model.Package.Version >= 24.2) {
if (Model.Package.Version >= MetadataVersions.V242) {
// TODO: Add some kind of AppArray composite type for arrays as we'll be adding more later
Add(binary.CodeRegistration.pcodeGenModules, binary.CodeGenModulePointers);

View File

@@ -12,6 +12,7 @@ using System.Linq;
using Aron.Weiler;
using Il2CppInspector.Cpp;
using Il2CppInspector.Cpp.UnityHeaders;
using Il2CppInspector.Next;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Model
@@ -54,7 +55,7 @@ namespace Il2CppInspector.Model
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
public bool StringIndexesAreOrdinals => Package.Version < 19;
public bool StringIndexesAreOrdinals => Package.Version < MetadataVersions.V190;
// The .NET type model for the application
public TypeModel TypeModel { get; }
@@ -270,7 +271,7 @@ namespace Il2CppInspector.Model
}
// Add string literals for metadata <19 to the model
if (Package.Version < 19) {
if (Package.Version < MetadataVersions.V190) {
/* Version < 19 calls `il2cpp_codegen_string_literal_from_index` to get string literals.
* Unfortunately, metadata references are just loose globals in Il2CppMetadataUsage.cpp
* so we can't automatically name those. Next best thing is to define an enum for the strings. */

View File

@@ -0,0 +1,33 @@
using VersionedSerialization;
namespace Il2CppInspector.Next;
public static class MetadataVersions
{
public static readonly StructVersion V160 = new(16);
public static readonly StructVersion V190 = new(19);
public static readonly StructVersion V210 = new(21);
public static readonly StructVersion V220 = new(22);
public static readonly StructVersion V240 = new(24);
public static readonly StructVersion V241 = new(24, 1);
public static readonly StructVersion V242 = new(24, 2);
public static readonly StructVersion V243 = new(24, 3);
public static readonly StructVersion V244 = new(24, 4);
public static readonly StructVersion V245 = new(24, 5);
public static readonly StructVersion V270 = new(27);
public static readonly StructVersion V271 = new(27, 1);
public static readonly StructVersion V272 = new(27, 2);
public static readonly StructVersion V290 = new(29);
public static readonly StructVersion V310 = new(31);
public static readonly StructVersion V291 = new(29, 1);
public static readonly StructVersion V311 = new(31, 1);
public static readonly StructVersion V292 = new(29, 2);
public static readonly StructVersion V312 = new(31, 2);
}

View File

@@ -12,6 +12,7 @@ using System.IO;
using System.Linq;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Il2CppInspector.Next;
using Il2CppInspector.Reflection;
namespace Il2CppInspector.Outputs
@@ -591,7 +592,7 @@ namespace Il2CppInspector.Outputs
// Create folder for DLLs
Directory.CreateDirectory(outputPath);
if (model.Package.Version >= 29)
if (model.Package.Version >= MetadataVersions.V290)
{
// We can now apply all attributes directly.
directApplyAttributes = model.TypesByDefinitionIndex

View File

@@ -248,7 +248,7 @@ namespace Il2CppInspector.Outputs
using (_writer)
{
writeHeader();
writeCode($"#define __IL2CPP_METADATA_VERSION {_model.Package.Version * 10:F0}");
writeCode($"#define __IL2CPP_METADATA_VERSION {_model.Package.Version.Major * 10 + _model.Package.Version.Minor * 10:F0}");
}
// Write boilerplate code

View File

@@ -8,6 +8,7 @@ using System.IO;
using System.Text.Json;
using Il2CppInspector.Reflection;
using Il2CppInspector.Model;
using Il2CppInspector.Next;
namespace Il2CppInspector.Outputs
{
@@ -182,7 +183,7 @@ namespace Il2CppInspector.Outputs
// TODO: In the future, add data ranges for the entire IL2CPP metadata tree
writeArray("arrayMetadata", () => {
if (model.Package.Version >= 24.2) {
if (model.Package.Version >= MetadataVersions.V242) {
writeObject(() => writeTypedArray(binary.CodeRegistration.pcodeGenModules, binary.Modules.Count, "struct Il2CppCodeGenModule *", "g_CodeGenModules"));
}
}, "IL2CPP Array Metadata");

View File

@@ -4,6 +4,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -88,10 +89,10 @@ namespace Il2CppInspector.Reflection
var pkg = asm.Model.Package;
// Attribute type ranges weren't included before v21 (customASttributeGenerators was though)
if (pkg.Version < 21)
if (pkg.Version < MetadataVersions.V210)
yield break;
if (pkg.Version < 29)
if (pkg.Version < MetadataVersions.V290)
{
var range = pkg.AttributeTypeRanges[customAttributeIndex];
for (var i = range.start; i < range.start + range.count; i++)

View File

@@ -5,6 +5,7 @@
All rights reserved.
*/
using Il2CppInspector.Next;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -214,7 +215,7 @@ namespace Il2CppInspector.Reflection
// Get generic type definition
TypeInfo genericTypeDef;
if (Package.Version < 27) {
if (Package.Version < MetadataVersions.V270) {
// It appears that TypeRef can be -1 if the generic depth recursion limit
// (--maximum-recursive-generic-depth=) is reached in Il2Cpp. In this case,
// no generic instance type is generated, so we just produce a null TypeInfo here.
@@ -318,7 +319,7 @@ namespace Il2CppInspector.Reflection
// The attribute index is an index into AttributeTypeRanges, each of which is a start-end range index into AttributeTypeIndices, each of which is a TypeIndex
public int GetCustomAttributeIndex(Assembly asm, int token, int customAttributeIndex) {
// Prior to v24.1, Type, Field, Parameter, Method, Event, Property, Assembly definitions had their own customAttributeIndex field
if (Package.Version <= 24.0)
if (Package.Version <= MetadataVersions.V240)
return customAttributeIndex;
// From v24.1 onwards, token was added to Il2CppCustomAttributeTypeRange and each Il2CppImageDefinition noted the CustomAttributeTypeRanges for the image

View File

@@ -3,6 +3,7 @@ using System.Text;
using System;
using System.Diagnostics;
using System.IO;
using Il2CppInspector.Next;
namespace Il2CppInspector.Utils;
@@ -111,7 +112,7 @@ public static class BlobReader
int ReadInt32()
{
if (blob.Version >= 29)
if (blob.Version >= MetadataVersions.V290)
{
var address = blob.Position;
@@ -131,7 +132,7 @@ public static class BlobReader
uint ReadUInt32()
{
if (blob.Version >= 29)
if (blob.Version >= MetadataVersions.V290)
{
var address = blob.Position;

View File

@@ -6,6 +6,8 @@ public readonly struct StructVersion(int major = 0, int minor = 0, string? tag =
public readonly int Minor = minor;
public readonly string? Tag = tag;
public double AsDouble => Major + Minor / 10.0;
#region Equality operators
public static bool operator ==(StructVersion left, StructVersion right)
@@ -42,9 +44,17 @@ public readonly struct StructVersion(int major = 0, int minor = 0, string? tag =
public static implicit operator StructVersion(string value)
{
var versionParts = value.Split('.');
if (versionParts.Length is 1 or > 2)
if (versionParts.Length > 2)
throw new InvalidOperationException("Invalid version string.");
if (versionParts.Length == 1)
{
if (!int.TryParse(versionParts[0], out var version))
throw new InvalidOperationException("Invalid single-number version string.");
return new StructVersion(version);
}
var tagParts = versionParts[1].Split("-");
if (tagParts.Length > 2)
throw new InvalidOperationException("Invalid version string.");