migrate versioning to StructVersion class, add handling/detection for 29.2/31.2
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
33
Il2CppInspector.Common/Next/MetadataVersions.cs
Normal file
33
Il2CppInspector.Common/Next/MetadataVersions.cs
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.");
|
||||
|
||||
Reference in New Issue
Block a user