private ulong FindCodeRegistrationOld() { foreach (var section in data) { il2Cpp.Position = section.offset; while (il2Cpp.Position < section.offsetEnd) { var addr = il2Cpp.Position; if (il2Cpp.ReadIntPtr() == methodCount) { try { var pointer = il2Cpp.MapVATR(il2Cpp.ReadUIntPtr()); if (CheckPointerRangeDataRa(pointer)) { var pointers = il2Cpp.ReadClassArray <ulong>(pointer, methodCount); if (CheckPointerRangeExecVa(pointers)) { return(addr - section.offset + section.address); } } } catch { // ignored } } il2Cpp.Position = addr + il2Cpp.PointerSize; } } return(0ul); }
public ulong FindCodeRegistration() { foreach (var section in search) { il2Cpp.Position = section.start; while ((ulong)il2Cpp.Position < section.end) { var addr = il2Cpp.Position; if (il2Cpp.ReadUInt32() == methodCount) { try { var pointer = il2Cpp.MapVATR(il2Cpp.ReadUInt32()); if (CheckPointerRangeFirst(pointer)) { var sign = il2Cpp.Position; var pointers = il2Cpp.ReadClassArray <uint>(pointer, methodCount); if (CheckPointerRangeSecond(pointers)) { return((ulong)addr - section.start + section.address); //VirtualAddress } il2Cpp.Position = sign; } } catch { // ignored } } } } return(0ul); }
private static string GetTypeName(Il2CppType pType) { string ret; switch (pType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: { var klass = metadata.typeDefs[pType.data.klassIndex]; ret = metadata.GetStringFromIndex(klass.nameIndex); break; } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { var generic_class = il2cpp.MapVATR <Il2CppGenericClass>(pType.data.generic_class); var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex]; ret = metadata.GetStringFromIndex(pMainDef.nameIndex); var typeNames = new List <string>(); var pInst = il2cpp.MapVATR <Il2CppGenericInst>(generic_class.context.class_inst); var pointers = il2cpp.GetPointers(pInst.type_argv, (long)pInst.type_argc); for (uint i = 0; i < pInst.type_argc; ++i) { var pOriType = il2cpp.GetIl2CppType(pointers[i]); typeNames.Add(GetTypeName(pOriType)); } ret += $"<{string.Join(", ", typeNames)}>"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2cpp.MapVATR <Il2CppArrayType>(pType.data.array); var type = il2cpp.GetIl2CppType(arrayType.etype); ret = $"{GetTypeName(type)}[{new string(',', arrayType.rank - 1)}]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var type = il2cpp.GetIl2CppType(pType.data.type); ret = $"{GetTypeName(type)}[]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var type = il2cpp.GetIl2CppType(pType.data.type); ret = $"{GetTypeName(type)}*"; break; } default: ret = TypeString[(int)pType.type]; break; } return(ret); }
private static string GetTypeName(Il2CppType pType) { string ret; if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { var klass = metadata.typeDefs[pType.data.klassIndex]; ret = metadata.GetString(klass.nameIndex); } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { var generic_class = il2cpp.MapVATR <Il2CppGenericClass>(pType.data.generic_class); var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex]; ret = metadata.GetString(pMainDef.nameIndex); var typeNames = new List <string>(); var pInst = il2cpp.MapVATR <Il2CppGenericInst>(generic_class.context.class_inst); var pointers = il2cpp.GetPointers(pInst.type_argv, (long)pInst.type_argc); for (uint i = 0; i < pInst.type_argc; ++i) { var pOriType = il2cpp.GetIl2CppType(pointers[i]); typeNames.Add(GetTypeName(pOriType)); } ret += $"<{string.Join(", ", typeNames)}>"; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY) { var arrayType = il2cpp.MapVATR <Il2CppArrayType>(pType.data.array); var type = il2cpp.GetIl2CppType(arrayType.etype); ret = $"{GetTypeName(type)}[]"; } else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY) { var type = il2cpp.GetIl2CppType(pType.data.type); ret = $"{GetTypeName(type)}[]"; } else { if ((int)pType.type >= szTypeString.Length) { ret = "unknow"; } else { ret = szTypeString[(int)pType.type]; } } return(ret); }
public Il2CppExecutor(Metadata metadata, Il2Cpp il2Cpp) { this.metadata = metadata; this.il2Cpp = il2Cpp; this.TypeDefToName = new UniqueTypeDefNameMap(new WeakReference <Il2CppExecutor>(this)); if (il2Cpp.Version >= 27) { customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)]; foreach (var imageDef in metadata.imageDefs) { var imageDefName = metadata.GetStringFromIndex(imageDef.nameIndex); var codeGenModule = il2Cpp.codeGenModules[imageDefName]; var pointers = il2Cpp.ReadClassArray <ulong>(il2Cpp.MapVATR(codeGenModule.customAttributeCacheGenerator), imageDef.customAttributeCount); pointers.CopyTo(customAttributeGenerators, imageDef.customAttributeStart); } } else { customAttributeGenerators = il2Cpp.customAttributeGenerators; } for (int index = 0; index < metadata.typeDefs.Length; ++index) { TypeDefToIndex[metadata.typeDefs[index]] = index; } for (long index = 0; index < il2Cpp.types.Length; ++index) { TypeToIndex[il2Cpp.types[index]] = index; } }
// requires TypeMetadata private void IndexGenerics() { // build type -> generic instance lookup foreach (var il2CppType in il2Cpp.types.Where(x => x.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)) { var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); var baseTypeDef = executor.GetGenericClassTypeDefinition(genericClass); if (baseTypeDef == null) { continue; } TypeDefinitionMetadata baseTypeMetadata = TypeMetadata[baseTypeDef]; var typeBaseName = TypeMetadata[baseTypeDef].UniqueName; var typeToReplaceName = executor.GetTypeDefName(baseTypeDef, true, true); var typeReplaceName = executor.GetTypeName(il2CppType, true, false); var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName); genericClassList.Add(il2CppType.data.generic_class); lookupGenericType[typeStructName] = il2CppType; lookupGenericClassName[il2CppType.data.generic_class] = typeStructName; } }
public Il2CppExecutor(Metadata metadata, Il2Cpp il2Cpp) { this.metadata = metadata; this.il2Cpp = il2Cpp; if (il2Cpp.Version >= 27) { customAttributeGenerators = new ulong[metadata.imageDefs.Sum(x => x.customAttributeCount)]; foreach (var imageDef in metadata.imageDefs) { var imageDefName = metadata.GetStringFromIndex(imageDef.nameIndex); var codeGenModule = il2Cpp.codeGenModules[imageDefName]; var pointers = il2Cpp.ReadClassArray <ulong>(il2Cpp.MapVATR(codeGenModule.customAttributeCacheGenerator), imageDef.customAttributeCount); pointers.CopyTo(customAttributeGenerators, imageDef.customAttributeStart); } } else { customAttributeGenerators = il2Cpp.customAttributeGenerators; } }
public DummyAssemblyGenerator(Metadata metadata, Il2Cpp il2Cpp) { this.metadata = metadata; this.il2Cpp = il2Cpp; //Il2CppDummyDll var il2CppDummyDll = Il2CppDummyDll.Create(); Assemblies.Add(il2CppDummyDll); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods[0]; var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods[0]; attributeAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AttributeAttribute").Methods[0]; var metadataOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "MetadataOffsetAttribute").Methods[0]; stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; 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>(); //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var assemblyName = new AssemblyNameDefinition(imageName.Replace(".dll", ""), new Version("3.7.1.6")); var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, imageName, moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); TypeDefinition typeDefinition; if (typeDef.declaringTypeIndex != -1)//nested types { typeDefinition = typeDefinitionDic[index]; } else { typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); moduleDefinition.Types.Add(typeDefinition); typeDefinitionDic.Add(index, typeDefinition); } //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = new TypeDefinition(metadata.GetStringFromIndex(nestedTypeDef.namespaceIndex), metadata.GetStringFromIndex(nestedTypeDef.nameIndex), (TypeAttributes)nestedTypeDef.flags); typeDefinition.NestedTypes.Add(nestedTypeDefinition); typeDefinitionDic.Add(nestedIndex, nestedTypeDefinition); } } } //先单独处理,因为不知道会不会有问题 for (var index = 0; index < metadata.typeDefs.Length; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //parent if (typeDef.parentIndex >= 0) { var parentType = il2Cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(new InterfaceImplementation(interfaceTypeRef)); } } //处理field, method, property等等 for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { 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 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); fieldDefinitionDic.Add(i, fieldDefinition); //fieldDefault if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1) { if (TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value)) { fieldDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } //fieldOffset if (!fieldDefinition.IsLiteral) { var fieldOffset = il2Cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i, typeDefinition.IsValueType, fieldDefinition.IsStatic); if (fieldOffset >= 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(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 methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.ImportReference(typeof(void))); methodDefinition.ImplAttributes = (MethodImplAttributes)methodDef.iflags; typeDefinition.Methods.Add(methodDefinition); var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = GetTypeReferenceWithByRef(methodDefinition, methodReturnType); methodDefinition.ReturnType = returnType; if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); if (returnType.FullName == "System.Void") { ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else if (returnType.IsValueType) { var variable = new VariableDefinition(returnType); methodDefinition.Body.Variables.Add(variable); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloca_S, variable)); ilprocessor.Append(ilprocessor.Create(OpCodes.Initobj, returnType)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else { ilprocessor.Append(ilprocessor.Create(OpCodes.Ldnull)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } } 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 = GetTypeReferenceWithByRef(methodDefinition, parameterType); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); parameterDefinitionDic.Add(methodDef.parameterStart + j, parameterDefinition); //ParameterDefault if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) { if (TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value)) { parameterDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); parameterDefinition.CustomAttributes.Add(customAttribute); } } } //补充泛型参数 if (methodDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; if (genericContainer.type_argc > methodDefinition.GenericParameters.Count) { for (int j = 0; j < genericContainer.type_argc; j++) { var genericParameterIndex = genericContainer.genericParameterStart + j; if (!genericParameterDic.TryGetValue(genericParameterIndex, out var genericParameter)) { CreateGenericParameter(genericParameterIndex, methodDefinition); } else { if (!methodDefinition.GenericParameters.Contains(genericParameter)) { methodDefinition.GenericParameters.Add(genericParameter); } } } } } //methodAddress var methodPointer = il2Cpp.GetMethodPointer(methodDef, imageIndex); if (methodPointer > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(addressAttribute)); var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}")); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}")); var va = new CustomAttributeNamedArgument("VA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}")); customAttribute.Fields.Add(rva); customAttribute.Fields.Add(offset); customAttribute.Fields.Add(va); if (methodDef.slot != ushort.MaxValue) { var slot = new CustomAttributeNamedArgument("Slot", new CustomAttributeArgument(stringType, methodDef.slot.ToString())); customAttribute.Fields.Add(slot); } 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); propertyDefinitionDic.Add(i, 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); eventDefinitionDic.Add(i, eventDefinition); } //补充泛型参数 if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; if (genericContainer.type_argc > typeDefinition.GenericParameters.Count) { for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; if (!genericParameterDic.TryGetValue(genericParameterIndex, out var genericParameter)) { CreateGenericParameter(genericParameterIndex, typeDefinition); } else { if (!typeDefinition.GenericParameters.Contains(genericParameter)) { typeDefinition.GenericParameters.Add(genericParameter); } } } } } } } //第三遍,添加CustomAttribute if (il2Cpp.Version > 20) { PrepareCustomAttribute(); foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //typeAttribute CreateCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token, typeDefinition.Module, typeDefinition.CustomAttributes); //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldDefinition = fieldDefinitionDic[i]; //fieldAttribute CreateCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, typeDefinition.Module, fieldDefinition.CustomAttributes); } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodDefinition = methodDefinitionDic[i]; //methodAttribute CreateCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, typeDefinition.Module, methodDefinition.CustomAttributes); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterDefinition = parameterDefinitionDic[methodDef.parameterStart + j]; //parameterAttribute CreateCustomAttribute(imageDef, parameterDef.customAttributeIndex, parameterDef.token, typeDefinition.Module, parameterDefinition.CustomAttributes); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyDefinition = propertyDefinitionDic[i]; //propertyAttribute CreateCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, typeDefinition.Module, propertyDefinition.CustomAttributes); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventDefinition = eventDefinitionDic[i]; //eventAttribute CreateCustomAttribute(imageDef, eventDef.customAttributeIndex, eventDef.token, typeDefinition.Module, eventDefinition.CustomAttributes); } } } } }
private static void Dump() { var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create), new UTF8Encoding(false)); Console.WriteLine("Dumping..."); //Script var scriptwriter = new StreamWriter(new FileStream("script.py", FileMode.Create), new UTF8Encoding(false)); scriptwriter.WriteLine(Resource1.ida); //dump image for (var imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } //dump type foreach (var imageDef in metadata.imageDefs) { try { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int idx = imageDef.typeStart; idx < typeEnd; idx++) { var typeDef = metadata.typeDefs[idx]; var isStruct = false; var isEnum = false; var extends = new List <string>(); if (typeDef.parentIndex >= 0) { var parent = il2cpp.types[typeDef.parentIndex]; var parentName = GetTypeName(parent); if (parentName == "ValueType") { isStruct = true; } else if (parentName == "Enum") { isEnum = true; } else if (parentName != "object") { extends.Add(parentName); } } //implementedInterfaces if (typeDef.interfaces_count > 0) { for (int i = 0; i < typeDef.interfaces_count; i++) { var @interface = il2cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; extends.Add(GetTypeName(@interface)); } } writer.Write($"\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\n"); writer.Write(GetCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token)); if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; switch (visibility) { case TYPE_ATTRIBUTE_PUBLIC: case TYPE_ATTRIBUTE_NESTED_PUBLIC: writer.Write("public "); break; case TYPE_ATTRIBUTE_NOT_PUBLIC: case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: writer.Write("internal "); break; case TYPE_ATTRIBUTE_NESTED_PRIVATE: writer.Write("private "); break; case TYPE_ATTRIBUTE_NESTED_FAMILY: writer.Write("protected "); break; case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("static "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if (!isStruct && !isEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else if (isEnum) { writer.Write("enum "); } else { writer.Write("class "); } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); writer.Write($"{typeName}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } if (config.DumpTypeDefIndex) { writer.Write($" // TypeDefIndex: {idx}\n{{"); } else { writer.Write("\n{"); } //dump field if (config.DumpField && typeDef.field_count > 0) { writer.Write("\n\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { //dump_field(i, idx, i - typeDef.fieldStart); var fieldDef = metadata.fieldDefs[i]; var fieldType = il2cpp.types[fieldDef.typeIndex]; var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i); writer.Write(GetCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, "\t")); writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(fieldType)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); if (fieldDefault != null && fieldDefault.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(fieldDefault.dataIndex); if (pointer > 0) { var pTypeToUse = il2cpp.types[fieldDefault.typeIndex]; metadata.Position = pointer; object multi = null; switch (pTypeToUse.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: multi = metadata.ReadBoolean(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U1: multi = metadata.ReadByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I1: multi = metadata.ReadSByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: multi = BitConverter.ToChar(metadata.ReadBytes(2), 0); break; case Il2CppTypeEnum.IL2CPP_TYPE_U2: multi = metadata.ReadUInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I2: multi = metadata.ReadInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U4: multi = metadata.ReadUInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I4: multi = metadata.ReadInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U8: multi = metadata.ReadUInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I8: multi = metadata.ReadInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R4: multi = metadata.ReadSingle(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R8: multi = metadata.ReadDouble(); break; case Il2CppTypeEnum.IL2CPP_TYPE_STRING: var uiLen = metadata.ReadInt32(); multi = Encoding.UTF8.GetString(metadata.ReadBytes(uiLen)); break; } if (multi is string str) { writer.Write($" = \"{ToEscapedString(str)}\""); } else if (multi is char c) { var v = (int)c; writer.Write($" = '\\x{v:x}'"); } else if (multi != null) { writer.Write($" = {multi}"); } } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } else { writer.Write(";\n"); } } } //dump property if (config.DumpProperty && typeDef.property_count > 0) { writer.Write("\n\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; writer.Write(GetCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, "\t")); writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2cpp.types[parameterDef.typeIndex]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } } //dump method if (config.DumpMethod && typeDef.method_count > 0) { writer.Write("\n\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t")); writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); writer.Write($"{GetTypeName(methodReturnType)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2cpp.types[parameterDef.typeIndex]; var parameterTypeName = GetTypeName(parameterType); if ((parameterType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { parameterStr += "optional "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "out "; } parameterStr += $"{parameterTypeName} {parameterName}"; parameterStrs.Add(parameterStr); } 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); } if (methodPointer > 0) { writer.Write("); // RVA: 0x{0:X} Offset: 0x{1:X}\n", methodPointer, il2cpp.MapVATR(methodPointer)); //Script - method var name = ToEscapedString(HandleSpecialCharacters(typeName + "$$" + methodName)); scriptwriter.WriteLine($"SetMethod(0x{methodPointer:X}, '{name}')"); } else { writer.Write("); // -1\n"); } } else { writer.Write("); \n"); } } } writer.Write("}\n"); } } catch (Exception e) { Console.WriteLine("ERROR: Some errors in dumping"); writer.Write("/*"); writer.Write(e); writer.Write("*/\n}\n"); } } //Script - stringLiteral scriptwriter.WriteLine("print('Make method name done')"); scriptwriter.WriteLine("print('Setting String...')"); if (il2cpp.version > 16) { foreach (var i in metadata.stringLiteralsdic) { scriptwriter.WriteLine($"SetString(0x{il2cpp.metadataUsages[i.Key]:X}, r'{ToEscapedString(i.Value)}')"); } } scriptwriter.WriteLine("print('Set string done')"); //Script - MakeFunction if (config.MakeFunction) { var orderedPointers = il2cpp.methodPointers.ToList(); orderedPointers.AddRange(il2cpp.genericMethodPointers.Where(x => x > 0)); orderedPointers.AddRange(il2cpp.invokerPointers); orderedPointers.AddRange(il2cpp.customAttributeGenerators); orderedPointers = orderedPointers.OrderBy(x => x).ToList(); scriptwriter.WriteLine("print('Making function...')"); for (int i = 0; i < orderedPointers.Count - 1; i++) { scriptwriter.WriteLine($"MakeFunction(0x{orderedPointers[i]:X}, 0x{orderedPointers[i + 1]:X})"); } scriptwriter.WriteLine("print('Make function done, please wait for IDA to complete the analysis')"); } scriptwriter.WriteLine("print('Script finish !')"); //writer close writer.Close(); scriptwriter.Close(); Console.WriteLine("Done !"); //DummyDll if (config.DummyDll) { Console.WriteLine("Create DummyDll..."); if (Directory.Exists("DummyDll")) { Directory.Delete("DummyDll", true); } Directory.CreateDirectory("DummyDll"); Directory.SetCurrentDirectory("DummyDll"); File.WriteAllBytes("Il2CppDummyDll.dll", Resource1.Il2CppDummyDll); var dummy = new DummyAssemblyCreator(metadata, il2cpp); foreach (var assembly in dummy.Assemblies) { var stream = new MemoryStream(); assembly.Write(stream); File.WriteAllBytes(assembly.MainModule.Name, stream.ToArray()); } Console.WriteLine("Done !"); } }
static void Main(string[] args) { config = File.Exists("config.json") ? new JavaScriptSerializer().Deserialize <Config>(File.ReadAllText("config.json")) : new Config(); var ofd = new OpenFileDialog(); ofd.Filter = "Il2Cpp binary file|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { var il2cppfile = File.ReadAllBytes(ofd.FileName); ofd.Filter = "global-metadata|global-metadata.dat"; if (ofd.ShowDialog() == DialogResult.OK) { try { Console.WriteLine("Initializing metadata..."); metadata = new Metadata(new MemoryStream(File.ReadAllBytes(ofd.FileName))); Console.Clear(); //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppfile, 0); var isElf = false; var isPE = false; var is64bit = false; switch (il2cppMagic) { default: throw new Exception("ERROR: il2cpp file not supported."); case 0x905A4D: //PE isPE = true; break; case 0x464c457f: //ELF isElf = true; if (il2cppfile[4] == 2) { goto case 0xFEEDFACF; //ELF64 } break; case 0xCAFEBABE: //FAT header case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppfile)); Console.Write("Select Platform: "); for (var i = 0; i < machofat.fats.Length; i++) { var fat = machofat.fats[i]; Console.Write(fat.magic == 0xFEEDFACF ? $"{i + 1}.64bit " : $"{i + 1}.32bit "); } Console.WriteLine(); var key = Console.ReadKey(true); var index = int.Parse(key.KeyChar.ToString()) - 1; var magic = machofat.fats[index % 2].magic; il2cppfile = machofat.GetMacho(index % 2); if (magic == 0xFEEDFACF) // 64-bit mach object file { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64-bit mach object file is64bit = true; break; case 0xFEEDFACE: // 32-bit mach object file break; } Console.WriteLine("Select Mode: 1.Manual 2.Auto 3.Auto(Advanced) 4.Auto(Plus) 5.Auto(Symbol)"); var modeKey = Console.ReadKey(true); var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.version; Console.WriteLine("Initializing il2cpp file..."); if (isPE) { il2cpp = new PE(new MemoryStream(il2cppfile), version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2cpp = new Elf64(new MemoryStream(il2cppfile), version, metadata.maxMetadataUsages); } else { il2cpp = new Elf(new MemoryStream(il2cppfile), version, metadata.maxMetadataUsages); } } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppfile), version, metadata.maxMetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppfile), version, metadata.maxMetadataUsages); } try { bool flag; switch (modeKey.KeyChar) { case '1': //Manual Console.Write("Input CodeRegistration: "); var codeRegistration = Convert.ToUInt64(Console.ReadLine(), 16); Console.Write("Input MetadataRegistration: "); var metadataRegistration = Convert.ToUInt64(Console.ReadLine(), 16); il2cpp.Init(codeRegistration, metadataRegistration); flag = true; break; case '2': //Auto flag = il2cpp.Search(); break; case '3': //Auto(Advanced) flag = il2cpp.AdvancedSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0)); break; case '4': //Auto(Plus) flag = il2cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); break; case '5': //Auto(Symbol) flag = il2cpp.SymbolSearch(); break; default: return; } if (!flag) { throw new Exception(); } } catch { throw new Exception("ERROR: Can't use this mode to process file, try another mode."); } var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create), new UTF8Encoding(false)); Console.WriteLine("Dumping..."); //Script var scriptwriter = new StreamWriter(new FileStream("script.py", FileMode.Create), new UTF8Encoding(false)); scriptwriter.WriteLine(Resource1.ida); //dump image; for (var imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } //dump type; for (var idx = 0; idx < metadata.uiNumTypes; ++idx) { try { var typeDef = metadata.typeDefs[idx]; var isStruct = false; var isEnum = false; var extends = new List <string>(); if (typeDef.parentIndex >= 0) { var parent = il2cpp.types[typeDef.parentIndex]; var parentName = GetTypeName(parent); if (parentName == "ValueType") { isStruct = true; } else if (parentName == "Enum") { isEnum = true; } else if (parentName != "object") { extends.Add(parentName); } } //implementedInterfaces if (typeDef.interfaces_count > 0) { for (int i = 0; i < typeDef.interfaces_count; i++) { var @interface = il2cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; extends.Add(GetTypeName(@interface)); } } writer.Write($"\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\n"); writer.Write(GetCustomAttribute(typeDef.customAttributeIndex)); if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; switch (visibility) { case TYPE_ATTRIBUTE_PUBLIC: case TYPE_ATTRIBUTE_NESTED_PUBLIC: writer.Write("public "); break; case TYPE_ATTRIBUTE_NOT_PUBLIC: case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: writer.Write("internal "); break; case TYPE_ATTRIBUTE_NESTED_PRIVATE: writer.Write("private "); break; case TYPE_ATTRIBUTE_NESTED_FAMILY: writer.Write("protected "); break; case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("static "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if (!isStruct && !isEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else if (isEnum) { writer.Write("enum "); } else { writer.Write("class "); } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); writer.Write($"{typeName}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } if (config.DumpTypeDefIndex) { writer.Write($" // TypeDefIndex: {idx}\n{{\n"); } else { writer.Write("\n{\n"); } //dump field if (config.DumpField && typeDef.field_count > 0) { writer.Write("\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { //dump_field(i, idx, i - typeDef.fieldStart); var fieldDef = metadata.fieldDefs[i]; var fieldType = il2cpp.types[fieldDef.typeIndex]; var fieldDefault = metadata.GetFieldDefaultValueFromIndex(i); writer.Write(GetCustomAttribute(fieldDef.customAttributeIndex, "\t")); writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(fieldType)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); if (fieldDefault != null && fieldDefault.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(fieldDefault.dataIndex); if (pointer > 0) { var pTypeToUse = il2cpp.types[fieldDefault.typeIndex]; metadata.Position = pointer; object multi = null; switch (pTypeToUse.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: multi = metadata.ReadBoolean(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U1: multi = metadata.ReadByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I1: multi = metadata.ReadSByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: multi = BitConverter.ToChar(metadata.ReadBytes(2), 0); break; case Il2CppTypeEnum.IL2CPP_TYPE_U2: multi = metadata.ReadUInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I2: multi = metadata.ReadInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U4: multi = metadata.ReadUInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I4: multi = metadata.ReadInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U8: multi = metadata.ReadUInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I8: multi = metadata.ReadInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R4: multi = metadata.ReadSingle(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R8: multi = metadata.ReadDouble(); break; case Il2CppTypeEnum.IL2CPP_TYPE_STRING: var uiLen = metadata.ReadInt32(); multi = Encoding.UTF8.GetString(metadata.ReadBytes(uiLen)); break; } if (multi is string str) { writer.Write($" = \"{ToEscapedString(str)}\""); } else if (multi is char c) { var v = (int)c; writer.Write($" = '\\x{v:x}'"); } else if (multi != null) { writer.Write($" = {multi}"); } } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } else { writer.Write(";\n"); } } writer.Write("\n"); } //dump property if (config.DumpProperty && typeDef.property_count > 0) { writer.Write("\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; writer.Write(GetCustomAttribute(propertyDef.customAttributeIndex, "\t")); writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2cpp.types[parameterDef.typeIndex]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } writer.Write("\n"); } //dump method if (config.DumpMethod && typeDef.method_count > 0) { writer.Write("\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; writer.Write(GetCustomAttribute(methodDef.customAttributeIndex, "\t")); writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); writer.Write($"{GetTypeName(methodReturnType)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2cpp.types[parameterDef.typeIndex]; var parameterTypeName = GetTypeName(parameterType); if ((parameterType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { parameterStr += "optional "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "out "; } parameterStr += $"{parameterTypeName} {parameterName}"; parameterStrs.Add(parameterStr); } 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); } if (methodPointer > 0) { writer.Write("); // RVA: 0x{0:X} Offset: 0x{1:X}\n", methodPointer, il2cpp.MapVATR(methodPointer)); //Script - method var name = ToEscapedString(HandleSpecialCharacters(typeName + "$$" + methodName)); scriptwriter.WriteLine($"SetMethod(0x{methodPointer:X}, '{name}')"); } else { writer.Write("); // -1\n"); } } else { writer.Write("); \n"); } } } writer.Write("}\n"); } catch (Exception e) { Console.WriteLine("ERROR: Some errors in dumping"); writer.Write("/*"); writer.Write($"{e.Message}\n{e.StackTrace}\n"); writer.Write("*/\n}\n"); } } //Script - stringLiteral scriptwriter.WriteLine("print('Make method name done')"); scriptwriter.WriteLine("print('Setting String...')"); if (il2cpp.version > 16) { foreach (var i in metadata.stringLiteralsdic) { scriptwriter.WriteLine($"SetString(0x{il2cpp.metadataUsages[i.Key]:X}, r'{ToEscapedString(i.Value)}')"); } } scriptwriter.WriteLine("print('Set string done')"); //Script - MakeFunction if (config.MakeFunction) { var orderedPointers = il2cpp.methodPointers.ToList(); orderedPointers.AddRange(il2cpp.genericMethodPointers.Where(x => x > 0)); orderedPointers.AddRange(il2cpp.invokerPointers); orderedPointers.AddRange(il2cpp.customAttributeGenerators); orderedPointers = orderedPointers.OrderBy(x => x).ToList(); scriptwriter.WriteLine("print('Making function...')"); for (int i = 0; i < orderedPointers.Count - 1; i++) { scriptwriter.WriteLine($"MakeFunction(0x{orderedPointers[i]:X}, 0x{orderedPointers[i + 1]:X})"); } scriptwriter.WriteLine("print('Make function done, please wait for IDA to complete the analysis')"); } scriptwriter.WriteLine("print('Script finish !')"); //writer close writer.Close(); scriptwriter.Close(); Console.WriteLine("Done !"); //DummyDll if (config.DummyDll) { Console.WriteLine("Create DummyDll..."); if (Directory.Exists("DummyDll")) { Directory.Delete("DummyDll", true); } Directory.CreateDirectory("DummyDll"); Directory.SetCurrentDirectory("DummyDll"); File.WriteAllBytes("Il2CppDummyDll.dll", Resource1.Il2CppDummyDll); var dummy = new DummyAssemblyCreator(metadata, il2cpp); foreach (var assembly in dummy.Assemblies) { var stream = new MemoryStream(); assembly.Write(stream); File.WriteAllBytes(assembly.MainModule.Name, stream.ToArray()); } Console.WriteLine("Done !"); } } catch (Exception e) { Console.WriteLine(e); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(true); } } }
public void Decompile(StreamWriter writer, Config config) { //dump image for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } //dump type 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]; var isStruct = false; var isEnum = false; var extends = new List <string>(); if (typeDef.parentIndex >= 0) { var parent = il2Cpp.types[typeDef.parentIndex]; var parentName = GetTypeName(parent); if (parentName == "ValueType") { isStruct = true; } else if (parentName == "Enum") { isEnum = true; } else if (parentName != "object") { extends.Add(parentName); } } if (typeDef.interfaces_count > 0) { for (int i = 0; i < typeDef.interfaces_count; i++) { var @interface = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; extends.Add(GetTypeName(@interface)); } } writer.Write($"\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\n"); if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token)); } if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; switch (visibility) { case TYPE_ATTRIBUTE_PUBLIC: case TYPE_ATTRIBUTE_NESTED_PUBLIC: writer.Write("public "); break; case TYPE_ATTRIBUTE_NOT_PUBLIC: case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: writer.Write("internal "); break; case TYPE_ATTRIBUTE_NESTED_PRIVATE: writer.Write("private "); break; case TYPE_ATTRIBUTE_NESTED_FAMILY: writer.Write("protected "); break; case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("static "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if (!isStruct && !isEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else if (isEnum) { writer.Write("enum "); } else { writer.Write("class "); } var typeName = GetTypeName(typeDef); writer.Write($"{typeName}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } if (config.DumpTypeDefIndex) { writer.Write($" // TypeDefIndex: {idx}\n{{"); } else { writer.Write("\n{"); } //dump field if (config.DumpField && typeDef.field_count > 0) { writer.Write("\n\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; var fieldDefaultValue = metadata.GetFieldDefaultValueFromIndex(i); if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, "\t")); } writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(fieldType)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); if (fieldDefaultValue != null && fieldDefaultValue.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(fieldDefaultValue.dataIndex); var fieldDefaultValueType = il2Cpp.types[fieldDefaultValue.typeIndex]; metadata.Position = pointer; object val = null; switch (fieldDefaultValueType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: val = metadata.ReadBoolean(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U1: val = metadata.ReadByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I1: val = metadata.ReadSByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: val = BitConverter.ToChar(metadata.ReadBytes(2), 0); break; case Il2CppTypeEnum.IL2CPP_TYPE_U2: val = metadata.ReadUInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I2: val = metadata.ReadInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U4: val = metadata.ReadUInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I4: val = metadata.ReadInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U8: val = metadata.ReadUInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I8: val = metadata.ReadInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R4: val = metadata.ReadSingle(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R8: val = metadata.ReadDouble(); break; case Il2CppTypeEnum.IL2CPP_TYPE_STRING: var len = metadata.ReadInt32(); val = Encoding.UTF8.GetString(metadata.ReadBytes(len)); break; default: writer.Write($" /*Metadata offset 0x{pointer:X}*/"); break; } if (val is string str) { writer.Write($" = \"{ToEscapedString(str)}\""); } else if (val is char c) { var v = (int)c; writer.Write($" = '\\x{v:x}'"); } else if (val != null) { writer.Write($" = {val}"); } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2Cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } else { writer.Write(";\n"); } } } //dump property if (config.DumpProperty && typeDef.property_count > 0) { writer.Write("\n\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, "\t")); } writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2Cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2Cpp.types[parameterDef.typeIndex]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } } //dump method if (config.DumpMethod && typeDef.method_count > 0) { writer.Write("\n\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t")); } writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2Cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); if (methodReturnType.byref == 1) { writer.Write("ref "); } writer.Write($"{GetTypeName(methodReturnType)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2Cpp.types[parameterDef.typeIndex]; var parameterTypeName = GetTypeName(parameterType); if (parameterType.byref == 1) { if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) == 0) { parameterStr += "out "; } else if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) == 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0) { parameterStr += "in "; } else { parameterStr += "ref "; } } else { if ((parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0) { parameterStr += "[In] "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "[Out] "; } } parameterStr += $"{parameterTypeName} {parameterName}"; var parameterDefault = metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j); if (parameterDefault != null && parameterDefault.dataIndex != -1) { var value = GetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex); if (value is string str) { parameterStr += $" = \"{ToEscapedString(str)}\""; } else if (value is char c) { var v = (int)c; parameterStr += $" = '\\x{v:x}'"; } else if (value != null) { parameterStr += $" = {value}"; } } parameterStrs.Add(parameterStr); } writer.Write(string.Join(", ", parameterStrs)); writer.Write(") { }"); if (config.DumpMethodOffset) { var methodPointer = il2Cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token); if (methodPointer > 0) { var fixedMethodPointer = il2Cpp.FixPointer(methodPointer); writer.Write(" // RVA: 0x{0:X} Offset: 0x{1:X}\n", fixedMethodPointer, il2Cpp.MapVATR(methodPointer)); } else { writer.Write(" // -1\n"); } } else { writer.Write("\n"); } } } writer.Write("}\n"); } } catch (Exception e) { Console.WriteLine("ERROR: Some errors in dumping"); writer.Write("/*"); writer.Write(e); writer.Write("*/\n}\n"); } } writer.Close(); }
private string header_include(Il2CppType type) { string output; string type_name = ""; string namespaze = ""; string template_decl = ""; switch (type.type) { case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { return("#include <cs/array.hpp>"); } case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: return(""); case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: return($"#include <{include_path(type)}.hpp>"); case Il2CppTypeEnum.IL2CPP_TYPE_STRING: { return("#include <cs/string.hpp>"); } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { Il2CppTypeDefinition typeDef; Il2CppGenericClass genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(type.data.generic_class); typeDef = executor.GetGenericClassTypeDefinition(genericClass); var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (@namespace != "") { type_name += @namespace + "."; } type_name += metadata.GetStringFromIndex(typeDef.nameIndex); var index = type_name.IndexOf("`"); if (index != -1) { type_name = type_name.Substring(0, index); } template_decl = "template <class...> "; //Il2CppExecutor.GetGenericContainerParams(genericContainer, generic_decl) break; } default: { if (type.type > Il2CppTypeEnum.IL2CPP_TYPE_R8) { type_name = executor.GetTypeName(type, true, false); } else { return(""); } break; } } type_name = type_name.Replace(".", "::"); type_name = type_name.Replace("*", ""); var nsindex = type_name.LastIndexOf("::"); if (nsindex > 0) { namespaze = type_name.Substring(0, nsindex); type_name = type_name.Substring(nsindex + 2); output = "namespace " + namespaze + "{ " + template_decl + "struct " + deobfu(type_name) + "; }"; } else { output = "struct " + deobfu(type_name) + ";"; } return(output); }
public string GetTypeName(Il2CppType il2CppType, bool addNamespace, bool is_nested, bool is_pointer = true) { /* * if (il2CppType.data.klassIndex) * var typeDef = metadata.typeDefs[typeDefIndex]; * var typeName = executor.GetTypeDefName(typeDef, false, true);*/ switch (il2CppType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2Cpp.MapVATR <Il2CppArrayType>(il2CppType.data.array); var elementType = il2Cpp.GetIl2CppType(arrayType.etype); return($"{GetTypeName(elementType, addNamespace, false)}[{new string(',', arrayType.rank - 1)}]"); } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type); return($"cs::array<{GetTypeName(elementType, addNamespace, false, false)}>*"); } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type); return($"{GetTypeName(oriType, addNamespace, false)}*"); } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { var param = GetGenericParameteFromIl2CppType(il2CppType); return(metadata.GetStringFromIndex(param.nameIndex)); } case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { string str = string.Empty; string str_params = string.Empty; string str_pointer = "*"; if (!is_pointer) { str_pointer = ""; } Il2CppTypeDefinition typeDef; Il2CppGenericClass genericClass = null; if (il2CppType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); typeDef = GetGenericClassTypeDefinition(genericClass); } else { typeDef = GetTypeDefinitionFromIl2CppType(il2CppType); } if (typeDef.declaringTypeIndex != -1) { // nested str += GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true, true); str += "_"; } else if (addNamespace) { var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (@namespace != "") { @namespace = @namespace.Replace(".", "::"); str += @namespace + "::"; } } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); var index = typeName.IndexOf("`"); if (index != -1) { str += typeName.Substring(0, index); } else { str += typeName; } if (is_nested) { return(str); } if (genericClass != null) { var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(genericClass.context.class_inst); str_params += GetGenericInstParams(genericInst); } else if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; str_params += GetGenericContainerParams(genericContainer); } if (il2CppType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) { str_pointer = ""; } str = str.Replace("<", "_"); str = str.Replace(">", "_"); str = Il2CppDecompiler.deobfu(str); return(str + str_params + str_pointer); } default: return(TypeString[(int)il2CppType.type]); } }
public DummyAssemblyGenerator(Il2CppExecutor il2CppExecutor, bool addToken) { executor = il2CppExecutor; metadata = il2CppExecutor.metadata; il2Cpp = il2CppExecutor.il2Cpp; //Il2CppDummyDll var il2CppDummyDll = Il2CppDummyDll.Create(); Assemblies.Add(il2CppDummyDll); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods[0]; var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods[0]; attributeAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AttributeAttribute").Methods[0]; var metadataOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "MetadataOffsetAttribute").Methods[0]; var tokenAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "TokenAttribute").Methods[0]; stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; resolver.Register(il2CppDummyDll); var parameterDefinitionDic = new Dictionary <int, ParameterDefinition>(); var eventDefinitionDic = new Dictionary <int, EventDefinition>(); //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var aname = metadata.assemblyDefs[imageDef.assemblyIndex].aname; var assemblyName = metadata.GetStringFromIndex(aname.nameIndex); 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; * assemblyNameDef.Attributes = (AssemblyAttributes)aname.flags; * assemblyNameDef.PublicKeyToken = aname.public_key_token;*/ var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyNameDef, imageName, moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); var typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); typeDefinitionDic.Add(typeDef, typeDefinition); if (typeDef.declaringTypeIndex == -1) { moduleDefinition.Types.Add(typeDefinition); } } } foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = typeDefinitionDic[nestedTypeDef]; typeDefinition.NestedTypes.Add(nestedTypeDefinition); } } } //提前处理 foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{typeDef.token:X}"))); typeDefinition.CustomAttributes.Add(customTokenAttribute); } //genericParameter if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; for (int i = 0; i < genericContainer.type_argc; i++) { var genericParameterIndex = genericContainer.genericParameterStart + i; var param = metadata.genericParameters[genericParameterIndex]; var genericParameter = CreateGenericParameter(param, typeDefinition); typeDefinition.GenericParameters.Add(genericParameter); } } //parent if (typeDef.parentIndex >= 0) { var parentType = il2Cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(new InterfaceImplementation(interfaceTypeRef)); } } } //处理field, method, property等等 foreach (var imageDef in metadata.imageDefs) { var imageName = metadata.GetStringFromIndex(imageDef.nameIndex); var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { 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); fieldDefinitionDic.Add(i, fieldDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{fieldDef.token:X}"))); fieldDefinition.CustomAttributes.Add(customTokenAttribute); } //fieldDefault if (metadata.GetFieldDefaultValueFromIndex(i, out var fieldDefault) && fieldDefault.dataIndex != -1) { if (executor.TryGetDefaultValue(fieldDefault.typeIndex, fieldDefault.dataIndex, out var value)) { fieldDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); fieldDefinition.CustomAttributes.Add(customAttribute); } } //fieldOffset if (!fieldDefinition.IsLiteral) { var fieldOffset = il2Cpp.GetFieldOffsetFromIndex(index, i - typeDef.fieldStart, i, typeDefinition.IsValueType, fieldDefinition.IsStatic); if (fieldOffset >= 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(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 methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodDefinition = new MethodDefinition(methodName, (MethodAttributes)methodDef.flags, typeDefinition.Module.ImportReference(typeof(void))); methodDefinition.ImplAttributes = (MethodImplAttributes)methodDef.iflags; typeDefinition.Methods.Add(methodDefinition); //genericParameter if (methodDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[methodDef.genericContainerIndex]; for (int j = 0; j < genericContainer.type_argc; j++) { var genericParameterIndex = genericContainer.genericParameterStart + j; var param = metadata.genericParameters[genericParameterIndex]; var genericParameter = CreateGenericParameter(param, methodDefinition); methodDefinition.GenericParameters.Add(genericParameter); } } var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = GetTypeReferenceWithByRef(methodDefinition, methodReturnType); methodDefinition.ReturnType = returnType; if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{methodDef.token:X}"))); methodDefinition.CustomAttributes.Add(customTokenAttribute); } if (methodDefinition.HasBody && typeDefinition.BaseType?.FullName != "System.MulticastDelegate") { var ilprocessor = methodDefinition.Body.GetILProcessor(); if (returnType.FullName == "System.Void") { ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else if (returnType.IsValueType) { var variable = new VariableDefinition(returnType); methodDefinition.Body.Variables.Add(variable); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloca_S, variable)); ilprocessor.Append(ilprocessor.Create(OpCodes.Initobj, returnType)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } else { ilprocessor.Append(ilprocessor.Create(OpCodes.Ldnull)); ilprocessor.Append(ilprocessor.Create(OpCodes.Ret)); } } 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 = GetTypeReferenceWithByRef(methodDefinition, parameterType); var parameterDefinition = new ParameterDefinition(parameterName, (ParameterAttributes)parameterType.attrs, parameterTypeRef); methodDefinition.Parameters.Add(parameterDefinition); parameterDefinitionDic.Add(methodDef.parameterStart + j, parameterDefinition); //ParameterDefault if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) { if (executor.TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value)) { parameterDefinition.Constant = value; } else { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(metadataOffsetAttribute)); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{value:X}")); customAttribute.Fields.Add(offset); parameterDefinition.CustomAttributes.Add(customAttribute); } } } //methodAddress if (!methodDefinition.IsAbstract) { var methodPointer = il2Cpp.GetMethodPointer(imageName, methodDef); if (methodPointer > 0) { var customAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(addressAttribute)); var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); var rva = new CustomAttributeNamedArgument("RVA", new CustomAttributeArgument(stringType, $"0x{fixedMethodPointer:X}")); var offset = new CustomAttributeNamedArgument("Offset", new CustomAttributeArgument(stringType, $"0x{il2Cpp.MapVATR(methodPointer):X}")); var va = new CustomAttributeNamedArgument("VA", new CustomAttributeArgument(stringType, $"0x{methodPointer:X}")); customAttribute.Fields.Add(rva); customAttribute.Fields.Add(offset); customAttribute.Fields.Add(va); if (methodDef.slot != ushort.MaxValue) { var slot = new CustomAttributeNamedArgument("Slot", new CustomAttributeArgument(stringType, methodDef.slot.ToString())); customAttribute.Fields.Add(slot); } 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); propertyDefinitionDic.Add(i, propertyDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{propertyDef.token:X}"))); propertyDefinition.CustomAttributes.Add(customTokenAttribute); } } //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); eventDefinitionDic.Add(i, eventDefinition); if (addToken) { var customTokenAttribute = new CustomAttribute(typeDefinition.Module.ImportReference(tokenAttribute)); customTokenAttribute.Fields.Add(new CustomAttributeNamedArgument("Token", new CustomAttributeArgument(stringType, $"0x{eventDef.token:X}"))); eventDefinition.CustomAttributes.Add(customTokenAttribute); } } } } //第三遍,添加CustomAttribute if (il2Cpp.Version > 20) { foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[typeDef]; //typeAttribute CreateCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token, typeDefinition.Module, typeDefinition.CustomAttributes); //field var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldDefinition = fieldDefinitionDic[i]; //fieldAttribute CreateCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, typeDefinition.Module, fieldDefinition.CustomAttributes); } //method var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodDefinition = methodDefinitionDic[i]; //methodAttribute CreateCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, typeDefinition.Module, methodDefinition.CustomAttributes); //method parameter for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterDefinition = parameterDefinitionDic[methodDef.parameterStart + j]; //parameterAttribute CreateCustomAttribute(imageDef, parameterDef.customAttributeIndex, parameterDef.token, typeDefinition.Module, parameterDefinition.CustomAttributes); } } //property var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; var propertyDefinition = propertyDefinitionDic[i]; //propertyAttribute CreateCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, typeDefinition.Module, propertyDefinition.CustomAttributes); } //event var eventEnd = typeDef.eventStart + typeDef.event_count; for (var i = typeDef.eventStart; i < eventEnd; ++i) { var eventDef = metadata.eventDefs[i]; var eventDefinition = eventDefinitionDic[i]; //eventAttribute CreateCustomAttribute(imageDef, eventDef.customAttributeIndex, eventDef.token, typeDefinition.Module, eventDefinition.CustomAttributes); } } } } }
public string GetTypeName(Il2CppType il2CppType, bool addNamespace, bool is_nested) { switch (il2CppType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2Cpp.MapVATR <Il2CppArrayType>(il2CppType.data.array); var elementType = il2Cpp.GetIl2CppType(arrayType.etype); return($"{GetTypeName(elementType, addNamespace, false)}[{new string(',', arrayType.rank - 1)}]"); } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type); return($"{GetTypeName(elementType, addNamespace, false)}[]"); } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type); return($"{GetTypeName(oriType, addNamespace, false)}*"); } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { var param = GetGenericParameteFromIl2CppType(il2CppType); return(metadata.GetStringFromIndex(param.nameIndex)); } case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { string str = string.Empty; Il2CppTypeDefinition typeDef; Il2CppGenericClass genericClass = null; if (il2CppType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) { genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); typeDef = GetGenericClassTypeDefinition(genericClass); } else { typeDef = GetTypeDefinitionFromIl2CppType(il2CppType); } if (typeDef.declaringTypeIndex != -1) { str += GetTypeName(il2Cpp.types[typeDef.declaringTypeIndex], addNamespace, true); str += '.'; } else if (addNamespace) { var @namespace = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (@namespace != "") { str += @namespace + "."; } } var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); var index = typeName.IndexOf("`"); if (index != -1) { str += typeName.Substring(0, index); } else { str += typeName; } if (is_nested) { return(str); } if (genericClass != null) { var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(genericClass.context.class_inst); str += GetGenericInstParams(genericInst); } else if (typeDef.genericContainerIndex >= 0) { var genericContainer = metadata.genericContainers[typeDef.genericContainerIndex]; str += GetGenericContainerParams(genericContainer); } return(str); } default: return(TypeString[(int)il2CppType.type]); } }
private TypeReference GetTypeReference(MemberReference memberReference, Il2CppType il2CppType) { var moduleDefinition = memberReference.Module; switch (il2CppType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT: return(moduleDefinition.ImportReference(typeof(object))); case Il2CppTypeEnum.IL2CPP_TYPE_VOID: return(moduleDefinition.ImportReference(typeof(void))); case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: return(moduleDefinition.ImportReference(typeof(bool))); case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: return(moduleDefinition.ImportReference(typeof(char))); case Il2CppTypeEnum.IL2CPP_TYPE_I1: return(moduleDefinition.ImportReference(typeof(sbyte))); case Il2CppTypeEnum.IL2CPP_TYPE_U1: return(moduleDefinition.ImportReference(typeof(byte))); case Il2CppTypeEnum.IL2CPP_TYPE_I2: return(moduleDefinition.ImportReference(typeof(short))); case Il2CppTypeEnum.IL2CPP_TYPE_U2: return(moduleDefinition.ImportReference(typeof(ushort))); case Il2CppTypeEnum.IL2CPP_TYPE_I4: return(moduleDefinition.ImportReference(typeof(int))); case Il2CppTypeEnum.IL2CPP_TYPE_U4: return(moduleDefinition.ImportReference(typeof(uint))); case Il2CppTypeEnum.IL2CPP_TYPE_I: return(moduleDefinition.ImportReference(typeof(IntPtr))); case Il2CppTypeEnum.IL2CPP_TYPE_U: return(moduleDefinition.ImportReference(typeof(UIntPtr))); case Il2CppTypeEnum.IL2CPP_TYPE_I8: return(moduleDefinition.ImportReference(typeof(long))); case Il2CppTypeEnum.IL2CPP_TYPE_U8: return(moduleDefinition.ImportReference(typeof(ulong))); case Il2CppTypeEnum.IL2CPP_TYPE_R4: return(moduleDefinition.ImportReference(typeof(float))); case Il2CppTypeEnum.IL2CPP_TYPE_R8: return(moduleDefinition.ImportReference(typeof(double))); case Il2CppTypeEnum.IL2CPP_TYPE_STRING: return(moduleDefinition.ImportReference(typeof(string))); case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF: return(moduleDefinition.ImportReference(typeof(TypedReference))); case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: { var typeDefinition = typeDefinitionDic[il2CppType.data.klassIndex]; return(moduleDefinition.ImportReference(typeDefinition)); } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2Cpp.MapVATR <Il2CppArrayType>(il2CppType.data.array); var oriType = il2Cpp.GetIl2CppType(arrayType.etype); return(new ArrayType(GetTypeReference(memberReference, oriType), arrayType.rank)); } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); var typeDefinition = typeDefinitionDic[genericClass.typeDefinitionIndex]; var genericInstanceType = new GenericInstanceType(moduleDefinition.ImportReference(typeDefinition)); var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(genericClass.context.class_inst); var pointers = il2Cpp.MapVATR <ulong>(genericInst.type_argv, genericInst.type_argc); foreach (var pointer in pointers) { var oriType = il2Cpp.GetIl2CppType(pointer); genericInstanceType.GenericArguments.Add(GetTypeReference(memberReference, oriType)); } return(genericInstanceType); } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type); return(new ArrayType(GetTypeReference(memberReference, oriType))); } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: { if (genericParameterDic.TryGetValue(il2CppType.data.genericParameterIndex, out var genericParameter)) { return(genericParameter); } if (memberReference is MethodDefinition methodDefinition) { return(CreateGenericParameter(il2CppType.data.genericParameterIndex, methodDefinition.DeclaringType)); } var typeDefinition = (TypeDefinition)memberReference; return(CreateGenericParameter(il2CppType.data.genericParameterIndex, typeDefinition)); } case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { if (genericParameterDic.TryGetValue(il2CppType.data.genericParameterIndex, out var genericParameter)) { return(genericParameter); } var methodDefinition = (MethodDefinition)memberReference; return(CreateGenericParameter(il2CppType.data.genericParameterIndex, methodDefinition)); } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type); return(new PointerType(GetTypeReference(memberReference, oriType))); } default: throw new ArgumentOutOfRangeException(); } }
private static void Dump() { var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create), new UTF8Encoding(false)); Console.WriteLine("Dumping..."); //Script var scriptwriter = CreateScriptWriter(); //dump image for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } //dump type 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>(); if (typeDef.parentIndex >= 0) { var parent = il2cpp.types[typeDef.parentIndex]; var parentName = GetTypeName(parent); if (parentName == "ValueType") { isStruct = true; } else if (parentName == "Enum") { isEnum = true; } else if (parentName != "object") { extends.Add(parentName); } } //implementedInterfaces if (typeDef.interfaces_count > 0) { for (int i = 0; i < typeDef.interfaces_count; i++) { var @interface = il2cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; extends.Add(GetTypeName(@interface)); } } writer.Write($"\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\n"); writer.Write(GetCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token)); if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; switch (visibility) { case TYPE_ATTRIBUTE_PUBLIC: case TYPE_ATTRIBUTE_NESTED_PUBLIC: writer.Write("public "); break; case TYPE_ATTRIBUTE_NOT_PUBLIC: case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: writer.Write("internal "); break; case TYPE_ATTRIBUTE_NESTED_PRIVATE: writer.Write("private "); break; case TYPE_ATTRIBUTE_NESTED_FAMILY: writer.Write("protected "); break; case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("static "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if (!isStruct && !isEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (isStruct) { writer.Write("struct "); } else if (isEnum) { writer.Write("enum "); } else { writer.Write("class "); } var typeName = GetTypeName(typeDef); writer.Write($"{typeName}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } if (config.DumpTypeDefIndex) { writer.Write($" // TypeDefIndex: {idx}\n{{"); } else { writer.Write("\n{"); } //dump field if (config.DumpField && typeDef.field_count > 0) { writer.Write("\n\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { //dump_field(i, idx, i - typeDef.fieldStart); var fieldDef = metadata.fieldDefs[i]; var fieldType = il2cpp.types[fieldDef.typeIndex]; var fieldDefaultValue = metadata.GetFieldDefaultValueFromIndex(i); writer.Write(GetCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, "\t")); writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(fieldType)} {metadata.GetStringFromIndex(fieldDef.nameIndex)}"); if (fieldDefaultValue != null && fieldDefaultValue.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(fieldDefaultValue.dataIndex); if (pointer > 0) { var fieldDefaultValueType = il2cpp.types[fieldDefaultValue.typeIndex]; metadata.Position = pointer; object val = null; switch (fieldDefaultValueType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: val = metadata.ReadBoolean(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U1: val = metadata.ReadByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I1: val = metadata.ReadSByte(); break; case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: val = BitConverter.ToChar(metadata.ReadBytes(2), 0); break; case Il2CppTypeEnum.IL2CPP_TYPE_U2: val = metadata.ReadUInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I2: val = metadata.ReadInt16(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U4: val = metadata.ReadUInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I4: val = metadata.ReadInt32(); break; case Il2CppTypeEnum.IL2CPP_TYPE_U8: val = metadata.ReadUInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_I8: val = metadata.ReadInt64(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R4: val = metadata.ReadSingle(); break; case Il2CppTypeEnum.IL2CPP_TYPE_R8: val = metadata.ReadDouble(); break; case Il2CppTypeEnum.IL2CPP_TYPE_STRING: var len = metadata.ReadInt32(); val = Encoding.UTF8.GetString(metadata.ReadBytes(len)); break; //case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: default: writer.Write($" /*Default value offset 0x{pointer:X}*/"); break; } if (val is string str) { writer.Write($" = \"{ToEscapedString(str)}\""); } else if (val is char c) { var v = (int)c; writer.Write($" = '\\x{v:x}'"); } else if (val != null) { writer.Write($" = {val}"); } } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } else { writer.Write(";\n"); } } } //dump property if (config.DumpProperty && typeDef.property_count > 0) { writer.Write("\n\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; writer.Write(GetCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, "\t")); writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2cpp.types[parameterDef.typeIndex]; writer.Write($"{GetTypeName(propertyType)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } } //dump method if (config.DumpMethod && typeDef.method_count > 0) { writer.Write("\n\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t")); writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); writer.Write($"{GetTypeName(methodReturnType)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2cpp.types[parameterDef.typeIndex]; var parameterTypeName = GetTypeName(parameterType); if ((parameterType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { parameterStr += "optional "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "out "; } parameterStr += $"{parameterTypeName} {parameterName}"; parameterStrs.Add(parameterStr); } writer.Write(string.Join(", ", parameterStrs)); if (config.DumpMethodOffset) { var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token); if (methodPointer > 0) { var fixedMethodPointer = il2cpp.FixPointer(methodPointer); writer.Write("); // RVA: 0x{0:X} Offset: 0x{1:X}\n", fixedMethodPointer, il2cpp.MapVATR(methodPointer)); //Script - methodPointer if (il2cpp is PE) { scriptwriter.WriteLine($"SetName(0x{methodPointer:X}, '{typeName + "$$" + methodName}')"); } else { scriptwriter.WriteLine($"SetName(0x{fixedMethodPointer:X}, '{typeName + "$$" + methodName}')"); } } else { writer.Write("); // -1\n"); } } else { writer.Write("); \n"); } } } writer.Write("}\n"); } } catch (Exception e) { Console.WriteLine("ERROR: Some errors in dumping"); writer.Write("/*"); writer.Write(e); writer.Write("*/\n}\n"); } } scriptwriter.WriteLine("print('Make method name done')"); //Script - MetadataUsage if (il2cpp.version > 16) { scriptwriter.WriteLine("print('Setting MetadataUsage...')"); foreach (var i in metadata.metadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo { var type = il2cpp.types[i.Value]; var typeName = GetTypeName(type, true); scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')"); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, r'{typeName}', 1)"); } foreach (var i in metadata.metadataUsageDic[2]) //kIl2CppMetadataUsageIl2CppType { var type = il2cpp.types[i.Value]; var typeName = GetTypeName(type, true); scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')"); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, r'{typeName}', 1)"); } foreach (var i in metadata.metadataUsageDic[3]) //kIl2CppMetadataUsageMethodDef { var methodDef = metadata.methodDefs[i.Value]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = GetTypeName(typeDef); var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()"; scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')"); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)"); var imageIndex = typeDefImageIndices[typeDef]; var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, (int)i.Value, imageIndex, methodDef.token); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)"); } foreach (var i in metadata.metadataUsageDic[4]) //kIl2CppMetadataUsageFieldInfo { var fieldRef = metadata.fieldRefs[i.Value]; var type = il2cpp.types[fieldRef.typeIndex]; var typeDef = metadata.typeDefs[type.data.klassIndex]; var fieldDef = metadata.fieldDefs[typeDef.fieldStart + fieldRef.fieldIndex]; var fieldName = GetTypeName(type, true) + "." + metadata.GetStringFromIndex(fieldDef.nameIndex); scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Field$" + fieldName}')"); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, r'{fieldName}', 1)"); } var stringLiterals = metadata.metadataUsageDic[5].Select(x => new //kIl2CppMetadataUsageStringLiteral { value = metadata.GetStringLiteralFromIndex(x.Value), address = $"0x{il2cpp.metadataUsages[x.Key]:X}" }).ToArray(); File.WriteAllText("stringliteral.json", JsonConvert.SerializeObject(stringLiterals, Formatting.Indented), new UTF8Encoding(false)); foreach (var stringLiteral in stringLiterals) { scriptwriter.WriteLine($"SetString({stringLiteral.address}, r'{ToEscapedString(stringLiteral.value)}')"); } foreach (var i in metadata.metadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef { var methodSpec = il2cpp.methodSpecs[i.Value]; var methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = GetTypeName(typeDef); // Class of the method is generic if (methodSpec.classIndexIndex != -1) { var classInst = il2cpp.genericInsts[methodSpec.classIndexIndex]; typeName += GetGenericTypeParams(classInst); } var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()"; // Method itself is generic if (methodSpec.methodIndexIndex != -1) { var methodInst = il2cpp.genericInsts[methodSpec.methodIndexIndex]; methodName += GetGenericTypeParams(methodInst); } scriptwriter.WriteLine($"SetName(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')"); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}', 1)"); var imageIndex = typeDefImageIndices[typeDef]; var methodPointer = il2cpp.GetMethodPointer(methodDef.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token); scriptwriter.WriteLine($"idc.set_cmt(0x{il2cpp.metadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)"); } scriptwriter.WriteLine("print('Set MetadataUsage done')"); } //Script - MakeFunction if (config.MakeFunction) { 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); orderedPointers.AddRange(il2cpp.invokerPointers); orderedPointers.AddRange(il2cpp.customAttributeGenerators); if (il2cpp.version >= 22) { orderedPointers.AddRange(il2cpp.reversePInvokeWrappers); orderedPointers.AddRange(il2cpp.unresolvedVirtualCallPointers); } //TODO interopData内也包含函数 orderedPointers = orderedPointers.Distinct().OrderBy(x => x).ToList(); orderedPointers.Remove(0); scriptwriter.WriteLine("print('Making function...')"); for (int i = 0; i < orderedPointers.Count - 1; i++) { scriptwriter.WriteLine($"MakeFunction(0x{orderedPointers[i]:X}, 0x{orderedPointers[i + 1]:X})"); } scriptwriter.WriteLine("print('Make function done, please wait for IDA to complete the analysis')"); } scriptwriter.WriteLine("print('Script finish !')"); //writer close writer.Close(); scriptwriter.Close(); Console.WriteLine("Done !"); //DummyDll if (config.DummyDll) { Console.WriteLine("Create DummyDll..."); if (Directory.Exists("DummyDll")) { Directory.Delete("DummyDll", true); } Directory.CreateDirectory("DummyDll"); Directory.SetCurrentDirectory("DummyDll"); var dummy = new DummyAssemblyCreator(metadata, il2cpp); foreach (var assembly in dummy.Assemblies) { var stream = new MemoryStream(); assembly.Write(stream); File.WriteAllBytes(assembly.MainModule.Name, stream.ToArray()); } Console.WriteLine("Done !"); } }
public void Decompile(Config config) { var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create), new UTF8Encoding(false)); //dump image for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetStringFromIndex(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } //dump type for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { try { var imageDef = metadata.imageDefs[imageIndex]; var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int typeDefIndex = imageDef.typeStart; typeDefIndex < typeEnd; typeDefIndex++) { var typeDef = metadata.typeDefs[typeDefIndex]; var extends = new List <string>(); if (typeDef.parentIndex >= 0) { var parent = il2Cpp.types[typeDef.parentIndex]; var parentName = executor.GetTypeName(parent, false, false); if (!typeDef.IsValueType && !typeDef.IsEnum && parentName != "object") { extends.Add(parentName); } } if (typeDef.interfaces_count > 0) { for (int i = 0; i < typeDef.interfaces_count; i++) { var @interface = il2Cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; extends.Add(executor.GetTypeName(@interface, false, false)); } } writer.Write($"\n// Namespace: {metadata.GetStringFromIndex(typeDef.namespaceIndex)}\n"); if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, typeDef.customAttributeIndex, typeDef.token)); } if (config.DumpAttribute && (typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } var visibility = typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; switch (visibility) { case TYPE_ATTRIBUTE_PUBLIC: case TYPE_ATTRIBUTE_NESTED_PUBLIC: writer.Write("public "); break; case TYPE_ATTRIBUTE_NOT_PUBLIC: case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: writer.Write("internal "); break; case TYPE_ATTRIBUTE_NESTED_PRIVATE: writer.Write("private "); break; case TYPE_ATTRIBUTE_NESTED_FAMILY: writer.Write("protected "); break; case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0 && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("static "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) == 0 && (typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if (!typeDef.IsValueType && !typeDef.IsEnum && (typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else if (typeDef.IsEnum) { writer.Write("enum "); } else if (typeDef.IsValueType) { writer.Write("struct "); } else { writer.Write("class "); } var typeName = executor.GetTypeDefName(typeDef, false, true); writer.Write($"{typeName}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } if (config.DumpTypeDefIndex) { writer.Write($" // TypeDefIndex: {typeDefIndex}\n{{"); } else { writer.Write("\n{"); } //dump field if (config.DumpField && typeDef.field_count > 0) { writer.Write("\n\t// Fields\n"); var fieldEnd = typeDef.fieldStart + typeDef.field_count; for (var i = typeDef.fieldStart; i < fieldEnd; ++i) { var fieldDef = metadata.fieldDefs[i]; var fieldType = il2Cpp.types[fieldDef.typeIndex]; var isStatic = false; if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, fieldDef.customAttributeIndex, fieldDef.token, "\t")); } writer.Write("\t"); var access = fieldType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; switch (access) { case FIELD_ATTRIBUTE_PRIVATE: writer.Write("private "); break; case FIELD_ATTRIBUTE_PUBLIC: writer.Write("public "); break; case FIELD_ATTRIBUTE_FAMILY: writer.Write("protected "); break; case FIELD_ATTRIBUTE_ASSEMBLY: case FIELD_ATTRIBUTE_FAM_AND_ASSEM: writer.Write("internal "); break; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: writer.Write("protected internal "); break; } if ((fieldType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((fieldType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { isStatic = true; writer.Write("static "); } if ((fieldType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } 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)) { writer.Write($" = "); if (value is string str) { writer.Write($"\"{str.ToEscapedString()}\""); } else if (value is char c) { var v = (int)c; writer.Write($"'\\x{v:x}'"); } else if (value != null) { writer.Write($"{value}"); } } else { writer.Write($" /*Metadata offset 0x{value:X}*/"); } } if (config.DumpFieldOffset) { writer.Write("; // 0x{0:X}\n", il2Cpp.GetFieldOffsetFromIndex(typeDefIndex, i - typeDef.fieldStart, i, typeDef.IsValueType, isStatic)); } else { writer.Write(";\n"); } } } //dump property if (config.DumpProperty && typeDef.property_count > 0) { writer.Write("\n\t// Properties\n"); var propertyEnd = typeDef.propertyStart + typeDef.property_count; for (var i = typeDef.propertyStart; i < propertyEnd; ++i) { var propertyDef = metadata.propertyDefs[i]; if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, propertyDef.customAttributeIndex, propertyDef.token, "\t")); } writer.Write("\t"); if (propertyDef.get >= 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.get]; writer.Write(GetModifiers(methodDef)); var propertyType = il2Cpp.types[methodDef.returnType]; writer.Write($"{executor.GetTypeName(propertyType, false, false)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } else if (propertyDef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertyDef.set]; writer.Write(GetModifiers(methodDef)); var parameterDef = metadata.parameterDefs[methodDef.parameterStart]; var propertyType = il2Cpp.types[parameterDef.typeIndex]; writer.Write($"{executor.GetTypeName(propertyType, false, false)} {metadata.GetStringFromIndex(propertyDef.nameIndex)} {{ "); } if (propertyDef.get >= 0) { writer.Write("get; "); } if (propertyDef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } } //dump method if (config.DumpMethod && typeDef.method_count > 0) { writer.Write("\n\t// Methods\n"); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; if (config.DumpAttribute) { writer.Write(GetCustomAttribute(imageDef, methodDef.customAttributeIndex, methodDef.token, "\t")); } if (config.DumpMethodOffset) { var methodPointer = il2Cpp.GetMethodPointer(methodDef.methodIndex, i, imageIndex, methodDef.token); if (methodPointer > 0) { var fixedMethodPointer = il2Cpp.GetRVA(methodPointer); writer.Write("\t// RVA: 0x{0:X} Offset: 0x{1:X} VA: 0x{2:X}", fixedMethodPointer, il2Cpp.MapVATR(methodPointer), methodPointer); } else { writer.Write("\t// RVA: -1 Offset: -1"); } if (methodDef.slot != ushort.MaxValue) { writer.Write(" Slot: {0}", methodDef.slot); } writer.Write("\n"); } writer.Write("\t"); writer.Write(GetModifiers(methodDef)); var methodReturnType = il2Cpp.types[methodDef.returnType]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); if (methodReturnType.byref == 1) { writer.Write("ref "); } writer.Write($"{executor.GetTypeName(methodReturnType, false, false)} {methodName}("); var parameterStrs = new List <string>(); for (var j = 0; j < methodDef.parameterCount; ++j) { var parameterStr = ""; var parameterDef = metadata.parameterDefs[methodDef.parameterStart + j]; var parameterName = metadata.GetStringFromIndex(parameterDef.nameIndex); var parameterType = il2Cpp.types[parameterDef.typeIndex]; var parameterTypeName = executor.GetTypeName(parameterType, false, false); if (parameterType.byref == 1) { if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) == 0) { parameterStr += "out "; } else if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) == 0 && (parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0) { parameterStr += "in "; } else { parameterStr += "ref "; } } else { if ((parameterType.attrs & PARAM_ATTRIBUTE_IN) != 0) { parameterStr += "[In] "; } if ((parameterType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { parameterStr += "[Out] "; } } parameterStr += $"{parameterTypeName} {parameterName}"; if (metadata.GetParameterDefaultValueFromIndex(methodDef.parameterStart + j, out var parameterDefault) && parameterDefault.dataIndex != -1) { if (TryGetDefaultValue(parameterDefault.typeIndex, parameterDefault.dataIndex, out var value)) { parameterStr += " = "; if (value is string str) { parameterStr += $"\"{str.ToEscapedString()}\""; } else if (value is char c) { var v = (int)c; parameterStr += $"'\\x{v:x}'"; } else if (value != null) { parameterStr += $"{value}"; } } else { parameterStr += $" /*Metadata offset 0x{value:X}*/"; } } parameterStrs.Add(parameterStr); } writer.Write(string.Join(", ", parameterStrs)); writer.Write(") { }\n"); } } writer.Write("}\n"); } } catch (Exception e) { Console.WriteLine("ERROR: Some errors in dumping"); writer.Write("/*"); writer.Write(e); writer.Write("*/\n}\n"); } } writer.Close(); }
public DummyAssemblyCreator(Metadata metadata, Il2Cpp il2cpp) { this.metadata = metadata; this.il2cpp = il2cpp; //Il2CppDummyDll var il2CppDummyDll = AssemblyDefinition.ReadAssembly(new MemoryStream(Resource1.Il2CppDummyDll)); var addressAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "AddressAttribute").Methods.First(); var fieldOffsetAttribute = il2CppDummyDll.MainModule.Types.First(x => x.Name == "FieldOffsetAttribute").Methods.First(); var stringType = il2CppDummyDll.MainModule.TypeSystem.String; var resolver = new MyAssemblyResolver(); var moduleParameters = new ModuleParameters { Kind = ModuleKind.Dll, AssemblyResolver = resolver }; //创建程序集,同时创建所有类 foreach (var imageDef in metadata.imageDefs) { var assemblyName = new AssemblyNameDefinition(metadata.GetStringFromIndex(imageDef.nameIndex).Replace(".dll", ""), new Version("3.7.1.6")); var assemblyDefinition = AssemblyDefinition.CreateAssembly(assemblyName, metadata.GetStringFromIndex(imageDef.nameIndex), moduleParameters); resolver.Register(assemblyDefinition); Assemblies.Add(assemblyDefinition); var moduleDefinition = assemblyDefinition.MainModule; moduleDefinition.Types.Clear();//清除自动创建的<Module>类 var typeEnd = imageDef.typeStart + imageDef.typeCount; for (var index = imageDef.typeStart; index < typeEnd; ++index) { var typeDef = metadata.typeDefs[index]; var namespaceName = metadata.GetStringFromIndex(typeDef.namespaceIndex); var typeName = metadata.GetStringFromIndex(typeDef.nameIndex); TypeDefinition typeDefinition; if (typeDef.declaringTypeIndex != -1)//nested types { typeDefinition = typeDefinitionDic[index]; } else { typeDefinition = new TypeDefinition(namespaceName, typeName, (TypeAttributes)typeDef.flags); moduleDefinition.Types.Add(typeDefinition); typeDefinitionDic.Add(index, typeDefinition); } //nestedtype for (int i = 0; i < typeDef.nested_type_count; i++) { var nestedIndex = metadata.nestedTypeIndices[typeDef.nestedTypesStart + i]; var nestedTypeDef = metadata.typeDefs[nestedIndex]; var nestedTypeDefinition = new TypeDefinition(metadata.GetStringFromIndex(nestedTypeDef.namespaceIndex), metadata.GetStringFromIndex(nestedTypeDef.nameIndex), (TypeAttributes)nestedTypeDef.flags); typeDefinition.NestedTypes.Add(nestedTypeDefinition); typeDefinitionDic.Add(nestedIndex, nestedTypeDefinition); } } } //先单独处理,因为不知道会不会有问题 for (var index = 0; index < metadata.uiNumTypes; ++index) { var typeDef = metadata.typeDefs[index]; var typeDefinition = typeDefinitionDic[index]; //parent if (typeDef.parentIndex >= 0) { var parentType = il2cpp.types[typeDef.parentIndex]; var parentTypeRef = GetTypeReference(typeDefinition, parentType); typeDefinition.BaseType = parentTypeRef; } //interfaces for (int i = 0; i < typeDef.interfaces_count; i++) { var interfaceType = il2cpp.types[metadata.interfaceIndices[typeDef.interfacesStart + i]]; var interfaceTypeRef = GetTypeReference(typeDefinition, interfaceType); typeDefinition.Interfaces.Add(interfaceTypeRef); } } //处理field, method, property等等 for (var index = 0; index < metadata.uiNumTypes; ++index) { 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 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 fieldDefault = metadata.GetFieldDefaultValueFromIndex(i); if (fieldDefault != null && fieldDefault.dataIndex != -1) { 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 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的反序列化 if (il2cpp.version > 20) { var engine = Assemblies.Find(x => x.MainModule.Types.Any(t => t.Namespace == "UnityEngine" && t.Name == "SerializeField")); var serializeField = engine.MainModule.Types.First(x => x.Name == "SerializeField").Methods.First(); foreach (var imageDef in metadata.imageDefs) { var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int index = imageDef.typeStart; index < typeEnd; index++) { 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 fieldDef = metadata.fieldDefs[i]; var fieldName = metadata.GetStringFromIndex(fieldDef.nameIndex); var fieldDefinition = typeDefinition.Fields.First(x => x.Name == fieldName); //fieldAttribute var attributeIndex = metadata.GetCustomAttributeIndex(imageDef, fieldDef.customAttributeIndex, fieldDef.token); if (attributeIndex >= 0) { var attributeTypeRange = metadata.attributeTypeRanges[attributeIndex]; for (int j = 0; j < attributeTypeRange.count; j++) { var attributeTypeIndex = metadata.attributeTypes[attributeTypeRange.start + j]; var attributeType = il2cpp.types[attributeTypeIndex]; if (attributeType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS) { var klass = metadata.typeDefs[attributeType.data.klassIndex]; var attributeName = metadata.GetStringFromIndex(klass.nameIndex); if (attributeName == "SerializeField") { var customAttribute = new CustomAttribute(typeDefinition.Module.Import(serializeField)); fieldDefinition.CustomAttributes.Add(customAttribute); } } } } } } } } }
private string ParseType(Il2CppType il2CppType, Il2CppGenericContext context = null) { switch (il2CppType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_VOID: return("void"); case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: return("bool"); case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: return("uint16_t"); //Il2CppChar case Il2CppTypeEnum.IL2CPP_TYPE_I1: return("int8_t"); case Il2CppTypeEnum.IL2CPP_TYPE_U1: return("uint8_t"); case Il2CppTypeEnum.IL2CPP_TYPE_I2: return("int16_t"); case Il2CppTypeEnum.IL2CPP_TYPE_U2: return("uint16_t"); case Il2CppTypeEnum.IL2CPP_TYPE_I4: return("int32_t"); case Il2CppTypeEnum.IL2CPP_TYPE_U4: return("uint32_t"); case Il2CppTypeEnum.IL2CPP_TYPE_I8: return("int64_t"); case Il2CppTypeEnum.IL2CPP_TYPE_U8: return("uint64_t"); case Il2CppTypeEnum.IL2CPP_TYPE_R4: return("float"); case Il2CppTypeEnum.IL2CPP_TYPE_R8: return("double"); case Il2CppTypeEnum.IL2CPP_TYPE_STRING: return("System_String_o*"); case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var oriType = il2Cpp.GetIl2CppType(il2CppType.data.type); return(ParseType(oriType) + "*"); } case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: { var typeDef = metadata.typeDefs[il2CppType.data.klassIndex]; if (typeDef.IsEnum) { return(ParseType(il2Cpp.types[typeDef.elementTypeIndex])); } return(structNameDic[typeDef] + "_o"); } case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: { var typeDef = metadata.typeDefs[il2CppType.data.klassIndex]; return(structNameDic[typeDef] + "_o*"); } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: { if (context != null) { var genericParameter = metadata.genericParameters[il2CppType.data.genericParameterIndex]; var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(context.class_inst); var pointers = il2Cpp.MapVATR <ulong>(genericInst.type_argv, genericInst.type_argc); var pointer = pointers[genericParameter.num]; var type = il2Cpp.GetIl2CppType(pointer); return(ParseType(type)); } return("Il2CppObject*"); } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2Cpp.MapVATR <Il2CppArrayType>(il2CppType.data.array); var elementType = il2Cpp.GetIl2CppType(arrayType.etype); var elementStructName = GetIl2CppStructName(elementType, context); var typeStructName = elementStructName + "_array"; if (structNameHashSet.Add(typeStructName)) { ParseArrayClassStruct(elementType, context); } return(typeStructName + "*"); } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); var typeDef = metadata.typeDefs[genericClass.typeDefinitionIndex]; if (!genericClassStructNameDic.TryGetValue(il2CppType.data.generic_class, out var typeStructName)) { var typeOriName = structNameDic[typeDef]; var typeToReplaceName = FixName(executor.GetTypeDefName(typeDef, true, true)); var typeReplaceName = FixName(executor.GetTypeName(il2CppType, true, false)); typeStructName = typeOriName.Replace(typeToReplaceName, typeReplaceName); genericClassStructNameDic.Add(il2CppType.data.generic_class, typeStructName); if (structNameHashSet.Add(typeStructName)) { genericClassList.Add(il2CppType.data.generic_class); } } if (typeDef.IsValueType) { if (typeDef.IsEnum) { return(ParseType(il2Cpp.types[typeDef.elementTypeIndex])); } return(typeStructName + "_o"); } return(typeStructName + "_o*"); } case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF: return("Il2CppObject*"); case Il2CppTypeEnum.IL2CPP_TYPE_I: return("intptr_t"); case Il2CppTypeEnum.IL2CPP_TYPE_U: return("uintptr_t"); case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT: return("Il2CppObject*"); case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var elementType = il2Cpp.GetIl2CppType(il2CppType.data.type); var elementStructName = GetIl2CppStructName(elementType, context); var typeStructName = elementStructName + "_array"; if (structNameHashSet.Add(typeStructName)) { ParseArrayClassStruct(elementType, context); } return(typeStructName + "*"); } case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { if (context != null) { var genericParameter = metadata.genericParameters[il2CppType.data.genericParameterIndex]; var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(context.method_inst); var pointers = il2Cpp.MapVATR <ulong>(genericInst.type_argv, genericInst.type_argc); var pointer = pointers[genericParameter.num]; var type = il2Cpp.GetIl2CppType(pointer); return(ParseType(type)); } return("Il2CppObject*"); } default: throw new NotSupportedException(); } }
public string GetTypeName(Il2CppType type, bool fullName = false) { string ret; switch (type.type) { case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: { var typeDef = metadata.typeDefs[type.data.klassIndex]; ret = string.Empty; if (fullName) { ret = metadata.GetStringFromIndex(typeDef.namespaceIndex); if (ret != string.Empty) { ret += "."; } } ret += GetTypeDefName(typeDef); break; } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(type.data.generic_class); var typeDef = metadata.typeDefs[genericClass.typeDefinitionIndex]; ret = metadata.GetStringFromIndex(typeDef.nameIndex); var genericInst = il2Cpp.MapVATR <Il2CppGenericInst>(genericClass.context.class_inst); ret = ret.Replace($"`{genericInst.type_argc}", ""); ret += GetGenericTypeParams(genericInst); break; } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { var param = metadata.genericParameters[type.data.genericParameterIndex]; ret = metadata.GetStringFromIndex(param.nameIndex); break; } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2Cpp.MapVATR <Il2CppArrayType>(type.data.array); var oriType = il2Cpp.GetIl2CppType(arrayType.etype); ret = $"{GetTypeName(oriType)}[{new string(',', arrayType.rank - 1)}]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var oriType = il2Cpp.GetIl2CppType(type.data.type); ret = $"{GetTypeName(oriType)}[]"; break; } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var oriType = il2Cpp.GetIl2CppType(type.data.type); ret = $"{GetTypeName(oriType)}*"; break; } default: ret = TypeString[(int)type.type]; break; } return(ret); }
private TypeReference GetTypeReference(MemberReference memberReference, Il2CppType pType) { var moduleDefinition = memberReference.Module; switch (pType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_OBJECT: return(moduleDefinition.Import(typeof(Object))); case Il2CppTypeEnum.IL2CPP_TYPE_VOID: return(moduleDefinition.Import(typeof(void))); case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: return(moduleDefinition.Import(typeof(Boolean))); case Il2CppTypeEnum.IL2CPP_TYPE_CHAR: return(moduleDefinition.Import(typeof(Char))); case Il2CppTypeEnum.IL2CPP_TYPE_I1: return(moduleDefinition.Import(typeof(SByte))); case Il2CppTypeEnum.IL2CPP_TYPE_U1: return(moduleDefinition.Import(typeof(Byte))); case Il2CppTypeEnum.IL2CPP_TYPE_I2: return(moduleDefinition.Import(typeof(Int16))); case Il2CppTypeEnum.IL2CPP_TYPE_U2: return(moduleDefinition.Import(typeof(UInt16))); case Il2CppTypeEnum.IL2CPP_TYPE_I4: return(moduleDefinition.Import(typeof(Int32))); case Il2CppTypeEnum.IL2CPP_TYPE_U4: return(moduleDefinition.Import(typeof(UInt32))); case Il2CppTypeEnum.IL2CPP_TYPE_I: return(moduleDefinition.Import(typeof(IntPtr))); case Il2CppTypeEnum.IL2CPP_TYPE_U: return(moduleDefinition.Import(typeof(UIntPtr))); case Il2CppTypeEnum.IL2CPP_TYPE_I8: return(moduleDefinition.Import(typeof(Int64))); case Il2CppTypeEnum.IL2CPP_TYPE_U8: return(moduleDefinition.Import(typeof(UInt64))); case Il2CppTypeEnum.IL2CPP_TYPE_R4: return(moduleDefinition.Import(typeof(Single))); case Il2CppTypeEnum.IL2CPP_TYPE_R8: return(moduleDefinition.Import(typeof(Double))); case Il2CppTypeEnum.IL2CPP_TYPE_STRING: return(moduleDefinition.Import(typeof(String))); case Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF: return(moduleDefinition.Import(typeof(TypedReference))); case Il2CppTypeEnum.IL2CPP_TYPE_CLASS: case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE: { var typeDefinition = typeDefinitionDic[pType.data.klassIndex]; return(moduleDefinition.Import(typeDefinition)); } case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY: { var arrayType = il2cpp.MapVATR <Il2CppArrayType>(pType.data.array); var type = il2cpp.GetIl2CppType(arrayType.etype); return(new ArrayType(GetTypeReference(memberReference, type), arrayType.rank)); } case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST: { var generic_class = il2cpp.MapVATR <Il2CppGenericClass>(pType.data.generic_class); var typeDefinition = typeDefinitionDic[generic_class.typeDefinitionIndex]; var genericInstanceType = new GenericInstanceType(moduleDefinition.Import(typeDefinition)); var pInst = il2cpp.MapVATR <Il2CppGenericInst>(generic_class.context.class_inst); var pointers = il2cpp.GetPointers(pInst.type_argv, (long)pInst.type_argc); foreach (var pointer in pointers) { var pOriType = il2cpp.GetIl2CppType(pointer); genericInstanceType.GenericArguments.Add(GetTypeReference(memberReference, pOriType)); } return(genericInstanceType); } case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: { var type = il2cpp.GetIl2CppType(pType.data.type); return(new ArrayType(GetTypeReference(memberReference, type))); } case Il2CppTypeEnum.IL2CPP_TYPE_VAR: { if (genericParameterDic.TryGetValue(pType, out var genericParameter)) { return(genericParameter); } if (memberReference is MethodDefinition methodDefinition) { var genericName = "T" + (methodDefinition.DeclaringType.GenericParameters.Count + 1); genericParameter = new GenericParameter(genericName, methodDefinition.DeclaringType); methodDefinition.DeclaringType.GenericParameters.Add(genericParameter); genericParameterDic.Add(pType, genericParameter); return(genericParameter); } var typeDefinition = (TypeDefinition)memberReference; var genericName2 = "T" + (typeDefinition.GenericParameters.Count + 1); genericParameter = new GenericParameter(genericName2, typeDefinition); typeDefinition.GenericParameters.Add(genericParameter); genericParameterDic.Add(pType, genericParameter); return(genericParameter); } case Il2CppTypeEnum.IL2CPP_TYPE_MVAR: { if (genericParameterDic.TryGetValue(pType, out var genericParameter)) { return(genericParameter); } var methodDefinition = (MethodDefinition)memberReference; var genericName = "T" + (methodDefinition.GenericParameters.Count + 1); genericParameter = new GenericParameter(genericName, methodDefinition); methodDefinition.GenericParameters.Add(genericParameter); genericParameterDic.Add(pType, genericParameter); return(genericParameter); } case Il2CppTypeEnum.IL2CPP_TYPE_PTR: { var type = il2cpp.GetIl2CppType(pType.data.type); return(new PointerType(GetTypeReference(memberReference, type))); } default: return(moduleDefinition.Import(typeof(Object))); } }
public void WriteScript(Config config) { var json = new ScriptJson(); // 生成唯一名称 for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++) { var typeDef = metadata.typeDefs[typeIndex]; typeDefImageIndices.Add(typeDef, imageIndex); CreateStructNameDic(typeDef); } } // 生成后面处理泛型实例要用到的字典 foreach (var il2CppType in il2Cpp.types.Where(x => x.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)) { var genericClass = il2Cpp.MapVATR <Il2CppGenericClass>(il2CppType.data.generic_class); var typeDef = metadata.typeDefs[genericClass.typeDefinitionIndex]; var typeBaseName = structNameDic[typeDef]; var typeToReplaceName = FixName(executor.GetTypeDefName(typeDef, true, true)); var typeReplaceName = FixName(executor.GetTypeName(il2CppType, true, false)); var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName); nameGenericClassDic[typeStructName] = il2CppType; genericClassStructNameDic[il2CppType.data.generic_class] = typeStructName; } // 处理函数 for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; var typeEnd = imageDef.typeStart + imageDef.typeCount; for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++) { var typeDef = metadata.typeDefs[typeIndex]; AddStruct(typeDef); var typeName = executor.GetTypeDefName(typeDef, true, true); var methodEnd = typeDef.methodStart + typeDef.method_count; for (var i = typeDef.methodStart; i < methodEnd; ++i) { var methodDef = metadata.methodDefs[i]; var methodName = metadata.GetStringFromIndex(methodDef.nameIndex); var methodPointer = il2Cpp.GetMethodPointer(methodDef, imageIndex); if (methodPointer > 0) { var scriptMethod = new ScriptMethod(); json.ScriptMethod.Add(scriptMethod); scriptMethod.Address = il2Cpp.GetRVA(methodPointer); var methodFullName = typeName + "$$" + methodName; scriptMethod.Name = methodFullName; var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = ParseType(methodReturnType); if (methodReturnType.byref == 1) { returnType += "*"; } var signature = $"{returnType} {FixName(methodFullName)} ("; var parameterStrs = new List <string>(); if (il2Cpp.Version <= 22f || (methodDef.flags & METHOD_ATTRIBUTE_STATIC) == 0) { var thisType = ParseType(il2Cpp.types[typeDef.byrefTypeIndex]); parameterStrs.Add($"{thisType} __this"); } 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 parameterCType = ParseType(parameterType); if (parameterType.byref == 1) { parameterCType += "*"; } parameterStrs.Add($"{parameterCType} {FixName(parameterName)}"); } signature += string.Join(", ", parameterStrs); signature += ");"; scriptMethod.Signature = signature; } //泛型实例函数 if (il2Cpp.methodDefinitionMethodSpecs.TryGetValue(i, out var methodSpecs)) { foreach (var methodSpec in methodSpecs) { var genericMethodPointer = il2Cpp.methodSpecGenericMethodPointers[methodSpec]; if (genericMethodPointer > 0) { var scriptMethod = new ScriptMethod(); json.ScriptMethod.Add(scriptMethod); scriptMethod.Address = il2Cpp.GetRVA(genericMethodPointer); (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true); var methodFullName = methodSpecTypeName + "$$" + methodSpecMethodName; scriptMethod.Name = methodFullName; var genericContext = executor.GetMethodSpecGenericContext(methodSpec); var methodReturnType = il2Cpp.types[methodDef.returnType]; var returnType = ParseType(methodReturnType, genericContext); if (methodReturnType.byref == 1) { returnType += "*"; } var signature = $"{returnType} {FixName(methodFullName)} ("; var parameterStrs = new List <string>(); if (il2Cpp.Version <= 22f || (methodDef.flags & METHOD_ATTRIBUTE_STATIC) == 0) { string thisType; if (methodSpec.classIndexIndex != -1) { var typeBaseName = structNameDic[typeDef]; var typeToReplaceName = FixName(typeName); var typeReplaceName = FixName(methodSpecTypeName); var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName); var il2CppType = nameGenericClassDic[typeStructName]; thisType = ParseType(il2CppType); } else { thisType = ParseType(il2Cpp.types[typeDef.byrefTypeIndex]); } parameterStrs.Add($"{thisType} __this"); } 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 parameterCType = ParseType(parameterType, genericContext); if (parameterType.byref == 1) { parameterCType += "*"; } parameterStrs.Add($"{parameterCType} {FixName(parameterName)}"); } signature += string.Join(", ", parameterStrs); signature += ");"; scriptMethod.Signature = signature; } } } } } } // 处理MetadataUsage if (il2Cpp.Version > 16) { foreach (var i in metadata.metadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo { var type = il2Cpp.types[i.Value]; var typeName = executor.GetTypeName(type, true, false); var scriptMetadata = new ScriptMetadata(); json.ScriptMetadata.Add(scriptMetadata); scriptMetadata.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadata.Name = "Class$" + typeName; var signature = GetIl2CppStructName(type); if (signature.EndsWith("_array")) { scriptMetadata.Signature = signature + "*"; } else { scriptMetadata.Signature = FixName(signature) + "_c*"; } } foreach (var i in metadata.metadataUsageDic[2]) //kIl2CppMetadataUsageIl2CppType { var type = il2Cpp.types[i.Value]; var typeName = executor.GetTypeName(type, true, false); var scriptMetadata = new ScriptMetadata(); json.ScriptMetadata.Add(scriptMetadata); scriptMetadata.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadata.Name = "Object$" + typeName; var signature = GetIl2CppStructName(type); if (signature.EndsWith("_array")) { scriptMetadata.Signature = signature + "*"; } else { scriptMetadata.Signature = FixName(signature) + "_o*"; } } foreach (var i in metadata.metadataUsageDic[3]) //kIl2CppMetadataUsageMethodDef { var methodDef = metadata.methodDefs[i.Value]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = executor.GetTypeDefName(typeDef, true, true); var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()"; var scriptMetadataMethod = new ScriptMetadataMethod(); json.ScriptMetadataMethod.Add(scriptMetadataMethod); scriptMetadataMethod.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadataMethod.Name = "Method$" + methodName; var imageIndex = typeDefImageIndices[typeDef]; var methodPointer = il2Cpp.GetMethodPointer(methodDef, imageIndex); if (methodPointer > 0) { scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(methodPointer); } } foreach (var i in metadata.metadataUsageDic[4]) //kIl2CppMetadataUsageFieldInfo { var fieldRef = metadata.fieldRefs[i.Value]; var type = il2Cpp.types[fieldRef.typeIndex]; var typeDef = metadata.typeDefs[type.data.klassIndex]; var fieldDef = metadata.fieldDefs[typeDef.fieldStart + fieldRef.fieldIndex]; var fieldName = executor.GetTypeName(type, true, false) + "." + metadata.GetStringFromIndex(fieldDef.nameIndex); var scriptMetadata = new ScriptMetadata(); json.ScriptMetadata.Add(scriptMetadata); scriptMetadata.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadata.Name = "Field$" + fieldName; } foreach (var i in metadata.metadataUsageDic[5]) //kIl2CppMetadataUsageStringLiteral { var scriptString = new ScriptString(); json.ScriptString.Add(scriptString); scriptString.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptString.Value = metadata.GetStringLiteralFromIndex(i.Value); } var stringLiterals = json.ScriptString.Select(x => new { value = x.Value, address = $"0x{x.Address:X}" }).ToArray(); File.WriteAllText("stringliteral.json", JsonConvert.SerializeObject(stringLiterals, Formatting.Indented), new UTF8Encoding(false)); foreach (var i in metadata.metadataUsageDic[6]) //kIl2CppMetadataUsageMethodRef { var methodSpec = il2Cpp.methodSpecs[i.Value]; var scriptMetadataMethod = new ScriptMetadataMethod(); json.ScriptMetadataMethod.Add(scriptMetadataMethod); scriptMetadataMethod.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); (var methodSpecTypeName, var methodSpecMethodName) = executor.GetMethodSpecName(methodSpec, true); scriptMetadataMethod.Name = "Method$" + methodSpecTypeName + "." + methodSpecMethodName + "()"; var genericMethodPointer = il2Cpp.methodSpecGenericMethodPointers[methodSpec]; if (genericMethodPointer > 0) { scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(genericMethodPointer); } } } if (config.MakeFunction) { 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); orderedPointers.AddRange(il2Cpp.invokerPointers); orderedPointers.AddRange(il2Cpp.customAttributeGenerators); if (il2Cpp.Version >= 22) { if (il2Cpp.reversePInvokeWrappers != null) { orderedPointers.AddRange(il2Cpp.reversePInvokeWrappers); } if (il2Cpp.unresolvedVirtualCallPointers != null) { orderedPointers.AddRange(il2Cpp.unresolvedVirtualCallPointers); } } //TODO interopData内也包含函数 orderedPointers = orderedPointers.Distinct().OrderBy(x => x).ToList(); orderedPointers.Remove(0); for (int i = 0; i < orderedPointers.Count; i++) { orderedPointers[i] = il2Cpp.GetRVA(orderedPointers[i]); } json.Addresses = orderedPointers; } File.WriteAllText("script.json", JsonConvert.SerializeObject(json, Formatting.Indented)); //il2cpp.h for (int i = 0; i < genericClassList.Count; i++) { var pointer = genericClassList[i]; AddGenericClassStruct(pointer); } var preHeader = new StringBuilder(); var headerStruct = new StringBuilder(); var headerClass = new StringBuilder(); foreach (var info in structInfoList) { structInfoWithStructName.Add(info.TypeName + "_o", info); } foreach (var info in structInfoList) { preHeader.Append($"struct {info.TypeName}_o;\n"); if (info.IsValueType) { headerStruct.Append(RecursionStructInfo(info)); } else { headerClass.Append($"struct {info.TypeName}_StaticFields {{\n"); foreach (var field in info.StaticFields) { headerClass.Append($"\t{field.FieldTypeName} {field.FieldName};\n"); } headerClass.Append("};\n"); headerClass.Append($"struct {info.TypeName}_VTable {{\n"); foreach (var method in info.VTableMethod) { headerClass.Append($"\tVirtualInvokeData {method.MethodName};\n"); } headerClass.Append("};\n"); headerClass.Append($"struct {info.TypeName}_c {{\n" + $"\tIl2CppClass_1 _1;\n" + $"\t{info.TypeName}_StaticFields* static_fields;\n" + $"\tIl2CppClass_2 _2;\n" + $"\t{info.TypeName}_VTable vtable;\n" + $"}};\n"); headerClass.Append($"struct {info.TypeName}_o {{\n" + $"\t{info.TypeName}_c *klass;\n" + $"\tvoid *monitor;\n"); foreach (var field in info.Fields) { headerClass.Append($"\t{field.FieldTypeName} {field.FieldName};\n"); } headerClass.Append("};\n"); } } var sb = new StringBuilder(); if (il2Cpp is PE) { sb.Append(HeaderConstants.TypedefHeader); } sb.Append(HeaderConstants.GenericHeader); switch (il2Cpp.Version) { case 22f: sb.Append(HeaderConstants.HeaderV22); break; case 23f: case 24f: sb.Append(HeaderConstants.HeaderV240); break; case 24.1f: sb.Append(HeaderConstants.HeaderV241); break; case 24.2f: case 24.3f: sb.Append(HeaderConstants.HeaderV242); break; //TODO default: Console.WriteLine($"WARNING: This il2cpp version [{il2Cpp.Version}] does not support generating .h files"); return; } sb.Append(preHeader); sb.Append(arrayClassPreHeader); sb.Append(headerStruct); sb.Append(headerClass); sb.Append(arrayClassHeader); File.WriteAllText("il2cpp.h", sb.ToString()); }