private string AttributeDataToString(BlobValue blobValue) { //TODO enum if (blobValue.Value == null) { return("null"); } switch (blobValue.il2CppTypeEnum) { case Il2CppTypeEnum.IL2CPP_TYPE_STRING: return($"\"{blobValue.Value}\""); case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY: var array = (BlobValue[])blobValue.Value; var list = new List <string>(); foreach (var item in array) { list.Add(AttributeDataToString(item)); } return($"new[] {{ {string.Join(", ", list)} }}"); case Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX: var il2CppType = (Il2CppType)blobValue.Value; return($"typeof({executor.GetTypeName(il2CppType, false, false)})"); default: return(blobValue.Value.ToString()); } }
// 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 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]; CreateStructNameDic(typeDef); } } 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); typeDefImageIndices.Add(typeDef, imageIndex); 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.methodIndex, i, imageIndex, methodDef.token); 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); var signature = $"{returnType} {FixName(methodFullName)} ("; var parameterStrs = new List <string>(); if ((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]; parameterStrs.Add($"{ParseType(parameterType)} {FixName(parameterName)}"); } signature += string.Join(", ", parameterStrs); signature += ");"; scriptMethod.Signature = signature; } } } } 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.methodIndex, (int)i.Value, imageIndex, methodDef.token); 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 methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = executor.GetTypeDefName(typeDef, true, false); if (methodSpec.classIndexIndex != -1) { var classInst = il2Cpp.genericInsts[methodSpec.classIndexIndex]; typeName += executor.GetGenericInstParams(classInst); } var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex); if (methodSpec.methodIndexIndex != -1) { var methodInst = il2Cpp.genericInsts[methodSpec.methodIndexIndex]; methodName += executor.GetGenericInstParams(methodInst); } methodName += "()"; 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.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token); if (methodPointer > 0) { scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(methodPointer); } } } 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); 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: sb.Append(HeaderConstants.HeaderV240); break; case 24f: sb.Append(HeaderConstants.HeaderV240); break; case 24.1f: sb.Append(HeaderConstants.HeaderV241); break; case 24.2f: 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()); }
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 void WriteScript(string outputDir) { 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); if (genericClass.typeDefinitionIndex == 4294967295 || genericClass.typeDefinitionIndex == -1) { continue; } 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 methodInfoName = $"MethodInfo_{typeIndex}"; var structTypeName = structNameDic[typeDef]; GenerateMethodInfo(structTypeName, methodInfoName); 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 ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) == 0) { var thisType = ParseType(il2Cpp.types[typeDef.byrefTypeIndex]); parameterStrs.Add($"{thisType} __this"); } else if (il2Cpp.Version <= 24f) { parameterStrs.Add($"Il2CppObject* __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)}"); } parameterStrs.Add("const MethodInfo* method"); 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 ((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); if (nameGenericClassDic.TryGetValue(typeStructName, out var il2CppType)) { thisType = ParseType(il2CppType); } else { //没有单独的泛型实例类 thisType = ParseType(il2Cpp.types[typeDef.byrefTypeIndex]); } } else { thisType = ParseType(il2Cpp.types[typeDef.byrefTypeIndex]); } parameterStrs.Add($"{thisType} __this"); } else if (il2Cpp.Version <= 24f) { parameterStrs.Add($"Il2CppObject* __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)}"); } parameterStrs.Add($"const {methodInfoName}* method"); 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(outputDir + "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); } } } 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(outputDir + "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"); headerStruct.Append(RecursionStructInfo(info)); } var sb = new StringBuilder(); 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); sb.Append(methodInfoHeader); File.WriteAllText(outputDir + "il2cpp.h", sb.ToString()); }
public void WriteScript(Config config) { var writer = new StreamWriter(new FileStream("ida.py", FileMode.Create), new UTF8Encoding(false)); writer.WriteLine("# -*- coding: utf-8 -*-"); writer.WriteLine("import idaapi"); writer.WriteLine(); writer.WriteLine("def SetString(addr, comm):"); writer.WriteLine("\tglobal index"); writer.WriteLine("\tname = \"StringLiteral_\" + str(index)"); writer.WriteLine("\tret = idc.set_name(addr, name, SN_NOWARN)"); writer.WriteLine("\tidc.set_cmt(addr, comm, 1)"); writer.WriteLine("\tindex += 1"); writer.WriteLine(); writer.WriteLine("def SetName(addr, name):"); writer.WriteLine("\tret = idc.set_name(addr, name, SN_NOWARN | SN_NOCHECK)"); writer.WriteLine("\tif ret == 0:"); writer.WriteLine("\t\tnew_name = name + '_' + str(addr)"); writer.WriteLine("\t\tret = idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)"); writer.WriteLine(); writer.WriteLine("def MakeFunction(start, end):"); writer.WriteLine("\tnext_func = idc.get_next_func(start)"); writer.WriteLine("\tif next_func < end:"); writer.WriteLine("\t\tend = next_func"); writer.WriteLine("\tif idc.get_func_attr(start, FUNCATTR_START) == start:"); writer.WriteLine("\t\tida_funcs.del_func(start)"); writer.WriteLine("\tida_funcs.add_func(start, end)"); writer.WriteLine(); writer.WriteLine("index = 1"); writer.WriteLine("print('Making method name...')"); 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]; var typeName = executor.GetTypeDefName(typeDef, false, true); typeDefImageIndices.Add(typeDef, imageIndex); 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.methodIndex, i, imageIndex, methodDef.token); if (methodPointer > 0) { var fixedMethodPointer = il2Cpp.FixPointer(methodPointer); if (il2Cpp is PE) { writer.WriteLine($"SetName(0x{methodPointer:X}, '{typeName + "$$" + methodName}')"); } else { writer.WriteLine($"SetName(0x{fixedMethodPointer:X}, '{typeName + "$$" + methodName}')"); } } } } } writer.WriteLine("print('Make method name done')"); if (il2Cpp.Version > 16) { writer.WriteLine("print('Setting MetadataUsage...')"); foreach (var i in metadata.metadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo { var type = il2Cpp.types[i.Value]; var typeName = executor.GetTypeName(type, true, true); writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')"); writer.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 = executor.GetTypeName(type, true, true); writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Class$" + typeName}')"); writer.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 = executor.GetTypeDefName(typeDef, true, true); var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex) + "()"; writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')"); writer.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); writer.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 = executor.GetTypeName(type, true, true) + "." + metadata.GetStringFromIndex(fieldDef.nameIndex); writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Field$" + fieldName}')"); writer.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)); //TODO foreach (var stringLiteral in stringLiterals) { writer.WriteLine($"SetString({stringLiteral.address}, r'{stringLiteral.value.ToEscapedString()}')"); } 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 = executor.GetTypeDefName(typeDef, true, false); if (methodSpec.classIndexIndex != -1) { var classInst = il2Cpp.genericInsts[methodSpec.classIndexIndex]; typeName += executor.GetGenericInstParams(classInst); } var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex); if (methodSpec.methodIndexIndex != -1) { var methodInst = il2Cpp.genericInsts[methodSpec.methodIndexIndex]; methodName += executor.GetGenericInstParams(methodInst); } methodName += "()"; writer.WriteLine($"SetName(0x{il2Cpp.metadataUsages[i.Key]:X}, '{"Method$" + methodName}')"); writer.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); writer.WriteLine($"idc.set_cmt(0x{il2Cpp.metadataUsages[i.Key]:X}, '0x{methodPointer:X}', 0)"); } writer.WriteLine("print('Set MetadataUsage done')"); } 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); writer.WriteLine("print('Making function...')"); for (int i = 0; i < orderedPointers.Count - 1; i++) { writer.WriteLine($"MakeFunction(0x{orderedPointers[i]:X}, 0x{orderedPointers[i + 1]:X})"); } writer.WriteLine("print('Make function done, please wait for IDA to complete the analysis')"); } writer.WriteLine("print('Script finished!')"); 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 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]; var typeName = executor.GetTypeDefName(typeDef, false, true); typeDefImageIndices.Add(typeDef, imageIndex); 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.methodIndex, i, imageIndex, methodDef.token); if (methodPointer > 0) { var scriptMethod = new ScriptMethod(); json.ScriptMethod.Add(scriptMethod); scriptMethod.Address = il2Cpp.GetRVA(methodPointer); scriptMethod.Name = typeName + "$$" + methodName; } } } } if (il2Cpp.Version > 16) { foreach (var i in metadata.metadataUsageDic[1]) //kIl2CppMetadataUsageTypeInfo { var type = il2Cpp.types[i.Value]; var typeName = executor.GetTypeName(type, true, true); var scriptMetadata = new ScriptMetadata(); json.ScriptMetadata.Add(scriptMetadata); scriptMetadata.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadata.Name = "Class$" + typeName; } foreach (var i in metadata.metadataUsageDic[2]) //kIl2CppMetadataUsageIl2CppType { var type = il2Cpp.types[i.Value]; var typeName = executor.GetTypeName(type, true, true); var scriptMetadata = new ScriptMetadata(); json.ScriptMetadata.Add(scriptMetadata); scriptMetadata.Address = il2Cpp.GetRVA(il2Cpp.metadataUsages[i.Key]); scriptMetadata.Name = "Class$" + typeName; } 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.methodIndex, (int)i.Value, imageIndex, methodDef.token); 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, true) + "." + 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 methodDef = metadata.methodDefs[methodSpec.methodDefinitionIndex]; var typeDef = metadata.typeDefs[methodDef.declaringType]; var typeName = executor.GetTypeDefName(typeDef, true, false); if (methodSpec.classIndexIndex != -1) { var classInst = il2Cpp.genericInsts[methodSpec.classIndexIndex]; typeName += executor.GetGenericInstParams(classInst); } var methodName = typeName + "." + metadata.GetStringFromIndex(methodDef.nameIndex); if (methodSpec.methodIndexIndex != -1) { var methodInst = il2Cpp.genericInsts[methodSpec.methodIndexIndex]; methodName += executor.GetGenericInstParams(methodInst); } methodName += "()"; 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.methodIndex, methodSpec.methodDefinitionIndex, imageIndex, methodDef.token); if (methodPointer > 0) { scriptMetadataMethod.MethodAddress = il2Cpp.GetRVA(methodPointer); } } } 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); 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)); }