Add BlobReader, fix Il2CppType for 27.2+
This commit is contained in:
@@ -218,10 +218,12 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
public uint attrs => (uint) bits & 0xffff; /* param attributes or field flags */
|
public uint attrs => (uint) bits & 0xffff; /* param attributes or field flags */
|
||||||
public Il2CppTypeEnum type => (Il2CppTypeEnum)((bits >> 16) & 0xff);
|
public Il2CppTypeEnum type => (Il2CppTypeEnum)((bits >> 16) & 0xff);
|
||||||
// TODO: Unity 2021.1 (v27.2): num_mods becomes 1 bit shorter, shifting byref and pinned right 1 bit, valuetype bit added
|
// Unity 2021.1 (v27.2): num_mods becomes 1 bit shorter, shifting byref and pinned left 1 bit, valuetype bit added
|
||||||
public uint num_mods => (uint) (bits >> 24) & 0x3f; /* max 64 modifiers follow at the end */
|
|
||||||
public bool byref => ((bits >> 30) & 1) == 1;
|
public uint NumMods(double version) => (uint) (bits >> 24) & (version >= 27.2 ? 0x1fu : 0x3fu);
|
||||||
public bool pinned => (bits >> 31) == 1; /* valid when included in a local var signature */
|
public bool ByRef(double version) => (bits >> (version >= 27.2 ? 29 : 30) & 1) == 1;
|
||||||
|
public bool Pinned(double version) => (bits >> (version >= 27.2 ? 30 : 31) & 1) == 1;
|
||||||
|
public bool ValueType(double version) => version >= 27.2 && ((bits >> 31) & 1) == 1; // Was only added in 27.2
|
||||||
|
|
||||||
/*public class Union
|
/*public class Union
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -82,56 +82,9 @@ namespace Il2CppInspector
|
|||||||
if (pValue == 0)
|
if (pValue == 0)
|
||||||
return (0ul, null);
|
return (0ul, null);
|
||||||
|
|
||||||
object value = null;
|
|
||||||
Metadata.Position = pValue;
|
Metadata.Position = pValue;
|
||||||
switch (typeRef.type) {
|
var value = BlobReader.GetConstantValueFromBlob(this, typeRef.type, Metadata);
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
|
|
||||||
value = Metadata.ReadBoolean();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
|
|
||||||
value = Metadata.ReadByte();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
|
|
||||||
// UTF-8 character assumed
|
|
||||||
value = BitConverter.ToChar(Metadata.ReadBytes(2), 0);
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
|
|
||||||
value = Metadata.ReadUInt16();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
|
|
||||||
value = Metadata.ReadInt16();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
|
|
||||||
value = Metadata.Version >= 29
|
|
||||||
? Metadata.ReadCompressedUInt32()
|
|
||||||
: Metadata.ReadUInt32();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
|
|
||||||
value = Metadata.Version >= 29
|
|
||||||
? Metadata.ReadCompressedInt32()
|
|
||||||
: Metadata.ReadInt32();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
|
|
||||||
value = Metadata.ReadUInt64();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
|
|
||||||
value = Metadata.ReadInt64();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
|
|
||||||
value = Metadata.ReadSingle();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
|
|
||||||
value = Metadata.ReadDouble();
|
|
||||||
break;
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
|
|
||||||
var uiLen = Metadata.Version >= 29
|
|
||||||
? Metadata.ReadCompressedInt32()
|
|
||||||
: Metadata.ReadInt32();
|
|
||||||
|
|
||||||
value = Encoding.UTF8.GetString(Metadata.ReadBytes(uiLen));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ((ulong) pValue, value);
|
return ((ulong) pValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,8 +160,8 @@ namespace Il2CppInspector
|
|||||||
MetadataUsageType.MethodRef => MethodSpecs.Length > usage.SourceIndex,
|
MetadataUsageType.MethodRef => MethodSpecs.Length > usage.SourceIndex,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thumb instruction pointers have the bottom bit set to signify a switch from ARM to Thumb when jumping
|
// Thumb instruction pointers have the bottom bit set to signify a switch from ARM to Thumb when jumping
|
||||||
private ulong getDecodedAddress(ulong addr) {
|
private ulong getDecodedAddress(ulong addr) {
|
||||||
@@ -264,8 +217,7 @@ namespace Il2CppInspector
|
|||||||
// Build list of custom attribute generators
|
// Build list of custom attribute generators
|
||||||
if (Version < 27)
|
if (Version < 27)
|
||||||
CustomAttributeGenerators = Binary.CustomAttributeGenerators;
|
CustomAttributeGenerators = Binary.CustomAttributeGenerators;
|
||||||
|
else if (Version < 29) {
|
||||||
else {
|
|
||||||
var cagCount = Images.Sum(i => i.customAttributeCount);
|
var cagCount = Images.Sum(i => i.customAttributeCount);
|
||||||
CustomAttributeGenerators = new ulong[cagCount];
|
CustomAttributeGenerators = new ulong[cagCount];
|
||||||
|
|
||||||
@@ -278,15 +230,15 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decode addresses for Thumb etc. without altering the Il2CppBinary structure data
|
// Decode addresses for Thumb etc. without altering the Il2CppBinary structure data
|
||||||
CustomAttributeGenerators = CustomAttributeGenerators.Select(a => getDecodedAddress(a)).ToArray();
|
CustomAttributeGenerators = CustomAttributeGenerators.Select(getDecodedAddress).ToArray();
|
||||||
MethodInvokePointers = Binary.MethodInvokePointers.Select(a => getDecodedAddress(a)).ToArray();
|
MethodInvokePointers = Binary.MethodInvokePointers.Select(getDecodedAddress).ToArray();
|
||||||
GenericMethodPointers = Binary.GenericMethodPointers.ToDictionary(a => a.Key, a => getDecodedAddress(a.Value));
|
GenericMethodPointers = Binary.GenericMethodPointers.ToDictionary(a => a.Key, a => getDecodedAddress(a.Value));
|
||||||
|
|
||||||
// Get sorted list of function pointers from all sources
|
// Get sorted list of function pointers from all sources
|
||||||
// TODO: This does not include IL2CPP API functions
|
// TODO: This does not include IL2CPP API functions
|
||||||
var sortedFunctionPointers = (Version <= 24.1)?
|
var sortedFunctionPointers = (Version <= 24.1)?
|
||||||
Binary.GlobalMethodPointers.Select(a => getDecodedAddress(a)).ToList() :
|
Binary.GlobalMethodPointers.Select(getDecodedAddress).ToList() :
|
||||||
Binary.ModuleMethodPointers.SelectMany(module => module.Value).Select(a => getDecodedAddress(a)).ToList();
|
Binary.ModuleMethodPointers.SelectMany(module => module.Value).Select(getDecodedAddress).ToList();
|
||||||
|
|
||||||
sortedFunctionPointers.AddRange(CustomAttributeGenerators);
|
sortedFunctionPointers.AddRange(CustomAttributeGenerators);
|
||||||
sortedFunctionPointers.AddRange(MethodInvokePointers);
|
sortedFunctionPointers.AddRange(MethodInvokePointers);
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a reference type if necessary
|
// Create a reference type if necessary
|
||||||
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
|
return typeRef.ByRef(Package.Version) ? underlyingType.MakeByRefType() : underlyingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic primitive types are specified via a flag value
|
// Basic primitive types are specified via a flag value
|
||||||
|
|||||||
137
Il2CppInspector.Common/Utils/BlobReader.cs
Normal file
137
Il2CppInspector.Common/Utils/BlobReader.cs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
using NoisyCowStudios.Bin2Object;
|
||||||
|
using System.Text;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Il2CppInspector.Utils;
|
||||||
|
|
||||||
|
public static class BlobReader
|
||||||
|
{
|
||||||
|
public static object GetConstantValueFromBlob(Il2CppInspector inspector, Il2CppTypeEnum type, BinaryObjectStream blob)
|
||||||
|
{
|
||||||
|
const byte kArrayTypeWithDifferentElements = 1;
|
||||||
|
|
||||||
|
object value = null;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
|
||||||
|
value = blob.ReadBoolean();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
|
||||||
|
value = blob.ReadByte();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
|
||||||
|
// UTF-8 character assumed
|
||||||
|
value = BitConverter.ToChar(blob.ReadBytes(2), 0);
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
|
||||||
|
value = blob.ReadUInt16();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
|
||||||
|
value = blob.ReadInt16();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
|
||||||
|
value = blob.Version >= 29
|
||||||
|
? blob.ReadCompressedUInt32()
|
||||||
|
: blob.ReadUInt32();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
|
||||||
|
value = blob.Version >= 29
|
||||||
|
? blob.ReadCompressedInt32()
|
||||||
|
: blob.ReadInt32();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
|
||||||
|
value = blob.ReadUInt64();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
|
||||||
|
value = blob.ReadInt64();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
|
||||||
|
value = blob.ReadSingle();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
|
||||||
|
value = blob.ReadDouble();
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
|
||||||
|
var uiLen = blob.Version >= 29
|
||||||
|
? blob.ReadCompressedInt32()
|
||||||
|
: blob.ReadInt32();
|
||||||
|
|
||||||
|
if (uiLen != -1)
|
||||||
|
value = Encoding.UTF8.GetString(blob.ReadBytes(uiLen));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||||
|
var length = blob.Version >= 29
|
||||||
|
? blob.ReadCompressedInt32()
|
||||||
|
: blob.ReadInt32();
|
||||||
|
|
||||||
|
if (length == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var arrayElementType = ReadEncodedTypeEnum(inspector, blob, out var arrayElementDef);
|
||||||
|
var arrayElementsAreDifferent = blob.ReadByte();
|
||||||
|
|
||||||
|
if (arrayElementsAreDifferent == kArrayTypeWithDifferentElements)
|
||||||
|
{
|
||||||
|
var array = new ConstantBlobArrayElement[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var elementType = ReadEncodedTypeEnum(inspector, blob, out var elementTypeDef);
|
||||||
|
array[i] = new ConstantBlobArrayElement(elementTypeDef, GetConstantValueFromBlob(inspector, elementType, blob));
|
||||||
|
}
|
||||||
|
|
||||||
|
value = new ConstantBlobArray(arrayElementDef, array);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var array = new object[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
array[i] = GetConstantValueFromBlob(inspector, arrayElementType, blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
value = new ConstantBlobArray(arrayElementDef, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT:
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX:
|
||||||
|
var index = blob.ReadCompressedInt32();
|
||||||
|
if (index != -1)
|
||||||
|
value = inspector.TypeReferences[index];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Il2CppTypeEnum ReadEncodedTypeEnum(Il2CppInspector inspector, BinaryObjectStream blob,
|
||||||
|
out Il2CppTypeDefinition enumType)
|
||||||
|
{
|
||||||
|
enumType = null;
|
||||||
|
|
||||||
|
var typeEnum = (Il2CppTypeEnum)blob.ReadByte();
|
||||||
|
if (typeEnum == Il2CppTypeEnum.IL2CPP_TYPE_ENUM)
|
||||||
|
{
|
||||||
|
var typeIndex = blob.ReadCompressedInt32();
|
||||||
|
enumType = inspector.TypeDefinitions[typeIndex];
|
||||||
|
typeEnum = inspector.TypeReferences[enumType.byvalTypeIndex].type;
|
||||||
|
}
|
||||||
|
// This technically also handles SZARRAY (System.Array) and all others by just returning their system type
|
||||||
|
|
||||||
|
return typeEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ConstantBlobArray(Il2CppTypeDefinition ArrayTypeDef, object[] Elements);
|
||||||
|
|
||||||
|
public record ConstantBlobArrayElement(Il2CppTypeDefinition TypeDef, object value);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user