mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-09 11:17:35 -03:00
v29支持
This commit is contained in:
parent
22c6374f6f
commit
43ff0f23c1
15 changed files with 725 additions and 239 deletions
101
Il2CppDumper/Extensions/BinaryReaderExtensions.cs
Normal file
101
Il2CppDumper/Extensions/BinaryReaderExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
8
Il2CppDumper/Utils/AttributeArgument.cs
Normal file
8
Il2CppDumper/Utils/AttributeArgument.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Il2CppDumper
|
||||
{
|
||||
public class AttributeArgument
|
||||
{
|
||||
public BlobValue Value;
|
||||
public int Index;
|
||||
}
|
||||
}
|
15
Il2CppDumper/Utils/BlobValue.cs
Normal file
15
Il2CppDumper/Utils/BlobValue.cs
Normal 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;
|
||||
}
|
||||
}
|
170
Il2CppDumper/Utils/CustomAttributeDataReader.cs
Normal file
170
Il2CppDumper/Utils/CustomAttributeDataReader.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
10
Il2CppDumper/Utils/CustomAttributeReaderVisitor.cs
Normal file
10
Il2CppDumper/Utils/CustomAttributeReaderVisitor.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Il2CppDumper
|
||||
{
|
||||
public class CustomAttributeReaderVisitor
|
||||
{
|
||||
public int CtorIndex;
|
||||
public AttributeArgument[] Arguments;
|
||||
public AttributeArgument[] Fields;
|
||||
public AttributeArgument[] Properties;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue