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 double ReadDouble() => reader.ReadDouble();
public uint ReadULeb128() public uint ReadCompressedUInt32() => reader.ReadCompressedUInt32();
{
uint value = reader.ReadByte(); public int ReadCompressedInt32() => reader.ReadCompressedInt32();
if (value >= 0x80)
{ public uint ReadULeb128() => reader.ReadULeb128();
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 void Write(bool value) => writer.Write(value); public void Write(bool value) => writer.Write(value);
@ -246,6 +233,10 @@ namespace Il2CppDumper
get => Is32Bit ? 4ul : 8ul; get => Is32Bit ? 4ul : 8ul;
} }
public BinaryReader Reader => reader;
public BinaryWriter Writer => writer;
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) if (disposing)

View file

@ -128,7 +128,8 @@ namespace Il2CppDumper
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */ IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */ 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 public class Il2CppType
@ -261,7 +262,7 @@ namespace Il2CppDumper
public long rgctxsCount; public long rgctxsCount;
public ulong rgctxs; public ulong rgctxs;
public ulong debuggerMetadata; public ulong debuggerMetadata;
[Version(Min = 27)] [Version(Min = 27, Max = 27.2)]
public ulong customAttributeCacheGenerator; public ulong customAttributeCacheGenerator;
[Version(Min = 27)] [Version(Min = 27)]
public ulong moduleInitializer; public ulong moduleInitializer;

View file

