mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-25 02:03:02 -03:00
基础Unity2019.1支持
Elf arm Unity2019.1支持
This commit is contained in:
parent
3a2d25f39f
commit
b8679e2985
7 changed files with 389 additions and 262 deletions
59
Il2CppDumper/BoyerMooreHorspool.cs
Normal file
59
Il2CppDumper/BoyerMooreHorspool.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Il2CppDumper
|
||||
{
|
||||
static class BoyerMooreHorspool
|
||||
{
|
||||
public static IEnumerable<int> IndicesOf(this byte[] source, byte[] pattern)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
if (pattern == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pattern));
|
||||
}
|
||||
|
||||
int valueLength = source.Length;
|
||||
int patternLength = pattern.Length;
|
||||
|
||||
if ((valueLength == 0) || (patternLength == 0) || (patternLength > valueLength))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var badCharacters = new int[256];
|
||||
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
badCharacters[i] = patternLength;
|
||||
}
|
||||
|
||||
var lastPatternByte = patternLength - 1;
|
||||
|
||||
for (int i = 0; i < lastPatternByte; i++)
|
||||
{
|
||||
badCharacters[pattern[i]] = lastPatternByte - i;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
while (index <= valueLength - patternLength)
|
||||
{
|
||||
for (var i = lastPatternByte; source[index + i] == pattern[i]; i--)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
yield return index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index += badCharacters[source[index + lastPatternByte]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -91,164 +91,160 @@ namespace Il2CppDumper
|
|||
}
|
||||
}
|
||||
//处理field, method, property等等
|
||||
for (var index = 0; index < metadata.typeDefs.Length; ++index)
|
||||
for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)
|
||||
{
|
||||
var typeDef = metadata.typeDefs[index];
|
||||
var typeDefinition = typeDefinitionDic[index];
|
||||
//field
|
||||
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
|
||||
for (var i = typeDef.fieldStart; i < fieldEnd; ++i)
|
||||
var imageDef = metadata.imageDefs[imageIndex];
|
||||
var typeEnd = imageDef.typeStart + imageDef.typeCount;
|
||||
for (int index = imageDef.typeStart; index < typeEnd; index++)
|
||||
{
|
||||
var fieldDef = metadata.fieldDefs[i];
|
||||
var fieldType = il2cpp.types[fieldDef.typeIndex];
|
||||
var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex);
|
||||
var fieldTypeRef = GetTypeReference(typeDefinition, fieldType);
|
||||
var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef);
|
||||
typeDefinition.Fields.Add(fieldDefinition);
|
||||
//fieldDefault
|
||||
if (fieldDefinition.HasDefault)
|
||||
var typeDef = metadata.typeDefs[index];
|
||||
var typeDefinition = typeDefinitionDic[index];
|
||||
//field
|
||||
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
|
||||
for (var i = typeDef.fieldStart; i < fieldEnd; ++i)
|
||||
{
|
||||
var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i);
|
||||
if (fieldDefault != null && fieldDefault.dataIndex != -1)
|
||||
var fieldDef = metadata.fieldDefs[i];
|
||||
var fieldType = il2cpp.types[fieldDef.typeIndex];
|
||||
var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex);
|
||||
var fieldTypeRef = GetTypeReference(typeDefinition, fieldType);
|
||||
var fieldDefinition = new FieldDefinition(fieldName, (FieldAttributes)fieldType.attrs, fieldTypeRef);
|
||||
typeDefinition.Fields.Add(fieldDefinition);
|
||||
//fieldDefault
|
||||
if (fieldDefinition.HasDefault)
|
||||
{
|
||||
fieldDefinition.Constant = GetDefaultValue(fieldDefault.dataIndex, fieldDefault.typeIndex);
|
||||
}
|
||||
}
|
||||
//fieldOffset
|
||||
var fieldOffset = il2cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i);
|
||||
if (fieldOffset > 0)
|
||||
{
|
||||
var customAttribute = new CustomAttribute(typeDefinition.Module.Import(fieldOffsetAttribute));
|
||||
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{fieldOffset:X}"));
|
||||
customAttribute.Fields.Add(offset);
|
||||
fieldDefinition.CustomAttributes.Add(customAttribute);
|
||||
}
|
||||
}
|
||||
//method
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (var i = typeDef.methodStart; i < methodEnd; ++i)
|
||||
{
|
||||
var methodDef = metadata.methodDefs[i];
|
||||
var methodReturnType = il2cpp.types[methodDef.returnType];
|
||||
var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);
|
||||
var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.Import(typeof(void)));
|
||||
typeDefinition.Methods.Add(methodDefinition);
|
||||
methodDefinition.ReturnType = GetTypeReference(methodDefinition, methodReturnType);
|
||||
if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate")
|
||||
{
|
||||
var ilprocessor = methodDefinition.Body.GetILProcessor();
|
||||
ilprocessor.Append(ilprocessor.Create(OpCodes.Nop));
|
||||
}
|
||||
methodDefinitionDic.Add(i, methodDefinition);
|
||||
//method parameter
|
||||
for (var j = 0; j < methodDef.parameterCount; ++j)
|
||||
{
|
||||
var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];
|
||||
var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);
|
||||
var parameterType = il2cpp.types[parameterDef.typeIndex];
|
||||
var parameterTypeRef = GetTypeReference(methodDefinition, parameterType);
|
||||
var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef);
|
||||
methodDefinition.Parameters.Add(parameterDefinition);
|
||||
//ParameterDefault
|
||||
if (parameterDefinition.HasDefault)
|
||||
{
|
||||
var parameterDefault = metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j);
|
||||
if (parameterDefault != null && parameterDefault.dataIndex != -1)
|
||||
var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i);
|
||||
if (fieldDefault != null && fieldDefault.dataIndex != -1)
|
||||
{
|
||||
parameterDefinition.Constant = GetDefaultValue(parameterDefault.dataIndex, parameterDefault.typeIndex);
|
||||
fieldDefinition.Constant = GetDefaultValue(fieldDefault.dataIndex, fieldDefault.typeIndex);
|
||||
}
|
||||
}
|
||||
//fieldOffset
|
||||
var fieldOffset = il2cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i);
|
||||
if (fieldOffset > 0)
|
||||
{
|
||||
var customAttribute = new CustomAttribute(typeDefinition.Module.Import(fieldOffsetAttribute));
|
||||
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{fieldOffset:X}"));
|
||||
customAttribute.Fields.Add(offset);
|
||||
fieldDefinition.CustomAttributes.Add(customAttribute);
|
||||
}
|
||||
}
|
||||
//method
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (var i = typeDef.methodStart; i < methodEnd; ++i)
|
||||
{
|
||||
var methodDef = metadata.methodDefs[i];
|
||||
var methodReturnType = il2cpp.types[methodDef.returnType];
|
||||
var methodName = metadata.GetStringFromIndex(methodDef.nameIndex);
|
||||
var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.Import(typeof(void)));
|
||||
typeDefinition.Methods.Add(methodDefinition);
|
||||
methodDefinition.ReturnType = GetTypeReference(methodDefinition, methodReturnType);
|
||||
if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate")
|
||||
{
|
||||
var ilprocessor = methodDefinition.Body.GetILProcessor();
|
||||
ilprocessor.Append(ilprocessor.Create(OpCodes.Nop));
|
||||
}
|
||||
methodDefinitionDic.Add(i, methodDefinition);
|
||||
//method parameter
|
||||
for (var j = 0; j < methodDef.parameterCount; ++j)
|
||||
{
|
||||
var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j];
|
||||
var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex);
|
||||
var parameterType = il2cpp.types[parameterDef.typeIndex];
|
||||
var parameterTypeRef = GetTypeReference(methodDefinition, parameterType);
|
||||
var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef);
|
||||
methodDefinition.Parameters.Add(parameterDefinition);
|
||||
//ParameterDefault
|
||||
if (parameterDefinition.HasDefault)
|
||||
{
|
||||
var parameterDefault = metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j);
|
||||
if (parameterDefault != null && parameterDefault.dataIndex != -1)
|
||||
{
|
||||
parameterDefinition.Constant = GetDefaultValue(parameterDefault.dataIndex, parameterDefault.typeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
//补充泛型参数
|
||||
if (methodDef.genericContainerIndex >= 0)
|
||||
{
|
||||
var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex];
|
||||
if (genericContainer.type_argc > methodDefinition.GenericParameters.Count)
|
||||
{
|
||||
for (int j = methodDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++)
|
||||
{
|
||||
var genericParameter = new GenericParameter("T" + j, methodDefinition);
|
||||
methodDefinition.GenericParameters.Add(genericParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
//address
|
||||
var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token);
|
||||
if (methodPointer > 0)
|
||||
{
|
||||
var customAttribute = new CustomAttribute(typeDefinition.Module.Import(addressAttribute));
|
||||
var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}"));
|
||||
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2cpp.MapVATR(methodPointer):X}"));
|
||||
customAttribute.Fields.Add(rva);
|
||||
customAttribute.Fields.Add(offset);
|
||||
methodDefinition.CustomAttributes.Add(customAttribute);
|
||||
}
|
||||
}
|
||||
//property
|
||||
var propertyEnd = typeDef.propertyStart + typeDef.property_count;
|
||||
for (var i = typeDef.propertyStart; i < propertyEnd; ++i)
|
||||
{
|
||||
var propertyDef = metadata.propertyDefs[i];
|
||||
var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex);
|
||||
TypeReference propertyType = null;
|
||||
MethodDefinition GetMethod = null;
|
||||
MethodDefinition SetMethod = null;
|
||||
if (propertyDef.get >= 0)
|
||||
{
|
||||
GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get];
|
||||
propertyType = GetMethod.ReturnType;
|
||||
}
|
||||
if (propertyDef.set >= 0)
|
||||
{
|
||||
SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set];
|
||||
if (propertyType == null)
|
||||
propertyType = SetMethod.Parameters[0].ParameterType;
|
||||
}
|
||||
var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType)
|
||||
{
|
||||
GetMethod = GetMethod,
|
||||
SetMethod = SetMethod
|
||||
};
|
||||
typeDefinition.Properties.Add(propertyDefinition);
|
||||
}
|
||||
//event
|
||||
var eventEnd = typeDef.eventStart + typeDef.event_count;
|
||||
for (var i = typeDef.eventStart; i < eventEnd; ++i)
|
||||
{
|
||||
var eventDef = metadata.eventDefs[i];
|
||||
var eventName = metadata.GetStringFromIndex(eventDef.nameIndex);
|
||||
var eventType = il2cpp.types[eventDef.typeIndex];
|
||||
var eventTypeRef = GetTypeReference(typeDefinition, eventType);
|
||||
var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef);
|
||||
if (eventDef.add >= 0)
|
||||
eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add];
|
||||
if (eventDef.remove >= 0)
|
||||
eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove];
|
||||
if (eventDef.raise >= 0)
|
||||
eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise];
|
||||
typeDefinition.Events.Add(eventDefinition);
|
||||
}
|
||||
//补充泛型参数
|
||||
if (methodDef.genericContainerIndex >= 0)
|
||||
if (typeDef.genericContainerIndex >= 0)
|
||||
{
|
||||
var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex];
|
||||
if (genericContainer.type_argc > methodDefinition.GenericParameters.Count)
|
||||
var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex];
|
||||
if (genericContainer.type_argc > typeDefinition.GenericParameters.Count)
|
||||
{
|
||||
for (int j = methodDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++)
|
||||
for (int j = typeDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++)
|
||||
{
|
||||
var genericParameter = new GenericParameter("T" + j, methodDefinition);
|
||||
methodDefinition.GenericParameters.Add(genericParameter);
|
||||
var genericParameter = new GenericParameter("T" + j, typeDefinition);
|
||||
typeDefinition.GenericParameters.Add(genericParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
//address
|
||||
ulong methodPointer;
|
||||
if (methodDef.methodIndex >= 0)
|
||||
{
|
||||
methodPointer = il2cpp.methodPointers[methodDef.methodIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
il2cpp.genericMethoddDictionary.TryGetValue(i, out methodPointer);
|
||||
}
|
||||
if (methodPointer > 0)
|
||||
{
|
||||
var customAttribute = new CustomAttribute(typeDefinition.Module.Import(addressAttribute));
|
||||
var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}"));
|
||||
var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2cpp.MapVATR(methodPointer):X}"));
|
||||
customAttribute.Fields.Add(rva);
|
||||
customAttribute.Fields.Add(offset);
|
||||
methodDefinition.CustomAttributes.Add(customAttribute);
|
||||
}
|
||||
}
|
||||
//property
|
||||
var propertyEnd = typeDef.propertyStart + typeDef.property_count;
|
||||
for (var i = typeDef.propertyStart; i < propertyEnd; ++i)
|
||||
{
|
||||
var propertyDef = metadata.propertyDefs[i];
|
||||
var propertyName = metadata.GetStringFromIndex(propertyDef.nameIndex);
|
||||
TypeReference propertyType = null;
|
||||
MethodDefinition GetMethod = null;
|
||||
MethodDefinition SetMethod = null;
|
||||
if (propertyDef.get >= 0)
|
||||
{
|
||||
GetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.get];
|
||||
propertyType = GetMethod.ReturnType;
|
||||
}
|
||||
if (propertyDef.set >= 0)
|
||||
{
|
||||
SetMethod = methodDefinitionDic[typeDef.methodStart + propertyDef.set];
|
||||
if (propertyType == null)
|
||||
propertyType = SetMethod.Parameters[0].ParameterType;
|
||||
}
|
||||
var propertyDefinition = new PropertyDefinition(propertyName, (PropertyAttributes)propertyDef.attrs, propertyType)
|
||||
{
|
||||
GetMethod = GetMethod,
|
||||
SetMethod = SetMethod
|
||||
};
|
||||
typeDefinition.Properties.Add(propertyDefinition);
|
||||
}
|
||||
//event
|
||||
var eventEnd = typeDef.eventStart + typeDef.event_count;
|
||||
for (var i = typeDef.eventStart; i < eventEnd; ++i)
|
||||
{
|
||||
var eventDef = metadata.eventDefs[i];
|
||||
var eventName = metadata.GetStringFromIndex(eventDef.nameIndex);
|
||||
var eventType = il2cpp.types[eventDef.typeIndex];
|
||||
var eventTypeRef = GetTypeReference(typeDefinition, eventType);
|
||||
var eventDefinition = new EventDefinition(eventName, (EventAttributes)eventType.attrs, eventTypeRef);
|
||||
if (eventDef.add >= 0)
|
||||
eventDefinition.AddMethod = methodDefinitionDic[typeDef.methodStart + eventDef.add];
|
||||
if (eventDef.remove >= 0)
|
||||
eventDefinition.RemoveMethod = methodDefinitionDic[typeDef.methodStart + eventDef.remove];
|
||||
if (eventDef.raise >= 0)
|
||||
eventDefinition.InvokeMethod = methodDefinitionDic[typeDef.methodStart + eventDef.raise];
|
||||
typeDefinition.Events.Add(eventDefinition);
|
||||
|
||||
}
|
||||
//补充泛型参数
|
||||
if (typeDef.genericContainerIndex >= 0)
|
||||
{
|
||||
var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex];
|
||||
if (genericContainer.type_argc > typeDefinition.GenericParameters.Count)
|
||||
{
|
||||
for (int j = typeDefinition.GenericParameters.Count + 1; j <= genericContainer.type_argc; j++)
|
||||
{
|
||||
var genericParameter = new GenericParameter("T" + j, typeDefinition);
|
||||
typeDefinition.GenericParameters.Add(genericParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//第三遍,添加CustomAttribute。只添加SerializeField用于MonoBehaviour的反序列化
|
||||
|
|
|
@ -16,9 +16,23 @@ namespace Il2CppDumper
|
|||
private bool isDump;
|
||||
private uint dumpAddr;
|
||||
|
||||
private static readonly byte[] ARMFeatureBytes = { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
|
||||
private static readonly byte[] X86FeatureBytes1 = { 0x8D, 0x83 };//lea eax, X
|
||||
private static readonly byte[] X86FeatureBytes2 = { 0x89, 0x44, 0x24, 0x04, 0x8D, 0x83 };//mov [esp+4], eax and lea eax, X
|
||||
//默认编译器
|
||||
/*
|
||||
* LDR R1, [R1,R2]
|
||||
* ADD R0, R12, R2
|
||||
* ADD R2, R3, R2
|
||||
*/
|
||||
private static readonly byte[] ARMFeatureBytesv21 = { 0x02, 0x10, 0x91, 0xE7, 0x02, 0x00, 0x8C, 0xE0, 0x02, 0x20, 0x83, 0xE0 };
|
||||
/*
|
||||
* LDR R1, [PC,R1]
|
||||
* ADD R0, PC, R0
|
||||
* ADD R2, PC, R2
|
||||
*/
|
||||
private static readonly byte[] ARMFeatureBytesv24 = { 0x01, 0x10, 0x9F, 0xE7, 0x00, 0x00, 0x8F, 0xE0, 0x02, 0x20, 0x8F, 0xE0 };
|
||||
//TODO
|
||||
private static readonly byte[] X86FeatureBytesv21 = { 0x02, 0x10, 0x91, 0xE7, 0x02, 0x00, 0x8C, 0xE0, 0x02, 0x20, 0x83, 0xE0 };
|
||||
//TODO
|
||||
private static readonly byte[] X86FeatureBytesv24 = { 0x01, 0x10, 0x9F, 0xE7, 0x00, 0x00, 0x8F, 0xE0, 0x02, 0x20, 0x8F, 0xE0 };
|
||||
|
||||
public Elf(Stream stream, float version, long maxMetadataUsages) : base(stream, version, maxMetadataUsages)
|
||||
{
|
||||
|
@ -99,63 +113,54 @@ namespace Il2CppDumper
|
|||
public override bool Search()
|
||||
{
|
||||
var _GLOBAL_OFFSET_TABLE_ = dynamic_table.First(x => x.d_tag == DT_PLTGOT).d_un;
|
||||
uint initOffset = MapVATR(dynamic_table.First(x => x.d_tag == DT_INIT_ARRAY).d_un);
|
||||
var initSize = dynamic_table.First(x => x.d_tag == DT_INIT_ARRAYSZ).d_un;
|
||||
var addrs = ReadClassArray<uint>(initOffset, initSize / 4u);
|
||||
foreach (var i in addrs)
|
||||
var execs = program_table.Where(x => x.p_type == 1u && (x.p_flags & 1) == 1).ToArray();
|
||||
var resultList = new List<int>();
|
||||
byte[] featureBytes = null;
|
||||
if (version < 24f)
|
||||
{
|
||||
if (i > 0)
|
||||
featureBytes = elf_header.e_machine == 40 ? ARMFeatureBytesv21 : X86FeatureBytesv21;
|
||||
}
|
||||
else if (version >= 24f)
|
||||
{
|
||||
featureBytes = elf_header.e_machine == 40 ? ARMFeatureBytesv24 : X86FeatureBytesv24;
|
||||
}
|
||||
foreach (var exec in execs)
|
||||
{
|
||||
Position = exec.p_offset;
|
||||
var buff = ReadBytes((int)exec.p_filesz);
|
||||
resultList.AddRange(buff.IndicesOf(featureBytes));
|
||||
}
|
||||
if (resultList.Count == 1)
|
||||
{
|
||||
uint codeRegistration = 0;
|
||||
uint metadataRegistration = 0;
|
||||
if (version < 24f)
|
||||
{
|
||||
Position = i;
|
||||
if (elf_header.e_machine == 0x28) //ARM
|
||||
if (elf_header.e_machine == 40)
|
||||
{
|
||||
var buff = ReadBytes(12);
|
||||
if (ARMFeatureBytes.SequenceEqual(buff))
|
||||
{
|
||||
Position = i + 0x2c;
|
||||
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = subaddr + 0x28;
|
||||
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
|
||||
Position = subaddr + 0x2C;
|
||||
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = MapVATR(ptr);
|
||||
var metadataRegistration = ReadUInt32();
|
||||
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
|
||||
Init(codeRegistration, metadataRegistration);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (elf_header.e_machine == 0x3) //x86
|
||||
{
|
||||
Position = i + 22;
|
||||
var buff = ReadBytes(2);
|
||||
if (X86FeatureBytes1.SequenceEqual(buff))
|
||||
{
|
||||
Position = i + 28;
|
||||
buff = ReadBytes(6);
|
||||
if (X86FeatureBytes2.SequenceEqual(buff))
|
||||
{
|
||||
Position = i + 0x18;
|
||||
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = subaddr + 0x2C;
|
||||
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
|
||||
Position = subaddr + 0x20;
|
||||
var temp = ReadUInt16();
|
||||
var metadataRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
if (temp == 0x838B)//mov
|
||||
{
|
||||
Position = MapVATR(metadataRegistration);
|
||||
metadataRegistration = ReadUInt32();
|
||||
}
|
||||
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
|
||||
Init(codeRegistration, metadataRegistration);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
var result = (uint)resultList[0];
|
||||
Position = result + 0x14;
|
||||
codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = result + 0x18;
|
||||
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
|
||||
Position = MapVATR(ptr);
|
||||
metadataRegistration = ReadUInt32();
|
||||
}
|
||||
}
|
||||
else if (version >= 24f)
|
||||
{
|
||||
if (elf_header.e_machine == 40)
|
||||
{
|
||||
var result = (uint)resultList[0];
|
||||
Position = result + 0x14;
|
||||
codeRegistration = ReadUInt32() + result + 0xcu;
|
||||
Position = result + 0x10;
|
||||
var ptr = ReadUInt32() + result + 0x8;
|
||||
Position = MapVATR(ptr);
|
||||
metadataRegistration = ReadUInt32();
|
||||
}
|
||||
}
|
||||
return AutoInit(codeRegistration, metadataRegistration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@ namespace Il2CppDumper
|
|||
public ulong[] metadataUsages;
|
||||
private Il2CppGenericMethodFunctionsDefinitions[] genericMethodTable;
|
||||
public Il2CppMethodSpec[] methodSpecs;
|
||||
public Dictionary<int, ulong> genericMethoddDictionary;
|
||||
private Dictionary<int, ulong> genericMethoddDictionary;
|
||||
private bool isNew21;
|
||||
protected long maxMetadataUsages;
|
||||
private Il2CppCodeGenModule[] codeGenModules;
|
||||
public ulong[][] codeGenModuleMethodPointers;
|
||||
|
||||
public abstract dynamic MapVATR(dynamic uiAddr);
|
||||
|
||||
|
@ -50,70 +52,106 @@ namespace Il2CppDumper
|
|||
|
||||
public virtual void Init(ulong codeRegistration, ulong metadataRegistration)
|
||||
{
|
||||
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
|
||||
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
if (is32Bit)
|
||||
{
|
||||
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
|
||||
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
methodPointers = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount), x => (ulong)x);
|
||||
genericMethodPointers = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.genericMethodPointers, (long)pCodeRegistration.genericMethodPointersCount), x => (ulong)x);
|
||||
invokerPointers = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.invokerPointers, (long)pCodeRegistration.invokerPointersCount), x => (ulong)x);
|
||||
customAttributeGenerators = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount), x => (ulong)x);
|
||||
fieldOffsets = Array.ConvertAll(MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount), x => (long)x);
|
||||
//TODO 在21版本中存在两种FieldOffset,通过判断前5个数值是否为0确认是指针还是int
|
||||
//在21版本中存在两种FieldOffset,通过判断前5个数值是否为0确认是指针还是int
|
||||
isNew21 = version > 21 || (version == 21 && fieldOffsets.ToList().FindIndex(x => x > 0) == 5);
|
||||
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
|
||||
var pTypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
|
||||
types = new Il2CppType[pMetadataRegistration.typesCount];
|
||||
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
|
||||
{
|
||||
types[i] = MapVATR<Il2CppType>(ptypes[i]);
|
||||
types[i] = MapVATR<Il2CppType>(pTypes[i]);
|
||||
types[i].Init();
|
||||
typesdic.Add(ptypes[i], types[i]);
|
||||
typesdic.Add(pTypes[i], types[i]);
|
||||
}
|
||||
if (version > 16)
|
||||
metadataUsages = Array.ConvertAll(MapVATR<uint>(pMetadataRegistration.metadataUsages, maxMetadataUsages), x => (ulong)x);
|
||||
//处理泛型
|
||||
genericMethodTable = MapVATR<Il2CppGenericMethodFunctionsDefinitions>(pMetadataRegistration.genericMethodTable, pMetadataRegistration.genericMethodTableCount);
|
||||
methodSpecs = MapVATR<Il2CppMethodSpec>(pMetadataRegistration.methodSpecs, pMetadataRegistration.methodSpecsCount);
|
||||
genericMethoddDictionary = new Dictionary<int, ulong>(genericMethodTable.Length);
|
||||
foreach (var table in genericMethodTable)
|
||||
{
|
||||
var index = methodSpecs[table.genericMethodIndex].methodDefinitionIndex;
|
||||
if (!genericMethoddDictionary.ContainsKey(index))
|
||||
genericMethoddDictionary.Add(index, genericMethodPointers[table.indices.methodIndex]);
|
||||
metadataUsages = Array.ConvertAll(MapVATR<uint>(pMetadataRegistration.metadataUsages, maxMetadataUsages), x => (ulong)x);
|
||||
}
|
||||
if (version >= 24.2f)
|
||||
{
|
||||
var pCodeGenModules = MapVATR<uint>(pCodeRegistration.codeGenModules, (long)pCodeRegistration.codeGenModulesCount);
|
||||
codeGenModules = new Il2CppCodeGenModule[pCodeGenModules.Length];
|
||||
codeGenModuleMethodPointers = new ulong[pCodeGenModules.Length][];
|
||||
for (int i = 0; i < pCodeGenModules.Length; i++)
|
||||
{
|
||||
var codeGenModule = MapVATR<Il2CppCodeGenModule>(pCodeGenModules[i]);
|
||||
try
|
||||
{
|
||||
var ptrs = Array.ConvertAll(MapVATR<uint>(codeGenModule.methodPointers, (long)codeGenModule.methodPointerCount), x => (ulong)x);
|
||||
codeGenModuleMethodPointers[i] = ptrs;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//当整个DLL只有泛型函数时就有可能出现这种情况
|
||||
Console.WriteLine($"WARNING: Unable to get function pointers for {ReadStringToNull(MapVATR(codeGenModule.moduleName))}");
|
||||
codeGenModuleMethodPointers[i] = new ulong[codeGenModule.methodPointerCount];
|
||||
}
|
||||
codeGenModules[i] = codeGenModule;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
methodPointers = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount), x => (ulong)x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
|
||||
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount);
|
||||
genericMethodPointers = MapVATR<ulong>(pCodeRegistration.genericMethodPointers, (long)pCodeRegistration.genericMethodPointersCount);
|
||||
invokerPointers = MapVATR<ulong>(pCodeRegistration.invokerPointers, (long)pCodeRegistration.invokerPointersCount);
|
||||
customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
|
||||
fieldOffsets = MapVATR<long>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
|
||||
//TODO 在21版本中存在两种FieldOffset,通过判断前5个数值是否为0确认是指针还是int
|
||||
//在21版本中存在两种FieldOffset,通过判断前5个数值是否为0确认是指针还是int
|
||||
isNew21 = version > 21 || (version == 21 && fieldOffsets.ToList().FindIndex(x => x > 0) == 5);
|
||||
if (!isNew21)
|
||||
fieldOffsets = Array.ConvertAll(MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount), x => (long)x);
|
||||
var ptypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
|
||||
var pTypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
|
||||
types = new Il2CppType[pMetadataRegistration.typesCount];
|
||||
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
|
||||
{
|
||||
types[i] = MapVATR<Il2CppType>(ptypes[i]);
|
||||
types[i] = MapVATR<Il2CppType>(pTypes[i]);
|
||||
types[i].Init();
|
||||
typesdic.Add(ptypes[i], types[i]);
|
||||
typesdic.Add(pTypes[i], types[i]);
|
||||
}
|
||||
if (version > 16)
|
||||
metadataUsages = MapVATR<ulong>(pMetadataRegistration.metadataUsages, maxMetadataUsages);
|
||||
//处理泛型
|
||||
genericMethodTable = MapVATR<Il2CppGenericMethodFunctionsDefinitions>(pMetadataRegistration.genericMethodTable, pMetadataRegistration.genericMethodTableCount);
|
||||
methodSpecs = MapVATR<Il2CppMethodSpec>(pMetadataRegistration.methodSpecs, pMetadataRegistration.methodSpecsCount);
|
||||
genericMethoddDictionary = new Dictionary<int, ulong>(genericMethodTable.Length);
|
||||
foreach (var table in genericMethodTable)
|
||||
{
|
||||
var index = methodSpecs[table.genericMethodIndex].methodDefinitionIndex;
|
||||
if (!genericMethoddDictionary.ContainsKey(index))
|
||||
genericMethoddDictionary.Add(index, genericMethodPointers[table.indices.methodIndex]);
|
||||
metadataUsages = MapVATR<ulong>(pMetadataRegistration.metadataUsages, maxMetadataUsages);
|
||||
}
|
||||
if (version >= 24.2f)
|
||||
{
|
||||
var pCodeGenModules = MapVATR<ulong>(pCodeRegistration.codeGenModules, (long)pCodeRegistration.codeGenModulesCount);
|
||||
codeGenModules = new Il2CppCodeGenModule[pCodeGenModules.Length];
|
||||
codeGenModuleMethodPointers = new ulong[pCodeGenModules.Length][];
|
||||
for (int i = 0; i < pCodeGenModules.Length; i++)
|
||||
{
|
||||
var codeGenModule = MapVATR<Il2CppCodeGenModule>(pCodeGenModules[i]);
|
||||
var ptrs = MapVATR<ulong>(codeGenModule.methodPointers, (long)codeGenModule.methodPointerCount);
|
||||
codeGenModules[i] = codeGenModule;
|
||||
codeGenModuleMethodPointers[i] = ptrs;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount);
|
||||
}
|
||||
}
|
||||
//处理泛型
|
||||
genericMethodTable = MapVATR<Il2CppGenericMethodFunctionsDefinitions>(pMetadataRegistration.genericMethodTable, pMetadataRegistration.genericMethodTableCount);
|
||||
methodSpecs = MapVATR<Il2CppMethodSpec>(pMetadataRegistration.methodSpecs, pMetadataRegistration.methodSpecsCount);
|
||||
genericMethoddDictionary = new Dictionary<int, ulong>(genericMethodTable.Length);
|
||||
foreach (var table in genericMethodTable)
|
||||
{
|
||||
var index = methodSpecs[table.genericMethodIndex].methodDefinitionIndex;
|
||||
if (!genericMethoddDictionary.ContainsKey(index))
|
||||
{
|
||||
genericMethoddDictionary.Add(index, genericMethodPointers[table.indices.methodIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,5 +201,31 @@ namespace Il2CppDumper
|
|||
return Array.ConvertAll(MapVATR<uint>(pointer, count), x => (ulong)x);
|
||||
return MapVATR<ulong>(pointer, count);
|
||||
}
|
||||
|
||||
public ulong GetMethodPointer(int methodIndex, int methodDefinitionIndex, int imageIndex, uint methodToken)
|
||||
{
|
||||
if (version >= 24.2f)
|
||||
{
|
||||
if (genericMethoddDictionary.TryGetValue(methodDefinitionIndex, out var methodPointer))
|
||||
{
|
||||
return methodPointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ptrs = codeGenModuleMethodPointers[imageIndex];
|
||||
var methodPointerIndex = methodToken & 0x00FFFFFFu;
|
||||
return ptrs[methodPointerIndex - 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodIndex >= 0)
|
||||
{
|
||||
return methodPointers[methodIndex];
|
||||
}
|
||||
genericMethoddDictionary.TryGetValue(methodDefinitionIndex, out var methodPointer);
|
||||
return methodPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BoyerMooreHorspool.cs" />
|
||||
<Compile Include="Lz4DecoderStream.cs" />
|
||||
<Compile Include="NSO.cs" />
|
||||
<Compile Include="NSOClass.cs" />
|
||||
|
|
|
@ -132,7 +132,9 @@ namespace Il2CppDumper
|
|||
public int parentIndex;
|
||||
public int elementTypeIndex; // we can probably remove this one. Only used for enums
|
||||
|
||||
[Version(Max = 24.1f)]
|
||||
public int rgctxStartIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int rgctxCount;
|
||||
|
||||
public int genericContainerIndex;
|
||||
|
@ -188,10 +190,15 @@ namespace Il2CppDumper
|
|||
[Version(Max = 24)]
|
||||
public int customAttributeIndex;
|
||||
public int genericContainerIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int methodIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int invokerIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int delegateWrapperIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int rgctxStartIndex;
|
||||
[Version(Max = 24.1f)]
|
||||
public int rgctxCount;
|
||||
public uint token;
|
||||
public ushort flags;
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace Il2CppDumper
|
|||
private static Il2Cpp il2cpp;
|
||||
private static Config config = new JavaScriptSerializer().Deserialize<Config>(File.ReadAllText(Application.StartupPath + Path.DirectorySeparatorChar + @"config.json"));
|
||||
private static Dictionary<Il2CppMethodDefinition, string> methodModifiers = new Dictionary<Il2CppMethodDefinition, string>();
|
||||
private static Dictionary<Il2CppTypeDefinition, int> typeDefImageIndices = new Dictionary<Il2CppTypeDefinition, int>();
|
||||
|
||||
static void ShowHelp(string programName)
|
||||
{
|
||||
|
@ -258,14 +259,16 @@ namespace Il2CppDumper
|
|||
writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n");
|
||||
}
|
||||
//dump type
|
||||
foreach (var imageDef in metadata.imageDefs)
|
||||
for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var imageDef = metadata.imageDefs[imageIndex];
|
||||
var typeEnd = imageDef.typeStart + imageDef.typeCount;
|
||||
for (int idx = imageDef.typeStart; idx < typeEnd; idx++)
|
||||
{
|
||||
var typeDef = metadata.typeDefs[idx];
|
||||
typeDefImageIndices.Add(typeDef, imageIndex);
|
||||
var isStruct = false;
|
||||
var isEnum = false;
|
||||
var extends = new List<string>();
|
||||
|
@ -519,15 +522,7 @@ namespace Il2CppDumper
|
|||
writer.Write(string.Join(", ", parameterStrs));
|
||||
if (config.DumpMethodOffset)
|
||||
{
|
||||
ulong methodPointer;
|
||||
if (methodDef.methodIndex >= 0)
|
||||
{
|
||||
methodPointer = il2cpp.methodPointers[methodDef.methodIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
il2cpp.genericMethoddDictionary.TryGetValue(i, out methodPointer);
|
||||
}
|
||||
var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token);
|
||||
if (methodPointer > 0)
|
||||
{
|
||||
writer.Write("); // RVA: 0x{0:X} Offset: 0x{1:X}\n", methodPointer, il2cpp.MapVATR(methodPointer));
|
||||
|
@ -581,19 +576,13 @@ namespace Il2CppDumper
|
|||
foreach (var i in metadata.metadataUsageDic[3]) //kIl2CppMetadataUsageMethodDef
|
||||
{
|
||||
var methodDef = metadata.methodDefs[i.Key];
|
||||
var typeName = GetTypeName(metadata.typeDefs[methodDef.declaringType]);
|
||||
var typeDef = metadata.typeDefs[methodDef.declaringType];
|
||||
var typeName = GetTypeName(typeDef);
|
||||
var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
var legalName = "Method$" + HandleSpecialCharacters(methodName);
|
||||
scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{legalName}')");
|
||||
ulong methodPointer;
|
||||
if (methodDef.methodIndex >= 0)
|
||||
{
|
||||
methodPointer = il2cpp.methodPointers[methodDef.methodIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
il2cpp.genericMethoddDictionary.TryGetValue((int)i.Key, out methodPointer);
|
||||
}
|
||||
var imageIndex = typeDefImageIndices[typeDef];
|
||||
var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, (int)i.Key, imageIndex, methodDef.token);
|
||||
scriptwriter.WriteLine($"idc.MakeComm(0x{il2cpp.metadataUsages[i.Key]:X}, r'0x{methodPointer:X}')");
|
||||
}
|
||||
foreach (var i in metadata.metadataUsageDic[4]) //kIl2CppMetadataUsageFieldInfo
|
||||
|
@ -615,19 +604,13 @@ namespace Il2CppDumper
|
|||
{
|
||||
var methodSpec = il2cpp.methodSpecs[i.Value];
|
||||
var methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex];
|
||||
var typeName = GetTypeName(metadata.typeDefs[methodDef.declaringType]);
|
||||
var typeDef = metadata.typeDefs[methodDef.declaringType];
|
||||
var typeName = GetTypeName(typeDef);
|
||||
var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()";
|
||||
var legalName = "Method$" + HandleSpecialCharacters(methodName);
|
||||
scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{legalName}')");
|
||||
ulong methodPointer;
|
||||
if (methodDef.methodIndex >= 0)
|
||||
{
|
||||
methodPointer = il2cpp.methodPointers[methodDef.methodIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
il2cpp.genericMethoddDictionary.TryGetValue(methodSpec.methodDefinitionIndex, out methodPointer);
|
||||
}
|
||||
var imageIndex = typeDefImageIndices[typeDef];
|
||||
var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token);
|
||||
scriptwriter.WriteLine($"idc.MakeComm(0x{il2cpp.metadataUsages[i.Key]:X}, r'0x{methodPointer:X}')");
|
||||
}
|
||||
scriptwriter.WriteLine("print('Set MetadataUsage done')");
|
||||
|
@ -635,7 +618,19 @@ namespace Il2CppDumper
|
|||
//Script - MakeFunction
|
||||
if (config.MakeFunction)
|
||||
{
|
||||
var orderedPointers = il2cpp.methodPointers.ToList();
|
||||
List<ulong> orderedPointers;
|
||||
if (il2cpp.version >= 24.2f)
|
||||
{
|
||||
orderedPointers = new List<ulong>();
|
||||
foreach (var methodPointers in il2cpp.codeGenModuleMethodPointers)
|
||||
{
|
||||
orderedPointers.AddRange(methodPointers);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orderedPointers = il2cpp.methodPointers.ToList();
|
||||
}
|
||||
orderedPointers.AddRange(il2cpp.genericMethodPointers.Where(x => x > 0));
|
||||
orderedPointers.AddRange(il2cpp.invokerPointers);
|
||||
orderedPointers.AddRange(il2cpp.customAttributeGenerators);
|
||||
|
|
Loading…
Add table
Reference in a new issue