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, 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); 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, 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 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, imageIndex); 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) { 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()); }
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)); }