v29支持

This commit is contained in:
Perfare 2021-12-15 15:20:56 +08:00
parent 22c6374f6f
commit 43ff0f23c1
15 changed files with 725 additions and 239 deletions

View file

@ -0,0 +1,101 @@
using System;
using System.IO;
using System.Text;
namespace Il2CppDumper
{
public static class BinaryReaderExtensions
{
public static string ReadString(this BinaryReader reader, int numChars)
{
var start = reader.BaseStream.Position;
// UTF8 takes up to 4 bytes per character
var str = Encoding.UTF8.GetString(reader.ReadBytes(numChars * 4)).Substring(0, numChars);
// make our position what it would have been if we'd known the exact number of bytes needed.
reader.BaseStream.Position = start;
reader.ReadBytes(Encoding.UTF8.GetByteCount(str));
return str;
}
public static uint ReadULeb128(this BinaryReader reader)
{
uint value = reader.ReadByte();
if (value >= 0x80)
{
var bitshift = 0;
value &= 0x7f;
while (true)
{
var b = reader.ReadByte();
bitshift += 7;
value |= (uint)((b & 0x7f) << bitshift);
if (b < 0x80)
break;
}
}
return value;
}
public static uint ReadCompressedUInt32(this BinaryReader reader)
{
uint val;
var read = reader.ReadByte();
if ((read & 0x80) == 0)
{
// 1 byte written
val = read;
}
else if ((read & 0xC0) == 0x80)
{
// 2 bytes written
val = (read & ~0x80u) << 8;
val |= reader.ReadByte();
}
else if ((read & 0xE0) == 0xC0)
{
// 4 bytes written
val = (read & ~0xC0u) << 24;
val |= ((uint)reader.ReadByte() << 16);
val |= ((uint)reader.ReadByte() << 8);
val |= reader.ReadByte();
}
else if (read == 0xF0)
{
// 5 bytes written, we had a really large int32!
val = reader.ReadUInt32();
}
else if (read == 0xFE)
{
// Special encoding for Int32.MaxValue
val = uint.MaxValue - 1;
}
else if (read == 0xFF)
{
// Yes we treat UInt32.MaxValue (and Int32.MinValue, see ReadCompressedInt32) specially
val = uint.MaxValue;
}
else
{
throw new Exception("Invalid compressed integer format");
}
return val;
}
public static int ReadCompressedInt32(this BinaryReader reader)
{
var encoded = reader.ReadCompressedUInt32();
// -UINT32_MAX can't be represted safely in an int32_t, so we treat it specially
if (encoded == uint.MaxValue)
return int.MinValue;
bool isNegative = (encoded & 1) != 0;
encoded >>= 1;
if (isNegative)
return -(int)(encoded + 1);
return (int)encoded;
}
}
}

View file

@ -52,24 +52,11 @@ namespace Il2CppDumper
public double ReadDouble() => reader.ReadDouble();
public uint ReadULeb128()
{
uint value = reader.ReadByte();
if (value >= 0x80)
{
var bitshift = 0;
value &= 0x7f;
while (true)
{
var b = reader.ReadByte();
bitshift += 7;
value |= (uint)((b & 0x7f) << bitshift);
if (b < 0x80)
break;
}
}
return value;
}
public uint ReadCompressedUInt32() => reader.ReadCompressedUInt32();
public int ReadCompressedInt32() => reader.ReadCompressedInt32();
public uint ReadULeb128() => reader.ReadULeb128();
public void Write(bool value) => writer.Write(value);
@ -246,6 +233,10 @@ namespace Il2CppDumper
get => Is32Bit ? 4ul : 8ul;
}
public BinaryReader Reader => reader;
public BinaryWriter Writer => writer;
protected virtual void Dispose(bool disposing)
{
if (disposing)

View file

@ -128,7 +128,8 @@ namespace Il2CppDumper
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
IL2CPP_TYPE_ENUM = 0x55 /* an enumeration */
IL2CPP_TYPE_ENUM = 0x55, /* an enumeration */
IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff /* an index into IL2CPP type metadata table */
}
public class Il2CppType
@ -261,7 +262,7 @@ namespace Il2CppDumper
public long rgctxsCount;
public ulong rgctxs;
public ulong debuggerMetadata;
[Version(Min = 27)]
[Version(Min = 27, Max = 27.2)]
public ulong customAttributeCacheGenerator;
[Version(Min = 27)]
public ulong moduleInitializer;

View file