@ -20,6 +20,7 @@ namespace Il2CppDumper
private Dictionary<int, Il2CppParameterDefaultValue> parameterDefaultValuesDic; private Dictionary<int, Il2CppParameterDefaultValue> parameterDefaultValuesDic;
public Il2CppPropertyDefinition[] propertyDefs; public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributeTypeRanges; public Il2CppCustomAttributeTypeRange[] attributeTypeRanges;
public Il2CppCustomAttributeDataRange[] attributeDataRanges;
private Dictionary<Il2CppImageDefinition, Dictionary<uint, int>> attributeTypeRangesDic; private Dictionary<Il2CppImageDefinition, Dictionary<uint, int>> attributeTypeRangesDic;
public Il2CppStringLiteral[] stringLiterals; public Il2CppStringLiteral[] stringLiterals;
private Il2CppMetadataUsageList[] metadataUsageLists; private Il2CppMetadataUsageList[] metadataUsageLists;
@ -48,7 +49,7 @@ namespace Il2CppDumper
throw new InvalidDataException("ERROR: Metadata file supplied is not valid metadata file."); throw new InvalidDataException("ERROR: Metadata file supplied is not valid metadata file.");
} }
var version = ReadInt32(); 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}]."); throw new NotSupportedException($"ERROR: Metadata file supplied is not a supported version[{version}].");
} }
@ -63,39 +64,39 @@ namespace Il2CppDumper
} }
else else
{ {
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesCount); imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);
if (imageDefs.Any(x => x.token != 1)) if (imageDefs.Any(x => x.token != 1))
{ {
Version = 24.1; Version = 24.1;
} }
} }
} }
imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesCount); imageDefs = ReadMetadataClassArray<Il2CppImageDefinition>(header.imagesOffset, header.imagesSize);
if (Version == 24.2 && header.assembliesCount / 68 < imageDefs.Length) if (Version == 24.2 && header.assembliesSize / 68 < imageDefs.Length)
{ {
Version = 24.4; Version = 24.4;
} }
assemblyDefs = ReadMetadataClassArray<Il2CppAssemblyDefinition>(header.assembliesOffset, header.assembliesCount); assemblyDefs = ReadMetadataClassArray<Il2CppAssemblyDefinition>(header.assembliesOffset, header.assembliesSize);
typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(header.typeDefinitionsOffset, header.typeDefinitionsCount); typeDefs = ReadMetadataClassArray<Il2CppTypeDefinition>(header.typeDefinitionsOffset, header.typeDefinitionsSize);
methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(header.methodsOffset, header.methodsCount); methodDefs = ReadMetadataClassArray<Il2CppMethodDefinition>(header.methodsOffset, header.methodsSize);
parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(header.parametersOffset, header.parametersCount); parameterDefs = ReadMetadataClassArray<Il2CppParameterDefinition>(header.parametersOffset, header.parametersSize);
fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(header.fieldsOffset, header.fieldsCount); fieldDefs = ReadMetadataClassArray<Il2CppFieldDefinition>(header.fieldsOffset, header.fieldsSize);
var fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(header.fieldDefaultValuesOffset, header.fieldDefaultValuesCount); var fieldDefaultValues = ReadMetadataClassArray<Il2CppFieldDefaultValue>(header.fieldDefaultValuesOffset, header.fieldDefaultValuesSize);
var parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(header.parameterDefaultValuesOffset, header.parameterDefaultValuesCount); var parameterDefaultValues = ReadMetadataClassArray<Il2CppParameterDefaultValue>(header.parameterDefaultValuesOffset, header.parameterDefaultValuesSize);
fieldDefaultValuesDic = fieldDefaultValues.ToDictionary(x => x.fieldIndex); fieldDefaultValuesDic = fieldDefaultValues.ToDictionary(x => x.fieldIndex);
parameterDefaultValuesDic = parameterDefaultValues.ToDictionary(x => x.parameterIndex); parameterDefaultValuesDic = parameterDefaultValues.ToDictionary(x => x.parameterIndex);
propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(header.propertiesOffset, header.propertiesCount); propertyDefs = ReadMetadataClassArray<Il2CppPropertyDefinition>(header.propertiesOffset, header.propertiesSize);
interfaceIndices = ReadClassArray<int>(header.interfacesOffset, header.interfacesCount / 4); interfaceIndices = ReadClassArray<int>(header.interfacesOffset, header.interfacesSize / 4);
nestedTypeIndices = ReadClassArray<int>(header.nestedTypesOffset, header.nestedTypesCount / 4); nestedTypeIndices = ReadClassArray<int>(header.nestedTypesOffset, header.nestedTypesSize / 4);
eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(header.eventsOffset, header.eventsCount); eventDefs = ReadMetadataClassArray<Il2CppEventDefinition>(header.eventsOffset, header.eventsSize);
genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(header.genericContainersOffset, header.genericContainersCount); genericContainers = ReadMetadataClassArray<Il2CppGenericContainer>(header.genericContainersOffset, header.genericContainersSize);
genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(header.genericParametersOffset, header.genericParametersCount); genericParameters = ReadMetadataClassArray<Il2CppGenericParameter>(header.genericParametersOffset, header.genericParametersSize);
constraintIndices = ReadClassArray<int>(header.genericParameterConstraintsOffset, header.genericParameterConstraintsCount / 4); constraintIndices = ReadClassArray<int>(header.genericParameterConstraintsOffset, header.genericParameterConstraintsSize / 4);
vtableMethods = ReadClassArray<uint>(header.vtableMethodsOffset, header.vtableMethodsCount / 4); vtableMethods = ReadClassArray<uint>(header.vtableMethodsOffset, header.vtableMethodsSize / 4);
stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(header.stringLiteralOffset, header.stringLiteralCount); stringLiterals = ReadMetadataClassArray<Il2CppStringLiteral>(header.stringLiteralOffset, header.stringLiteralSize);
if (Version > 16) if (Version > 16)
{ {
fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(header.fieldRefsOffset, header.fieldRefsCount); fieldRefs = ReadMetadataClassArray<Il2CppFieldRef>(header.fieldRefsOffset, header.fieldRefsSize);
if (Version < 27) if (Version < 27)
{ {
metadataUsageLists = ReadMetadataClassArray<Il2CppMetadataUsageList>(header.metadataUsageListsOffset, header.metadataUsageListsCount); metadataUsageLists = ReadMetadataClassArray<Il2CppMetadataUsageList>(header.metadataUsageListsOffset, header.metadataUsageListsCount);
@ -104,11 +105,15 @@ namespace Il2CppDumper
ProcessingMetadataUsage(); ProcessingMetadataUsage();
} }
} }
if (Version > 20) if (Version > 20 && Version < 29)
{ {
attributeTypeRanges = ReadMetadataClassArray<Il2CppCustomAttributeTypeRange>(header.attributesInfoOffset, header.attributesInfoCount); attributeTypeRanges = ReadMetadataClassArray<Il2CppCustomAttributeTypeRange>(header.attributesInfoOffset, header.attributesInfoCount);
attributeTypes = ReadClassArray<int>(header.attributeTypesOffset, header.attributeTypesCount / 4); attributeTypes = ReadClassArray<int>(header.attributeTypesOffset, header.attributeTypesCount / 4);
} }
if (Version >= 29)
{
attributeDataRanges = ReadMetadataClassArray<Il2CppCustomAttributeDataRange>(header.attributeDataRangeOffset, header.attributeDataRangeSize);
}
if (Version > 24) if (Version > 24)
{ {
attributeTypeRangesDic = new Dictionary<Il2CppImageDefinition, Dictionary<uint, int>>(); attributeTypeRangesDic = new Dictionary<Il2CppImageDefinition, Dictionary<uint, int>>();
@ -119,7 +124,14 @@ namespace Il2CppDumper
var end = imageDef.customAttributeStart + imageDef.customAttributeCount; var end = imageDef.customAttributeStart + imageDef.customAttributeCount;
for (int i = imageDef.customAttributeStart; i < end; i++) 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 uint sanity;
public int version; public int version;
public uint stringLiteralOffset; // string data for managed code public uint stringLiteralOffset; // string data for managed code
public int stringLiteralCount; public int stringLiteralSize;
public uint stringLiteralDataOffset; public uint stringLiteralDataOffset;
public int stringLiteralDataCount; public int stringLiteralDataSize;
public uint stringOffset; // string data for metadata public uint stringOffset; // string data for metadata
public int stringCount; public int stringSize;
public uint eventsOffset; // Il2CppEventDefinition public uint eventsOffset; // Il2CppEventDefinition
public int eventsCount; public int eventsSize;
public uint propertiesOffset; // Il2CppPropertyDefinition public uint propertiesOffset; // Il2CppPropertyDefinition
public int propertiesCount; public int propertiesSize;
public uint methodsOffset; // Il2CppMethodDefinition public uint methodsOffset; // Il2CppMethodDefinition
public int methodsCount; public int methodsSize;
public uint parameterDefaultValuesOffset; // Il2CppParameterDefaultValue public uint parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
public int parameterDefaultValuesCount; public int parameterDefaultValuesSize;
public uint fieldDefaultValuesOffset; // Il2CppFieldDefaultValue public uint fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
public int fieldDefaultValuesCount; public int fieldDefaultValuesSize;
public uint fieldAndParameterDefaultValueDataOffset; // uint8_t public uint fieldAndParameterDefaultValueDataOffset; // uint8_t
public int fieldAndParameterDefaultValueDataCount; public int fieldAndParameterDefaultValueDataSize;
public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
public int fieldMarshaledSizesCount; public int fieldMarshaledSizesSize;
public uint parametersOffset; // Il2CppParameterDefinition public uint parametersOffset; // Il2CppParameterDefinition
public int parametersCount; public int parametersSize;
public uint fieldsOffset; // Il2CppFieldDefinition public uint fieldsOffset; // Il2CppFieldDefinition
public int fieldsCount; public int fieldsSize;
public uint genericParametersOffset; // Il2CppGenericParameter public uint genericParametersOffset; // Il2CppGenericParameter
public int genericParametersCount; public int genericParametersSize;
public uint genericParameterConstraintsOffset; // TypeIndex public uint genericParameterConstraintsOffset; // TypeIndex
public int genericParameterConstraintsCount; public int genericParameterConstraintsSize;
public uint genericContainersOffset; // Il2CppGenericContainer public uint genericContainersOffset; // Il2CppGenericContainer
public int genericContainersCount; public int genericContainersSize;
public uint nestedTypesOffset; // TypeDefinitionIndex public uint nestedTypesOffset; // TypeDefinitionIndex
public int nestedTypesCount; public int nestedTypesSize;
public uint interfacesOffset; // TypeIndex public uint interfacesOffset; // TypeIndex
public int interfacesCount; public int interfacesSize;
public uint vtableMethodsOffset; // EncodedMethodIndex public uint vtableMethodsOffset; // EncodedMethodIndex
public int vtableMethodsCount; public int vtableMethodsSize;
public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
public int interfaceOffsetsCount; public int interfaceOffsetsSize;
public uint typeDefinitionsOffset; // Il2CppTypeDefinition public uint typeDefinitionsOffset; // Il2CppTypeDefinition
public int typeDefinitionsCount; public int typeDefinitionsSize;
[Version(Max = 24.1)] [Version(Max = 24.1)]
public uint rgctxEntriesOffset; // Il2CppRGCTXDefinition public uint rgctxEntriesOffset; // Il2CppRGCTXDefinition
[Version(Max = 24.1)] [Version(Max = 24.1)]
public int rgctxEntriesCount; public int rgctxEntriesCount;
public uint imagesOffset; // Il2CppImageDefinition public uint imagesOffset; // Il2CppImageDefinition
public int imagesCount; public int imagesSize;
public uint assembliesOffset; // Il2CppAssemblyDefinition public uint assembliesOffset; // Il2CppAssemblyDefinition
public int assembliesCount; public int assembliesSize;
[Version(Min = 19, Max = 24.5)] [Version(Min = 19, Max = 24.5)]
public uint metadataUsageListsOffset; // Il2CppMetadataUsageList public uint metadataUsageListsOffset; // Il2CppMetadataUsageList
[Version(Min = 19, Max = 24.5)] [Version(Min = 19, Max = 24.5)]
@ -65,27 +65,35 @@ namespace Il2CppDumper
[Version(Min = 19)] [Version(Min = 19)]
public uint fieldRefsOffset; // Il2CppFieldRef public uint fieldRefsOffset; // Il2CppFieldRef
[Version(Min = 19)] [Version(Min = 19)]
public int fieldRefsCount; public int fieldRefsSize;
[Version(Min = 20)] [Version(Min = 20)]
public int referencedAssembliesOffset; // int32_t public int referencedAssembliesOffset; // int32_t
[Version(Min = 20)] [Version(Min = 20)]
public int referencedAssembliesCount; public int referencedAssembliesSize;
[Version(Min = 21)] [Version(Min = 21, Max = 27.2)]
public uint attributesInfoOffset; // Il2CppCustomAttributeTypeRange public uint attributesInfoOffset; // Il2CppCustomAttributeTypeRange
[Version(Min = 21)] [Version(Min = 21, Max = 27.2)]
public int attributesInfoCount; public int attributesInfoCount;
[Version(Min = 21)] [Version(Min = 21, Max = 27.2)]
public uint attributeTypesOffset; // TypeIndex public uint attributeTypesOffset; // TypeIndex
[Version(Min = 21)] [Version(Min = 21, Max = 27.2)]
public int attributeTypesCount; 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)] [Version(Min = 22)]
public int unresolvedVirtualCallParameterTypesOffset; // TypeIndex public int unresolvedVirtualCallParameterTypesOffset; // TypeIndex
[Version(Min = 22)] [Version(Min = 22)]
public int unresolvedVirtualCallParameterTypesCount; public int unresolvedVirtualCallParameterTypesSize;
[Version(Min = 22)] [Version(Min = 22)]
public int unresolvedVirtualCallParameterRangesOffset; // Il2CppRange public int unresolvedVirtualCallParameterRangesOffset; // Il2CppRange
[Version(Min = 22)] [Version(Min = 22)]
public int unresolvedVirtualCallParameterRangesCount; public int unresolvedVirtualCallParameterRangesSize;
[Version(Min = 23)] [Version(Min = 23)]
public int windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair public int windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair
[Version(Min = 23)] [Version(Min = 23)]
@ -97,7 +105,7 @@ namespace Il2CppDumper
[Version(Min = 24)] [Version(Min = 24)]
public int exportedTypeDefinitionsOffset; // TypeDefinitionIndex public int exportedTypeDefinitionsOffset; // TypeDefinitionIndex
[Version(Min = 24)] [Version(Min = 24)]
public int exportedTypeDefinitionsCount; public int exportedTypeDefinitionsSize;
} }
public class Il2CppAssemblyDefinition public class Il2CppAssemblyDefinition
@ -368,6 +376,7 @@ namespace Il2CppDumper
IL2CPP_RGCTX_DATA_CLASS, IL2CPP_RGCTX_DATA_CLASS,
IL2CPP_RGCTX_DATA_METHOD, IL2CPP_RGCTX_DATA_METHOD,
IL2CPP_RGCTX_DATA_ARRAY, IL2CPP_RGCTX_DATA_ARRAY,
IL2CPP_RGCTX_DATA_CONSTRAINED,
} }
public class Il2CppRGCTXDefinitionData public class Il2CppRGCTXDefinitionData
@ -379,7 +388,11 @@ namespace Il2CppDumper
public class Il2CppRGCTXDefinition 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)] [Version(Max = 27.1)]
public Il2CppRGCTXDefinitionData data; public Il2CppRGCTXDefinitionData data;
[Version(Min = 27.2)] [Version(Min = 27.2)]
@ -396,4 +409,10 @@ namespace Il2CppDumper
kIl2CppMetadataUsageStringLiteral, kIl2CppMetadataUsageStringLiteral,
kIl2CppMetadataUsageMethodRef, kIl2CppMetadataUsageMethodRef,
}; };
public class Il2CppCustomAttributeDataRange
{
public uint token;
public uint startOffset;
}
} }