@ -20,6 +20,7 @@ namespace Il2CppDumper
private Dictionary<int, Il2CppParameterDefaultValue> parameterDefaultValuesDic;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributeTypeRanges;
public Il2CppCustomAttributeDataRange[] attributeDataRanges;
private Dictionary<Il2CppImageDefinition, Dictionary<uint, int>> attributeTypeRangesDic;
public Il2CppStringLiteral[] stringLiterals;
private Il2CppMetadataUsageList[] metadataUsageLists;
@ -48,7 +49,7 @@ namespace Il2CppDumper
throw new InvalidDataException("ERROR: Metadata file supplied is not valid metadata file.");
}
var version = ReadInt32();
if (version < 16 || version > 27)
if (version < 16 || version > 29)
{
throw new NotSupportedException($"ERROR: Metadata file supplied is not a supported version[{version}].");
}
@ -63,39 +64,39 @@ namespace Il2CppDumper
}
else
{
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesCount);
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);
if (imageDefs.Any(x => x.token != 1))
{
Version = 24.1;
}
}
}
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesCount);
if (Version == 24.2 && header.assembliesCount / 68 < imageDefs.Length)
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);
if (Version == 24.2 && header.assembliesSize / 68 < imageDefs.Length)
{
Version = 24.4;
}
assemblyDefs = ReadMetadataClassArray<Il2CppAssemblyDefinition>(header.assembliesOffset, header.assembliesCount);
typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(header.typeDefinitionsOffset, header.typeDefinitionsCount);
methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(header.methodsOffset, header.methodsCount);
parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(header.parametersOffset, header.parametersCount);
fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(header.fieldsOffset, header.fieldsCount);
var fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(header.fieldDefaultValuesOffset, header.fieldDefaultValuesCount);
var parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(header.parameterDefaultValuesOffset, header.parameterDefaultValuesCount);
assemblyDefs = ReadMetadataClassArray<Il2CppAssemblyDefinition>(header.assembliesOffset, header.assembliesSize);
typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(header.typeDefinitionsOffset, header.typeDefinitionsSize);
methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(header.methodsOffset, header.methodsSize);
parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(header.parametersOffset, header.parametersSize);
fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(header.fieldsOffset, header.fieldsSize);
var fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(header.fieldDefaultValuesOffset, header.fieldDefaultValuesSize);
var parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(header.parameterDefaultValuesOffset, header.parameterDefaultValuesSize);
fieldDefaultValuesDic = fieldDefaultValues.ToDictionary(x => x.fieldIndex);
parameterDefaultValuesDic = parameterDefaultValues.ToDictionary(x => x.parameterIndex);
propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(header.propertiesOffset, header.propertiesCount);
interfaceIndices = ReadClassArray<int>(header.interfacesOffset, header.interfacesCount / 4);
nestedTypeIndices = ReadClassArray<int>(header.nestedTypesOffset, header.nestedTypesCount / 4);
eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(header.eventsOffset, header.eventsCount);
genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(header.genericContainersOffset, header.genericContainersCount);
genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(header.genericParametersOffset, header.genericParametersCount);
constraintIndices = ReadClassArray<int>(header.genericParameterConstraintsOffset, header.genericParameterConstraintsCount / 4);
vtableMethods = ReadClassArray<uint>(header.vtableMethodsOffset, header.vtableMethodsCount / 4);
stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(header.stringLiteralOffset, header.stringLiteralCount);
propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(header.propertiesOffset, header.propertiesSize);
interfaceIndices = ReadClassArray<int>(header.interfacesOffset, header.interfacesSize / 4);
nestedTypeIndices = ReadClassArray<int>(header.nestedTypesOffset, header.nestedTypesSize / 4);
eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(header.eventsOffset, header.eventsSize);
genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(header.genericContainersOffset, header.genericContainersSize);
genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(header.genericParametersOffset, header.genericParametersSize);
constraintIndices = ReadClassArray<int>(header.genericParameterConstraintsOffset, header.genericParameterConstraintsSize / 4);
vtableMethods = ReadClassArray<uint>(header.vtableMethodsOffset, header.vtableMethodsSize / 4);
stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(header.stringLiteralOffset, header.stringLiteralSize);
if (Version > 16)
{
fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(header.fieldRefsOffset, header.fieldRefsCount);
fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(header.fieldRefsOffset, header.fieldRefsSize);
if (Version < 27)
{
metadataUsageLists = ReadMetadataClassArray<Il2CppMetadataUsageList>(header.metadataUsageListsOffset, header.metadataUsageListsCount);
@ -104,11 +105,15 @@ namespace Il2CppDumper
ProcessingMetadataUsage();
}
}
if (Version > 20)
if (Version > 20 && Version < 29)
{
attributeTypeRanges = ReadMetadataClassArray<Il2CppCustomAttributeTypeRange>(header.attributesInfoOffset, header.attributesInfoCount);
attributeTypes = ReadClassArray<int>(header.attributeTypesOffset, header.attributeTypesCount / 4);
}
if (Version >= 29)
{
attributeDataRanges = ReadMetadataClassArray<Il2CppCustomAttributeDataRange>(header.attributeDataRangeOffset, header.attributeDataRangeSize);
}
if (Version > 24)
{
attributeTypeRangesDic = new Dictionary<Il2CppImageDefinition, Dictionary<uint, int>>();
@ -119,7 +124,14 @@ namespace Il2CppDumper
var end = imageDef.customAttributeStart + imageDef.customAttributeCount;
for (int i = imageDef.customAttributeStart; i < end; i++)
{
dic.Add(attributeTypeRanges[i].token, i);
if (Version >= 29)
{
dic.Add(attributeDataRanges[i].token, i);
}
else
{
dic.Add(attributeTypeRanges[i].token, i);
}
}
}
}
@ -268,16 +280,5 @@ namespace Il2CppDumper
}
}
}
public string ReadString(int numChars)
{
var start = Position;
// UTF8 takes up to 4 bytes per character
var str = Encoding.UTF8.GetString(ReadBytes(numChars * 4)).Substring(0, numChars);
// make our position what it would have been if we'd known the exact number of bytes needed.
Position = start;
ReadBytes(Encoding.UTF8.GetByteCount(str));
return str;
}
}
}

View file

@ -7,53 +7,53 @@ namespace Il2CppDumper
public uint sanity;
public int version;
public uint stringLiteralOffset; // string data for managed code
public int stringLiteralCount;
public int stringLiteralSize;
public uint stringLiteralDataOffset;
public int stringLiteralDataCount;
public int stringLiteralDataSize;
public uint stringOffset; // string data for metadata
public int stringCount;
public int stringSize;
public uint eventsOffset; // Il2CppEventDefinition
public int eventsCount;
public int eventsSize;
public uint propertiesOffset; // Il2CppPropertyDefinition
public int propertiesCount;
public int propertiesSize;
public uint methodsOffset; // Il2CppMethodDefinition
public int methodsCount;
public int methodsSize;
public uint parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
public int parameterDefaultValuesCount;
public int parameterDefaultValuesSize;
public uint fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
public int fieldDefaultValuesCount;
public int fieldDefaultValuesSize;
public uint fieldAndParameterDefaultValueDataOffset; // uint8_t
public int fieldAndParameterDefaultValueDataCount;
public int fieldAndParameterDefaultValueDataSize;
public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
public int fieldMarshaledSizesCount;
public int fieldMarshaledSizesSize;
public uint parametersOffset; // Il2CppParameterDefinition
public int parametersCount;
public int parametersSize;
public uint fieldsOffset; // Il2CppFieldDefinition
public int fieldsCount;
public int fieldsSize;
public uint genericParametersOffset; // Il2CppGenericParameter
public int genericParametersCount;
public int genericParametersSize;
public uint genericParameterConstraintsOffset; // TypeIndex
public int genericParameterConstraintsCount;
public int genericParameterConstraintsSize;
public uint genericContainersOffset; // Il2CppGenericContainer
public int genericContainersCount;
public int genericContainersSize;
public uint nestedTypesOffset; // TypeDefinitionIndex
public int nestedTypesCount;
public int nestedTypesSize;
public uint interfacesOffset; // TypeIndex
public int interfacesCount;
public int interfacesSize;
public uint vtableMethodsOffset; // EncodedMethodIndex
public int vtableMethodsCount;
public int vtableMethodsSize;
public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
public int interfaceOffsetsCount;
public int interfaceOffsetsSize;
public uint typeDefinitionsOffset; // Il2CppTypeDefinition
public int typeDefinitionsCount;
public int typeDefinitionsSize;
[Version(Max = 24.1)]
public uint rgctxEntriesOffset; // Il2CppRGCTXDefinition
[Version(Max = 24.1)]
public int rgctxEntriesCount;
public uint imagesOffset; // Il2CppImageDefinition
public int imagesCount;
public int imagesSize;
public uint assembliesOffset; // Il2CppAssemblyDefinition
public int assembliesCount;
public int assembliesSize;
[Version(Min = 19, Max = 24.5)]
public uint metadataUsageListsOffset; // Il2CppMetadataUsageList
[Version(Min = 19, Max = 24.5)]
@ -65,27 +65,35 @@ namespace Il2CppDumper
[Version(Min = 19)]
public uint fieldRefsOffset; // Il2CppFieldRef
[Version(Min = 19)]
public int fieldRefsCount;
public int fieldRefsSize;
[Version(Min = 20)]
public int referencedAssembliesOffset; // int32_t
[Version(Min = 20)]
public int referencedAssembliesCount;
[Version(Min = 21)]
public int referencedAssembliesSize;
[Version(Min = 21, Max = 27.2)]
public uint attributesInfoOffset; // Il2CppCustomAttributeTypeRange
[Version(Min = 21)]
[Version(Min = 21, Max = 27.2)]
public int attributesInfoCount;
[Version(Min = 21)]
[Version(Min = 21, Max = 27.2)]
public uint attributeTypesOffset; // TypeIndex
[Version(Min = 21)]
[Version(Min = 21, Max = 27.2)]
public int attributeTypesCount;
[Version(Min = 29)]
public uint attributeDataOffset;
[Version(Min = 29)]
public int attributeDataSize;
[Version(Min = 29)]
public uint attributeDataRangeOffset;
[Version(Min = 29)]
public int attributeDataRangeSize;
[Version(Min = 22)]
public int unresolvedVirtualCallParameterTypesOffset; // TypeIndex
[Version(Min = 22)]
public int unresolvedVirtualCallParameterTypesCount;
public int unresolvedVirtualCallParameterTypesSize;
[Version(Min = 22)]
public int unresolvedVirtualCallParameterRangesOffset; // Il2CppRange
[Version(Min = 22)]
public int unresolvedVirtualCallParameterRangesCount;
public int unresolvedVirtualCallParameterRangesSize;
[Version(Min = 23)]
public int windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair
[Version(Min = 23)]
@ -97,7 +105,7 @@ namespace Il2CppDumper
[Version(Min = 24)]
public int exportedTypeDefinitionsOffset; // TypeDefinitionIndex
[Version(Min = 24)]
public int exportedTypeDefinitionsCount;
public int exportedTypeDefinitionsSize;
}
public class Il2CppAssemblyDefinition
@ -368,6 +376,7 @@ namespace Il2CppDumper
IL2CPP_RGCTX_DATA_CLASS,
IL2CPP_RGCTX_DATA_METHOD,
IL2CPP_RGCTX_DATA_ARRAY,
IL2CPP_RGCTX_DATA_CONSTRAINED,
}
public class Il2CppRGCTXDefinitionData
@ -379,7 +388,11 @@ namespace Il2CppDumper
public class Il2CppRGCTXDefinition
{
public Il2CppRGCTXDataType type;
public Il2CppRGCTXDataType type => type_post29 == 0 ? (Il2CppRGCTXDataType)type_pre29 : (Il2CppRGCTXDataType)type_post29;
[Version(Max = 27.1)]
public int type_pre29;
[Version(Min = 29)]
public ulong type_post29;
[Version(Max = 27.1)]
public Il2CppRGCTXDefinitionData data;
[Version(Min = 27.2)]
@ -396,4 +409,10 @@ namespace Il2CppDumper
kIl2CppMetadataUsageStringLiteral,
kIl2CppMetadataUsageMethodRef,
};
public class Il2CppCustomAttributeDataRange
{
public uint token;
public uint startOffset;
}
}

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net472;net5.0;net6.0</TargetFrameworks>
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">