View file

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

View file

@ -165,7 +165,7 @@ namespace Il2CppDumper
writer.Write($"{executor.GetTypeName(fieldType, false, false)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); writer.Write($"{executor.GetTypeName(fieldType, false, false)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}");
if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefaultValue) && fieldDefaultValue.dataIndex != -1) 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($" = "); writer.Write($" = ");
if (value is string str) if (value is string str)
@ -181,6 +181,10 @@ namespace Il2CppDumper
{ {
writer.Write($"{value}"); writer.Write($"{value}");
} }
else
{
writer.Write("null");
}
} }
else else
{ {
@ -238,13 +242,13 @@ namespace Il2CppDumper
{ {
writer.Write("\n"); writer.Write("\n");
var methodDef = metadata.methodDefs[i]; var methodDef = metadata.methodDefs[i];
var isAbstract = (methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;
if (config.DumpAttribute) if (config.DumpAttribute)
{ {
writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t")); writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t"));
} }
if (config.DumpMethodOffset) if (config.DumpMethodOffset)
{ {
var isAbstract = (methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0;
var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef); var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef);
if (!isAbstract && methodPointer > 0) if (!isAbstract && methodPointer > 0)
{ {
@ -312,7 +316,7 @@ namespace Il2CppDumper
parameterStr += $"{parameterTypeName} {parameterName}"; parameterStr += $"{parameterTypeName} {parameterName}";
if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) 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 += " = "; parameterStr += " = ";
if (value is string str) if (value is string str)
@ -328,6 +332,10 @@ namespace Il2CppDumper
{ {
parameterStr += $"{value}"; parameterStr += $"{value}";
} }
else
{
writer.Write("null");
}
} }
else else
{ {
@ -337,7 +345,14 @@ namespace Il2CppDumper
parameterStrs.Add(parameterStr); parameterStrs.Add(parameterStr);
} }
writer.Write(string.Join(", ", parameterStrs)); 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)) if (il2Cpp.methodDefinitionMethodSpecs.TryGetValue(i, out var methodSpecs))
{ {
@ -387,21 +402,44 @@ namespace Il2CppDumper
var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token); var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);
if (attributeIndex >= 0) if (attributeIndex >= 0)
{ {
var methodPointer = executor.customAttributeGenerators[attributeIndex]; if (il2Cpp.Version < 29)
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]; var methodPointer = executor.customAttributeGenerators[attributeIndex];
sb.AppendFormat("{0}[{1}] // RVA: 0x{2:X} Offset: 0x{3:X} VA: 0x{4:X}\n", var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
padding, var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
executor.GetTypeName(il2Cpp.types[typeIndex], false, false), var sb = new StringBuilder();
fixedMethodPointer, for (var i = 0; i < attributeTypeRange.count; i++)
il2Cpp.MapVATR(methodPointer), {
methodPointer); 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 else
{ {
@ -458,58 +496,5 @@ namespace Il2CppDumper
methodModifiers.Add(methodDef, str); methodModifiers.Add(methodDef, str);
return 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.genericMethodPointers);
orderedPointers.AddRange(il2Cpp.invokerPointers); orderedPointers.AddRange(il2Cpp.invokerPointers);
orderedPointers.AddRange(executor.customAttributeGenerators); if (il2Cpp.Version < 29)
{
orderedPointers.AddRange(executor.customAttributeGenerators);
}
if (il2Cpp.Version >= 22) if (il2Cpp.Version >= 22)
{ {
if (il2Cpp.reversePInvokeWrappers != null) 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 Dictionary<Il2CppGenericParameter, GenericParameter> genericParameterDic = new Dictionary<Il2CppGenericParameter, GenericParameter>();
private MethodDefinition attributeAttribute; private MethodDefinition attributeAttribute;
private TypeReference stringType; 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) public DummyAssemblyGenerator(Il2CppExecutor il2CppExecutor, bool addToken)
{ {
@ -44,10 +46,7 @@ namespace Il2CppDumper
}; };
resolver.Register(il2CppDummyDll); resolver.Register(il2CppDummyDll);
var fieldDefinitionDic = new Dictionary<int, FieldDefinition>();
var methodDefinitionDic = new Dictionary<int, MethodDefinition>();
var parameterDefinitionDic = new Dictionary<int, ParameterDefinition>(); var parameterDefinitionDic = new Dictionary<int, ParameterDefinition>();
var propertyDefinitionDic = new Dictionary<int, PropertyDefinition>();
var eventDefinitionDic = new Dictionary<int, EventDefinition>(); var eventDefinitionDic = new Dictionary<int, EventDefinition>();
//创建程序集,同时创建所有类 //创建程序集,同时创建所有类
@ -56,7 +55,17 @@ namespace Il2CppDumper
var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);
var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname; var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname;
var assemblyName = metadata.GetStringFromIndex(aname.nameIndex); 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.Culture = metadata.GetStringFromIndex(aname.cultureIndex);
assemblyNameDef.PublicKey = Encoding.UTF8.GetBytes(metadata.GetStringFromIndex(aname.publicKeyIndex)); assemblyNameDef.PublicKey = Encoding.UTF8.GetBytes(metadata.GetStringFromIndex(aname.publicKeyIndex));
assemblyNameDef.HashAlgorithm = (AssemblyHashAlgorithm)aname.hash_alg; assemblyNameDef.HashAlgorithm = (AssemblyHashAlgorithm)aname.hash_alg;
@ -169,7 +178,7 @@ namespace Il2CppDumper
//fieldDefault //fieldDefault
if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1) 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; fieldDefinition.Constant = value;
} }
@ -262,7 +271,7 @@ namespace Il2CppDumper
//ParameterDefault //ParameterDefault
if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) 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; 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) private void CreateCustomAttribute(Il2CppImageDefinition imageDef, int customAttributeIndex, uint token, ModuleDefinition moduleDefinition, Collection<CustomAttribute> customAttributes)
{ {
var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token); var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, customAttributeIndex, token);
if (attributeIndex >= 0) if (attributeIndex >= 0)
{ {
var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex]; if (il2Cpp.Version < 29)
for (int i = 0; i < attributeTypeRange.count; i++)
{ {
var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + i]; var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex];
var attributeType = il2Cpp.types[attributeTypeIndex]; for (int i = 0; i < attributeTypeRange.count; i++)
var typeDef = executor.GetTypeDefinitionFromIl2CppType(attributeType);
var typeDefinition = typeDefinitionDic[typeDef];
if (!TryRestoreCustomAttribute(typeDefinition, moduleDefinition, customAttributes))
{ {
var methodPointer = executor.customAttributeGenerators[attributeIndex]; var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); var attributeType = il2Cpp.types[attributeTypeIndex];
var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(attributeAttribute)); var typeDef = executor.GetTypeDefinitionFromIl2CppType(attributeType);
var name = new CustomAttributeNamedArgument("Name", new CustomAttributeArgument(stringType, typeDefinition.Name)); var typeDefinition = typeDefinitionDic[typeDef];
var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}")); if (!TryRestoreCustomAttribute(typeDefinition, moduleDefinition, customAttributes))
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}")); {
customAttribute.Fields.Add(name); var methodPointer = executor.customAttributeGenerators[attributeIndex];
customAttribute.Fields.Add(rva); var fixedMethodPointer = il2Cpp.GetRVA(methodPointer);
customAttribute.Fields.Add(offset); var customAttribute = new CustomAttribute(moduleDefinition.ImportReference(attributeAttribute));
customAttributes.Add(customAttribute); 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; 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
namespace Il2CppDumper namespace Il2CppDumper
{ {
@ -36,7 +38,7 @@ namespace Il2CppDumper
this.metadata = metadata; this.metadata = metadata;
this.il2Cpp = il2Cpp; this.il2Cpp = il2Cpp;
if (il2Cpp.Version >= 27) if (il2Cpp.Version >= 27 && il2Cpp.Version < 29)
{ {
customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)]; customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)];
foreach (var imageDef in metadata.imageDefs) foreach (var imageDef in metadata.imageDefs)
@ -50,7 +52,7 @@ namespace Il2CppDumper
} }
} }
} }
else else if (il2Cpp.Version < 27)
{ {
customAttributeGenerators = il2Cpp.customAttributeGenerators; 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); 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); var va2 = FindReference(va - (ulong)i * il2Cpp.PointerSize);
if (va2 != 0ul) if (va2 != 0ul)
{ {
if (il2Cpp.Version >= 29)
{
return va2 - il2Cpp.PointerSize * 14;
}
return va2 - il2Cpp.PointerSize * 13; return va2 - il2Cpp.PointerSize * 13;
} }
} }