View file

@ -165,7 +165,7 @@ namespace Il2CppDumper
writer.Write($"{executor.GetTypeName(fieldType, false, false)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}");
if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefaultValue) && fieldDefaultValue.dataIndex != -1)
{
if (TryGetDefaultValue(fieldDefaultValue.typeIndex, fieldDefaultValue.dataIndex, out var value))
if (executor.TryGetDefaultValue(fieldDefaultValue.typeIndex, fieldDefaultValue.dataIndex, out var value))
{
writer.Write($" = ");
if (value is string str)
@ -181,6 +181,10 @@ namespace Il2CppDumper
{
writer.Write($"{value}");
}
else
{
writer.Write("null");
}
}
else
{
@ -238,13 +242,13 @@ namespace Il2CppDumper
{
writer.Write("\n");
var methodDef = metadata.methodDefs[i];
var isAbstract = (methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;
if (config.DumpAttribute)
{
writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t"));
}
if (config.DumpMethodOffset)
{
var isAbstract = (methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;
var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);
if (!isAbstract && methodPointer > 0)
{
@ -312,7 +316,7 @@ namespace Il2CppDumper
parameterStr += $"{parameterTypeName} {parameterName}";
if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1)
{
if (TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))
if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))
{
parameterStr += " = ";
if (value is string str)
@ -328,6 +332,10 @@ namespace Il2CppDumper
{
parameterStr += $"{value}";
}
else
{
writer.Write("null");
}
}
else
{
@ -337,7 +345,14 @@ namespace Il2CppDumper
parameterStrs.Add(parameterStr);
}
writer.Write(string.Join(", ", parameterStrs));
writer.Write(") { }\n");
if (isAbstract)
{
writer.Write(");\n");
}
else
{
writer.Write(") { }\n");
}
if (il2Cpp.methodDefinitionMethodSpecs.TryGetValue(i, out var methodSpecs))
{
@ -387,21 +402,44 @@ namespace Il2CppDumper
var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);
if (attributeIndex >= 0)
{
var methodPointer = executor.customAttributeGenerators[attributeIndex];
var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
var sb = new StringBuilder();
for (var i = 0; i < attributeTypeRange.count; i++)
if (il2Cpp.Version < 29)
{
var typeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
sb.AppendFormat("{0}[{1}] // RVA: 0x{2:X} Offset: 0x{3:X} VA: 0x{4:X}\n",
padding,
executor.GetTypeName(il2Cpp.types[typeIndex], false, false),
fixedMethodPointer,
il2Cpp.MapVATR(methodPointer),
methodPointer);
var methodPointer = executor.customAttributeGenerators[attributeIndex];
var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
var sb = new StringBuilder();
for (var i = 0; i < attributeTypeRange.count; i++)
{
var typeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
sb.AppendFormat("{0}[{1}] // RVA: 0x{2:X} Offset: 0x{3:X} VA: 0x{4:X}\n",
padding,
executor.GetTypeName(il2Cpp.types[typeIndex], false, false),
fixedMethodPointer,
il2Cpp.MapVATR(methodPointer),
methodPointer);
}
return sb.ToString();
}
else
{
var startRange = metadata.attributeDataRanges[attributeIndex];
var endRange = metadata.attributeDataRanges[attributeIndex + 1];
metadata.Position = metadata.header.attributeDataOffset + startRange.startOffset;
var buff = metadata.ReadBytes((int)(endRange.startOffset - startRange.startOffset));
var reader = new CustomAttributeDataReader(executor, buff);
if (reader.Count == 0)
{
return string.Empty;
}
var sb = new StringBuilder();
for (var i = 0; i < reader.Count; i++)
{
sb.Append(padding);
sb.Append(reader.GetStringCustomAttributeData());
sb.Append("\n");
}
return sb.ToString();
}
return sb.ToString();
}
else
{
@ -458,58 +496,5 @@ namespace Il2CppDumper
methodModifiers.Add(methodDef, str);
return str;
}
private bool TryGetDefaultValue(int typeIndex, int dataIndex, out object value)
{
var pointer = metadata.GetDefaultValueFromIndex(dataIndex);
var defaultValueType = il2Cpp.types[typeIndex];
metadata.Position = pointer;
switch (defaultValueType.type)
{
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
value = metadata.ReadBoolean();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
value = metadata.ReadByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
value = metadata.ReadSByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
value = BitConverter.ToChar(metadata.ReadBytes(2), 0);
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
value = metadata.ReadUInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
value = metadata.ReadInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
value = metadata.ReadUInt32();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
value = metadata.ReadInt32();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
value = metadata.ReadUInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
value = metadata.ReadInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
value = metadata.ReadSingle();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
value = metadata.ReadDouble();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
var len = metadata.ReadInt32();
value = metadata.ReadString(len);
return true;
default:
value = pointer;
return false;
}
}
}
}

View file

@ -243,7 +243,10 @@ namespace Il2CppDumper
}
orderedPointers.AddRange(il2Cpp.genericMethodPointers);
orderedPointers.AddRange(il2Cpp.invokerPointers);
orderedPointers.AddRange(executor.customAttributeGenerators);
if (il2Cpp.Version < 29)
{
orderedPointers.AddRange(executor.customAttributeGenerators);
}
if (il2Cpp.Version >= 22)
{
if (il2Cpp.reversePInvokeWrappers != null)

View file

@ -0,0 +1,8 @@
namespace Il2CppDumper
{
public class AttributeArgument
{
public BlobValue Value;
public int Index;
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Il2CppDumper
{
public class BlobValue
{
public object Value;
public Il2CppTypeEnum il2CppTypeEnum;
public Il2CppType EnumType;
}
}

View file

@ -0,0 +1,170 @@
using System.Collections.Generic;
using System.IO;
namespace Il2CppDumper
{
public class CustomAttributeDataReader : BinaryReader
{
private Il2CppExecutor executor;
private Metadata metadata;
private Il2Cpp il2Cpp;
private long ctorBuffer;
private long dataBuffer;
public uint Count { get; set; }
public CustomAttributeDataReader(Il2CppExecutor executor, byte[] buff) : base(new MemoryStream(buff))
{
this.executor = executor;
metadata = executor.metadata;
il2Cpp = executor.il2Cpp;
Count = this.ReadCompressedUInt32();
ctorBuffer = BaseStream.Position;
dataBuffer = BaseStream.Position + Count * 4;
}
public string GetStringCustomAttributeData()
{
BaseStream.Position = ctorBuffer;
var ctorIndex = ReadInt32();
var methodDef = metadata.methodDefs[ctorIndex];
var typeDef = metadata.typeDefs[methodDef.declaringType];
ctorBuffer = BaseStream.Position;
BaseStream.Position = dataBuffer;
var argumentCount = this.ReadCompressedUInt32();
var fieldCount = this.ReadCompressedUInt32();
var propertyCount = this.ReadCompressedUInt32();
var argList = new List<string>();
for (var i = 0; i < argumentCount; i++)
{
argList.Add($"{AttributeDataToString(ReadAttributeDataValue())}");
}
for (var i = 0; i < fieldCount; i++)
{
var str = AttributeDataToString(ReadAttributeDataValue());
(var declaring, var fieldIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);
var fieldDef = metadata.fieldDefs[declaring.fieldStart + fieldIndex];
argList.Add($"{metadata.GetStringFromIndex(fieldDef.nameIndex)} = {str}");
}
for (var i = 0; i < propertyCount; i++)
{
var str = AttributeDataToString(ReadAttributeDataValue());
(var declaring, var propertyIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);
var propertyDef = metadata.propertyDefs[declaring.propertyStart + propertyIndex];
argList.Add($"{metadata.GetStringFromIndex(propertyDef.nameIndex)} = {str}");
}
dataBuffer = BaseStream.Position;
var typeName = metadata.GetStringFromIndex(typeDef.nameIndex).Replace("Attribute", "");
if (argList.Count > 0)
{
return $"[{typeName}({string.Join(", ", argList)})]";
}
else
{
return $"[{typeName}]";
}
}
private string AttributeDataToString(BlobValue blobValue)
{
//TODO enum
if (blobValue.Value == null)
{
return "null";
}
switch (blobValue.il2CppTypeEnum)
{
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
return $"\"{blobValue.Value}\"";
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
var array = (BlobValue[])blobValue.Value;
var list = new List<string>();
foreach (var item in array)
{
list.Add(AttributeDataToString(item));
}
return $"new[] {{ {string.Join(", ", list)} }}";
case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX:
var il2CppType = (Il2CppType)blobValue.Value;
return $"typeof({executor.GetTypeName(il2CppType, false, false)})";
default:
return blobValue.Value.ToString();
}
}
public CustomAttributeReaderVisitor VisitCustomAttributeData()
{
var visitor = new CustomAttributeReaderVisitor();
BaseStream.Position = ctorBuffer;
var ctorIndex = ReadInt32();
visitor.CtorIndex = ctorIndex;
var methodDef = metadata.methodDefs[ctorIndex];
var typeDef = metadata.typeDefs[methodDef.declaringType];
ctorBuffer = BaseStream.Position;
BaseStream.Position = dataBuffer;
var argumentCount = this.ReadCompressedUInt32();
var fieldCount = this.ReadCompressedUInt32();
var propertyCount = this.ReadCompressedUInt32();
visitor.Arguments = new AttributeArgument[argumentCount];
for (var i = 0; i < argumentCount; i++)
{
var argument = visitor.Arguments[i] = new AttributeArgument();
argument.Value = ReadAttributeDataValue();
argument.Index = i;
}
visitor.Fields = new AttributeArgument[fieldCount];
for (var i = 0; i < fieldCount; i++)
{
var field = visitor.Fields[i] = new AttributeArgument();
field.Value = ReadAttributeDataValue();
(var declaring, var fieldIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);
field.Index = declaring.fieldStart + fieldIndex;
}
visitor.Properties = new AttributeArgument[propertyCount];
for (var i = 0; i < propertyCount; i++)
{
var property = visitor.Properties[i] = new AttributeArgument();
property.Value = ReadAttributeDataValue();
(var declaring, var propertyIndex) = ReadCustomAttributeNamedArgumentClassAndIndex(typeDef);
property.Index = declaring.propertyStart + propertyIndex;
}
dataBuffer = BaseStream.Position;
return visitor;
}
private BlobValue ReadAttributeDataValue()
{
var type = executor.ReadEncodedTypeEnum(this, out var enumType);
executor.GetConstantValueFromBlob(type, this, out var blobValue);
if (enumType != null)
{
blobValue.EnumType = enumType;
}
return blobValue;
}
private (Il2CppTypeDefinition, int) ReadCustomAttributeNamedArgumentClassAndIndex(Il2CppTypeDefinition typeDef)
{
var memberIndex = this.ReadCompressedInt32();
if (memberIndex >= 0)
{
return (typeDef, memberIndex);
}
memberIndex = -(memberIndex + 1);
var typeIndex = this.ReadCompressedUInt32();
var declaringClass = metadata.typeDefs[typeIndex];
return (declaringClass, memberIndex);
}
}
}

View file

@ -0,0 +1,10 @@
namespace Il2CppDumper
{
public class CustomAttributeReaderVisitor
{
public int CtorIndex;
public AttributeArgument[] Arguments;
public AttributeArgument[] Fields;
public AttributeArgument[] Properties;
}
}

View file

@ -18,7 +18,9 @@ namespace Il2CppDumper
private Dictionary<Il2CppGenericParameter, GenericParameter> genericParameterDic = new Dictionary<Il2CppGenericParameter, GenericParameter>();
private MethodDefinition attributeAttribute;
private TypeReference stringType;
private Dictionary<string, MethodDefinition> knownAttributes = new Dictionary<string, MethodDefinition>();
private Dictionary<int, FieldDefinition> fieldDefinitionDic = new Dictionary<int, FieldDefinition>();
private Dictionary<int, PropertyDefinition> propertyDefinitionDic = new Dictionary<int, PropertyDefinition>();
private Dictionary<int, MethodDefinition> methodDefinitionDic = new Dictionary<int, MethodDefinition>();
public DummyAssemblyGenerator(Il2CppExecutor il2CppExecutor, bool addToken)
{
@ -44,10 +46,7 @@ namespace Il2CppDumper
};
resolver.Register(il2CppDummyDll);
var fieldDefinitionDic = new Dictionary<int, FieldDefinition>();
var methodDefinitionDic = new Dictionary<int, MethodDefinition>();
var parameterDefinitionDic = new Dictionary<int, ParameterDefinition>();
var propertyDefinitionDic = new Dictionary<int, PropertyDefinition>();
var eventDefinitionDic = new Dictionary<int, EventDefinition>();
//创建程序集,同时创建所有类
@ -56,7 +55,17 @@ namespace Il2CppDumper
var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);
var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname;
var assemblyName = metadata.GetStringFromIndex(aname.nameIndex);
var assemblyNameDef = new AssemblyNameDefinition(assemblyName, new Version(aname.major, aname.minor, aname.build, aname.revision));
Version vers;
if (aname.build >= 0)
{
vers = new Version(aname.major, aname.minor, aname.build, aname.revision);
}
else
{
//__Generated
vers = new Version(3, 7, 1, 6);
}
var assemblyNameDef = new AssemblyNameDefinition(assemblyName, vers);
/*assemblyNameDef.Culture = metadata.GetStringFromIndex(aname.cultureIndex);
assemblyNameDef.PublicKey = Encoding.UTF8.GetBytes(metadata.GetStringFromIndex(aname.publicKeyIndex));
assemblyNameDef.HashAlgorithm = (AssemblyHashAlgorithm)aname.hash_alg;
@ -169,7 +178,7 @@ namespace Il2CppDumper
//fieldDefault
if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1)
{
if (TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value))
if (executor.TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value))
{
fieldDefinition.Constant = value;
}
@ -262,7 +271,7 @@ namespace Il2CppDumper
//ParameterDefault
if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1)
{
if (TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))
if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value))
{
parameterDefinition.Constant = value;
}
@ -537,83 +546,71 @@ namespace Il2CppDumper
}
}
private bool TryGetDefaultValue(int typeIndex, int dataIndex, out object value)
{
var pointer = metadata.GetDefaultValueFromIndex(dataIndex);
var defaultValueType = il2Cpp.types[typeIndex];
metadata.Position = pointer;
switch (defaultValueType.type)
{
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
value = metadata.ReadBoolean();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
value = metadata.ReadByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
value = metadata.ReadSByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
value = BitConverter.ToChar(metadata.ReadBytes(2), 0);
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
value = metadata.ReadUInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
value = metadata.ReadInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
value = metadata.ReadUInt32();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
value = metadata.ReadInt32();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
value = metadata.ReadUInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
value = metadata.ReadInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
value = metadata.ReadSingle();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
value = metadata.ReadDouble();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
var len = metadata.ReadInt32();
value = metadata.ReadString(len);
return true;
default:
value = pointer;
return false;
}
}
private void CreateCustomAttribute(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token, ModuleDefinition moduleDefinition, Collection<CustomAttribute> customAttributes)
{
var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);
if (attributeIndex >= 0)
{
var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
for (int i = 0; i < attributeTypeRange.count; i++)
if (il2Cpp.Version < 29)
{
var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
var attributeType = il2Cpp.types[attributeTypeIndex];
var typeDef = executor.GetTypeDefinitionFromIl2CppType(attributeType);
var typeDefinition = typeDefinitionDic[typeDef];
if (!TryRestoreCustomAttribute(typeDefinition, moduleDefinition, customAttributes))
var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
for (int i = 0; i < attributeTypeRange.count; i++)
{
var methodPointer = executor.customAttributeGenerators[attributeIndex];
var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(attributeAttribute));
var name = new CustomAttributeNamedArgument("Name", new CustomAttributeArgument(stringType, typeDefinition.Name));
var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}"));
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}"));
customAttribute.Fields.Add(name);
customAttribute.Fields.Add(rva);
customAttribute.Fields.Add(offset);
customAttributes.Add(customAttribute);
var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
var attributeType = il2Cpp.types[attributeTypeIndex];
var typeDef = executor.GetTypeDefinitionFromIl2CppType(attributeType);
var typeDefinition = typeDefinitionDic[typeDef];
if (!TryRestoreCustomAttribute(typeDefinition, moduleDefinition, customAttributes))
{
var methodPointer = executor.customAttributeGenerators[attributeIndex];
var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(attributeAttribute));
var name = new CustomAttributeNamedArgument("Name", new CustomAttributeArgument(stringType, typeDefinition.Name));
var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}"));
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}"));
customAttribute.Fields.Add(name);
customAttribute.Fields.Add(rva);
customAttribute.Fields.Add(offset);
customAttributes.Add(customAttribute);
}
}
}
else
{
var startRange = metadata.attributeDataRanges[attributeIndex];
var endRange = metadata.attributeDataRanges[attributeIndex + 1];
metadata.Position = metadata.header.attributeDataOffset + startRange.startOffset;
var buff = metadata.ReadBytes((int)(endRange.startOffset - startRange.startOffset));
var reader = new CustomAttributeDataReader(executor, buff);
if (reader.Count != 0)
{
for (var i = 0; i < reader.Count; i++)
{
var visitor = reader.VisitCustomAttributeData();
var methodDefinition = methodDefinitionDic[visitor.CtorIndex];
var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(methodDefinition));
foreach (var argument in visitor.Arguments)
{
var parameterDefinition = methodDefinition.Parameters[argument.Index];
var customAttributeArgument = CreateCustomAttributeArgument(parameterDefinition.ParameterType, argument.Value, methodDefinition);
customAttribute.ConstructorArguments.Add(customAttributeArgument);
}
foreach (var field in visitor.Fields)
{
var fieldDefinition = fieldDefinitionDic[field.Index];
var customAttributeArgument = CreateCustomAttributeArgument(fieldDefinition.FieldType, field.Value, fieldDefinition);
var customAttributeNamedArgument = new CustomAttributeNamedArgument(fieldDefinition.Name, customAttributeArgument);
customAttribute.Fields.Add(customAttributeNamedArgument);
}
foreach (var property in visitor.Properties)
{
var propertyDefinition = propertyDefinitionDic[property.Index];
var customAttributeArgument = CreateCustomAttributeArgument(propertyDefinition.PropertyType, property.Value, propertyDefinition);
var customAttributeNamedArgument = new CustomAttributeNamedArgument(propertyDefinition.Name, customAttributeArgument);
customAttribute.Properties.Add(customAttributeNamedArgument);
}
customAttributes.Add(customAttribute);
}
}
}
}
@ -650,5 +647,41 @@ namespace Il2CppDumper
}
return genericParameter;
}
private CustomAttributeArgument CreateCustomAttributeArgument(TypeReference typeReference, BlobValue blobValue, MemberReference memberReference)
{
var val = blobValue.Value;
if (typeReference.FullName == "System.Object")
{
val = new CustomAttributeArgument(GetBlobValueTypeReference(blobValue, memberReference), val);
}
else if (typeReference is ArrayType arrayType)
{
var arrayVal = (BlobValue[])val;
var array = new CustomAttributeArgument[arrayVal.Length];
var elementType = arrayType.ElementType;
for (int i = 0; i < arrayVal.Length; i++)
{
array[i] = CreateCustomAttributeArgument(elementType, arrayVal[i], memberReference);
}
val = array;
}
else if (typeReference.FullName == "System.Type")
{
val = GetTypeReference(memberReference, (Il2CppType)val);
}
return new CustomAttributeArgument(typeReference, val);
}
private TypeReference GetBlobValueTypeReference(BlobValue blobValue, MemberReference memberReference)
{
if (blobValue.EnumType != null)
{
return GetTypeReference(memberReference, blobValue.EnumType);
}
var il2CppType = new Il2CppType();
il2CppType.type = blobValue.il2CppTypeEnum;
return GetTypeReference(memberReference, il2CppType);
}
}
}

View file

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper
{
@ -36,7 +38,7 @@ namespace Il2CppDumper
this.metadata = metadata;
this.il2Cpp = il2Cpp;
if (il2Cpp.Version >= 27)
if (il2Cpp.Version >= 27 && il2Cpp.Version < 29)
{
customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)];
foreach (var imageDef in metadata.imageDefs)
@ -50,7 +52,7 @@ namespace Il2CppDumper
}
}
}
else
else if (il2Cpp.Version < 27)
{
customAttributeGenerators = il2Cpp.customAttributeGenerators;
}
@ -320,5 +322,148 @@ namespace Il2CppDumper
{
return il2Cpp.GetSectionHelper(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length);
}
public bool TryGetDefaultValue(int typeIndex, int dataIndex, out object value)
{
var pointer = metadata.GetDefaultValueFromIndex(dataIndex);
var defaultValueType = il2Cpp.types[typeIndex];
metadata.Position = pointer;
if (GetConstantValueFromBlob(defaultValueType.type, metadata.Reader, out var blobValue))
{
value = blobValue.Value;
return true;
}
else
{
value = pointer;
return false;
}
}
public bool GetConstantValueFromBlob(Il2CppTypeEnum type, BinaryReader reader, out BlobValue value)
{
value = new BlobValue();
value.il2CppTypeEnum = type;
switch (type)
{
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
value.Value = reader.ReadBoolean();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
value.Value = reader.ReadByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
value.Value = reader.ReadSByte();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
value.Value = BitConverter.ToChar(reader.ReadBytes(2), 0);
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
value.Value = reader.ReadUInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
value.Value = reader.ReadInt16();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
if (il2Cpp.Version >= 29)
{
value.Value = reader.ReadCompressedUInt32();
}
else
{
value.Value = reader.ReadUInt32();
}
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
if (il2Cpp.Version >= 29)
{
value.Value = reader.ReadCompressedInt32();
}
else
{
value.Value = reader.ReadInt32();
}
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
value.Value = reader.ReadUInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
value.Value = reader.ReadInt64();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
value.Value = reader.ReadSingle();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
value.Value = reader.ReadDouble();
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
int length;
if (il2Cpp.Version >= 29)
{
length = reader.ReadCompressedInt32();
if (length == -1)
{
value.Value = null;
}
else
{
value.Value = Encoding.UTF8.GetString(reader.ReadBytes(length));
}
}
else
{
length = reader.ReadInt32();
value.Value = reader.ReadString(length);
}
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
var arrayLen = reader.ReadCompressedInt32();
if (arrayLen == -1)
{
value.Value = null;
}
else
{
var array = new BlobValue[arrayLen];
var arrayElementType = ReadEncodedTypeEnum(reader, out var enumType);
var arrayElementsAreDifferent = reader.ReadByte();
for (int i = 0; i < arrayLen; i++)
{
var elementType = arrayElementType;
if (arrayElementsAreDifferent == 1)
{
elementType = ReadEncodedTypeEnum(reader, out enumType);
}
GetConstantValueFromBlob(elementType, reader, out var data);
data.il2CppTypeEnum = elementType;
data.EnumType = enumType;
array[i] = data;
}
value.Value = array;
}
return true;
case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX:
var typeIndex = reader.ReadCompressedInt32();
value.Value = il2Cpp.types[typeIndex];
return true;
default:
value = null;
return false;
}
}
public Il2CppTypeEnum ReadEncodedTypeEnum(BinaryReader reader, out Il2CppType enumType)
{
enumType = null;
var type = (Il2CppTypeEnum)reader.ReadByte();
if (type == Il2CppTypeEnum.IL2CPP_TYPE_ENUM)
{
var enumTypeIndex = reader.ReadCompressedInt32();
enumType = il2Cpp.types[enumTypeIndex];
var typeDef = GetTypeDefinitionFromIl2CppType(enumType);
type = il2Cpp.types[typeDef.elementTypeIndex].type;
}
return type;
}
}
}

View file

@ -340,6 +340,10 @@ namespace Il2CppDumper
var va2 = FindReference(va - (ulong)i * il2Cpp.PointerSize);
if (va2 != 0ul)
{
if (il2Cpp.Version >= 29)
{
return va2 - il2Cpp.PointerSize * 14;
}
return va2 - il2Cpp.PointerSize * 13;
}
}