private static bool Init(byte[] il2cppBytes, byte[] metadataBytes, string stringVersion, int mode, out Metadata metadata, out Il2Cpp il2Cpp) { var sanity = BitConverter.ToUInt32(metadataBytes, 0); if (sanity != 0xFAB11BAF) { throw new InvalidDataException("ERROR: Metadata file supplied is not valid metadata file."); } float fixedVersion; var metadataVersion = BitConverter.ToInt32(metadataBytes, 4); if (metadataVersion == 24) { if (stringVersion == null) { Console.WriteLine("Input Unity version: "); stringVersion = Console.ReadLine(); } try { var versionSplit = Array.ConvertAll(Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries), int.Parse); var unityVersion = new Version(versionSplit[0], versionSplit[1]); if (unityVersion >= Unity20201) { fixedVersion = 24.3f; } else if (unityVersion >= Unity20191) { fixedVersion = 24.2f; } else if (unityVersion >= Unity20183) { fixedVersion = 24.1f; } else { fixedVersion = metadataVersion; } } catch { throw new InvalidDataException("You must enter the correct Unity version number"); } } else { fixedVersion = metadataVersion; } Console.WriteLine("Initializing metadata..."); metadata = new Metadata(new MemoryStream(metadataBytes), fixedVersion); //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var isElf = false; var isPE = false; var is64bit = false; var isNSO = false; switch (il2cppMagic) { default: throw new NotSupportedException("ERROR: il2cpp file not supported."); case 0x304F534E: isNSO = true; is64bit = true; break; case 0x905A4D: //PE isPE = true; break; case 0x464c457f: //ELF isElf = true; if (il2cppBytes[4] == 2) //ELF64 { is64bit = true; } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O is64bit = true; break; case 0xFEEDFACE: // 32bit Mach-O break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version; Console.WriteLine("Initializing il2cpp file..."); var il2CppMemory = new MemoryStream(il2cppBytes); if (isNSO) { var nso = new NSO(il2CppMemory, version, metadata.maxMetadataUsages); il2Cpp = nso.UnCompress(); } else if (isPE) { il2Cpp = new PE(il2CppMemory, version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2Cpp = new Elf64(il2CppMemory, version, metadata.maxMetadataUsages); } else { il2Cpp = new Elf(il2CppMemory, version, metadata.maxMetadataUsages); } } else if (is64bit) { il2Cpp = new Macho64(il2CppMemory, version, metadata.maxMetadataUsages); } else { il2Cpp = new Macho(il2CppMemory, version, metadata.maxMetadataUsages); } if (mode == 0) { Console.WriteLine("Select Mode: 1.Manual 2.Auto"); var modeKey = Console.ReadKey(true); mode = int.Parse(modeKey.KeyChar.ToString()); } try { if (mode == 1) { 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); return(true); } else if (mode == 2) { Console.WriteLine("Searching..."); var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); if (!flag) { flag = il2Cpp.Search(); } if (!flag) { flag = il2Cpp.SymbolSearch(); } if (!flag) { Console.WriteLine("ERROR: Can't use auto mode to process file, try manual mode."); return(false); } } else { Console.WriteLine("ERROR: You have to choose a mode."); return(false); } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("ERROR: An error occurred while processing."); return(false); } return(true); }
private static bool Init(byte[] il2cppBytes, byte[] metadataBytes, out Metadata metadata, out Il2Cpp il2Cpp) { var sanity = BitConverter.ToUInt32(metadataBytes, 0); if (sanity != 0xFAB11BAF) { throw new InvalidDataException("ERROR: Metadata file supplied is not valid metadata file."); } Console.WriteLine("Initializing metadata..."); metadata = new Metadata(new MemoryStream(metadataBytes)); Console.WriteLine($"Metadata Version: {metadata.Version}"); //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var isElf = false; var isPE = false; var is64bit = false; var isNSO = false; var isRaw = false; var baseAddr = 0UL; switch (il2cppMagic) { default: //throw new NotSupportedException("ERROR: il2cpp file not supported."); Console.Write("Failed to recognize the format of il2cpp, processing it as raw memory file!"); isRaw = true; Console.Write("Enter base address (in hex, like 23c000): "); baseAddr = Convert.ToUInt64(Console.ReadLine(), 16); Console.WriteLine("Select the bit width:"); Console.WriteLine("1.32bit 2.64bit"); var k = Console.ReadKey(); var choice = int.Parse(k.KeyChar.ToString()) - 1; if (choice > 2 || choice < 0) { throw new InvalidDataException("ERROR: wrong bit width choice"); } is64bit = choice == 1; break; case 0x304F534E: isNSO = true; is64bit = true; break; case 0x905A4D: //PE isPE = true; break; case 0x464c457f: //ELF isElf = true; if (il2cppBytes[4] == 2) //ELF64 { is64bit = true; } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O is64bit = true; break; case 0xFEEDFACE: // 32bit Mach-O break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version; Console.WriteLine("Initializing il2cpp file..."); var il2CppMemory = new MemoryStream(il2cppBytes); if (isRaw) { il2Cpp = new Raw(il2CppMemory, baseAddr, is64bit, version, metadata.maxMetadataUsages); } else if (isNSO) { var nso = new NSO(il2CppMemory, version, metadata.maxMetadataUsages); il2Cpp = nso.UnCompress(); } else if (isPE) { il2Cpp = new PE(il2CppMemory, version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2Cpp = new Elf64(il2CppMemory, version, metadata.maxMetadataUsages); } else { il2Cpp = new Elf(il2CppMemory, version, metadata.maxMetadataUsages); } } else if (is64bit) { il2Cpp = new Macho64(il2CppMemory, version, metadata.maxMetadataUsages); } else { il2Cpp = new Macho(il2CppMemory, version, metadata.maxMetadataUsages); } Console.WriteLine($"Il2Cpp Version: {il2Cpp.Version}"); Console.WriteLine("Searching..."); try { var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); if (!flag) { flag = il2Cpp.Search(); } if (!flag) { flag = il2Cpp.SymbolSearch(); } if (!flag) { Console.WriteLine("ERROR: Can't use auto mode to process file, try manual mode."); 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); return(true); } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("ERROR: An error occurred while processing."); return(false); } return(true); }
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); } } }
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 = "ELF file or Mach-O 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 { metadata = new MetadataGeneric(new MemoryStream(File.ReadAllBytes(ofd.FileName))); //判断il2cpp的magic var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0); var isElf = false; var is64bit = false; switch (il2cppmagic) { default: throw new Exception("ERROR: il2cpp file not supported."); case 0x464c457f: //ELF isElf = true; goto case 0xFEEDFACE; case 0xCAFEBABE: //FAT header case 0xBEBAFECA: Console.WriteLine("WARNING: fat macho will only dump the first object file."); var fat = new MachoFat(new MemoryStream(il2cppfile)); il2cppfile = fat.GetFirstMacho(); var magic = fat.GetFirstMachoMagic(); if (magic == 0xFEEDFACF) // 64-bit mach object file { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64-bit mach object file is64bit = true; goto case 0xFEEDFACE; case 0xFEEDFACE: // 32-bit mach object file Console.WriteLine("Select Mode: 1. Manual 2.Auto"); var key = Console.ReadKey(true); if (key.KeyChar == '2') { if (isElf) { il2cpp = new Elf(new MemoryStream(il2cppfile), metadata.version, metadata.maxmetadataUsages); } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppfile), metadata.version, metadata.maxmetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppfile), metadata.version, metadata.maxmetadataUsages); } if (!il2cpp.Search()) { throw new Exception("ERROR: Unable to process file automatically, try to use manual mode."); } } else if (key.KeyChar == '1') { Console.Write("Input CodeRegistration(R0): "); var codeRegistration = Convert.ToUInt64(Console.ReadLine(), 16); Console.Write("Input MetadataRegistration(R1): "); var metadataRegistration = Convert.ToUInt64(Console.ReadLine(), 16); if (isElf) { il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, metadata.version, metadata.maxmetadataUsages); } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, metadata.version, metadata.maxmetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, metadata.version, metadata.maxmetadataUsages); } } else { return; } var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create)); Console.WriteLine("Dumping..."); //Script var scriptwriter = new StreamWriter(new FileStream("script.py", FileMode.Create)); scriptwriter.WriteLine(File.ReadAllText("ida")); // //dump_image(); for (var imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write( $"// Image {imageIndex}: {metadata.GetString(imageDef.nameIndex)} - {imageDef.typeStart}\n"); } for (var idx = 0; idx < metadata.uiNumTypes; ++idx) { try { //dump_class(i); var typeDef = metadata.typeDefs[idx]; writer.Write($"\n// Namespace: {metadata.GetString(typeDef.namespaceIndex)}\n"); writer.Write(GetCustomAttribute(typeDef.customAttributeIndex)); if ((typeDef.flags & TYPE_ATTRIBUTE_SERIALIZABLE) != 0) { writer.Write("[Serializable]\n"); } if ((typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if ((typeDef.flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NOT_PUBLIC) { writer.Write("internal "); } if ((typeDef.flags & TYPE_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } if ((typeDef.flags & TYPE_ATTRIBUTE_SEALED) != 0) { writer.Write("sealed "); } if ((typeDef.flags & TYPE_ATTRIBUTE_INTERFACE) != 0) { writer.Write("interface "); } else { writer.Write("class "); } writer.Write($"{metadata.GetString(typeDef.nameIndex)}"); if (typeDef.parentIndex >= 0) { var parent = il2cpp.types[typeDef.parentIndex]; var parentname = get_type_name(parent); if (parentname != "object") { writer.Write($" : {parentname}"); } } writer.Write($" // TypeDefIndex: {idx}\n{{\n"); 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 pField = metadata.fieldDefs[i]; var pType = il2cpp.types[pField.typeIndex]; var pDefault = metadata.GetFieldDefaultFromIndex(i); writer.Write(GetCustomAttribute(pField.customAttributeIndex, "\t")); writer.Write("\t"); if ((pType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == FIELD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } else if ((pType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == FIELD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if ((pType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == FIELD_ATTRIBUTE_FAMILY) { writer.Write("protected "); } if ((pType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((pType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } writer.Write( $"{get_type_name(pType)} {metadata.GetString(pField.nameIndex)}"); if (pDefault != null && pDefault.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex); if (pointer > 0) { var pTypeToUse = il2cpp.types[pDefault.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 = metadata.ReadChar(); 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) { writer.Write($" = \"{multi}\""); } else if (multi != null) { writer.Write($" = {multi}"); } } } writer.Write("; // 0x{0:x}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart, i)); } writer.Write("\n"); } if (config.dumpproperty && typeDef.property_count > 0) { //dump_property(i); 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]; var pReturnType = il2cpp.types[methodDef.returnType]; if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_FAMILY) { writer.Write("protected "); } if ((methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_VIRTUAL) != 0) { writer.Write("virtual "); } if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } writer.Write( $"{get_type_name(pReturnType)} {metadata.GetString(propertydef.nameIndex)} {{ "); } else if (propertydef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertydef.set]; if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_FAMILY) { writer.Write("protected "); } if ((methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_VIRTUAL) != 0) { writer.Write("virtual "); } if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } var pParam = metadata.parameterDefs[methodDef.parameterStart]; var pType = il2cpp.types[pParam.typeIndex]; writer.Write( $"{get_type_name(pType)} {metadata.GetString(propertydef.nameIndex)} {{ "); } if (propertydef.get >= 0) { writer.Write("get; "); } if (propertydef.set >= 0) { writer.Write("set; "); } writer.Write("}"); writer.Write("\n"); } writer.Write("\n"); } 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) { //dump_method(i); var methodDef = metadata.methodDefs[i]; writer.Write(GetCustomAttribute(methodDef.customAttributeIndex, "\t")); writer.Write("\t"); var pReturnType = il2cpp.types[methodDef.returnType]; if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_FAMILY) { writer.Write("protected "); } if ((methodDef.flags & METHOD_ATTRIBUTE_ABSTRACT) != 0) { writer.Write("abstract "); } else if ((methodDef.flags & METHOD_ATTRIBUTE_VIRTUAL) != 0) { writer.Write("virtual "); } if ((methodDef.flags & METHOD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } writer.Write( $"{get_type_name(pReturnType)} {metadata.GetString(methodDef.nameIndex)}("); for (var j = 0; j < methodDef.parameterCount; ++j) { var pParam = metadata.parameterDefs[methodDef.parameterStart + j]; var szParamName = metadata.GetString(pParam.nameIndex); var pType = il2cpp.types[pParam.typeIndex]; var szTypeName = get_type_name(pType); if ((pType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { writer.Write("optional "); } if ((pType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { writer.Write("out "); } if (j != methodDef.parameterCount - 1) { writer.Write($"{szTypeName} {szParamName}, "); } else { writer.Write($"{szTypeName} {szParamName}"); } } if (methodDef.methodIndex >= 0) { writer.Write("); // {0:x}\n", il2cpp.methodPointers[methodDef.methodIndex]); //Script var name = ToUnicodeString(metadata.GetString(typeDef.nameIndex) + "$$" + metadata.GetString(methodDef.nameIndex)); scriptwriter.WriteLine($"SetMethod(0x{il2cpp.methodPointers[methodDef.methodIndex]:x}, '{name}')"); // } else { writer.Write("); // 0\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 if (metadata.version > 16) { foreach (var i in metadata.stringLiteralsdic) { scriptwriter.WriteLine($"SetString(0x{il2cpp.metadataUsages[i.Key]:x}, '{ToUnicodeString(i.Value)}')"); } } // writer.Close(); scriptwriter.Close(); Console.WriteLine("Done !"); break; } } catch (Exception e) { Console.WriteLine($"{e.Message}\r\n{e.StackTrace}"); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(true); } } }
private static void Init(byte[] il2cppBytes, byte[] metadataBytes) { var sanity = BitConverter.ToUInt32(metadataBytes, 0); if (sanity != 0xFAB11BAF) { throw new Exception("ERROR: Metadata file supplied is not valid metadata file."); } var metadataVersion = (float)BitConverter.ToInt32(metadataBytes, 4); if (metadataVersion == 24) { Console.WriteLine("Is the Unity version greater than or equal to 2018.3?"); Console.WriteLine("1.Yes 2.No"); var key = Console.ReadKey(true); if (key.KeyChar == '1') { metadataVersion = 24.1f; } } Console.WriteLine("Initializing metadata..."); metadata = new Metadata(new MemoryStream(metadataBytes), metadataVersion); //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 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 (il2cppBytes[4] == 2) { goto case 0xFEEDFACF; //ELF64 } break; case 0xCAFEBABE: //FAT header case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = 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(il2cppBytes), version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2cpp = new Elf64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2cpp = new Elf(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } if (modeKey.KeyChar != '1') { Console.WriteLine("Searching..."); } 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."); } }
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 = "ELF file or Mach-O 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 { metadata = new Metadata(new MemoryStream(File.ReadAllBytes(ofd.FileName))); //判断il2cpp的magic var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0); var isElf = false; var is64bit = false; switch (il2cppmagic) { default: throw new Exception("ERROR: il2cpp file not supported."); case 0x464c457f: //ELF isElf = true; goto case 0xFEEDFACE; 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]; if (fat.magic == 0xFEEDFACF) //64-bit mach object file { Console.Write($"{i + 1}.64bit "); } else { Console.Write($"{i + 1}.32bit "); } } Console.WriteLine(); var key = Console.ReadKey(true); var index = int.Parse(key.KeyChar.ToString()) - 1; var magic = machofat.fats[index].magic; il2cppfile = machofat.GetMacho(index); if (magic == 0xFEEDFACF) // 64-bit mach object file { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64-bit mach object file is64bit = true; goto case 0xFEEDFACE; case 0xFEEDFACE: // 32-bit mach object file Console.WriteLine("Select Mode: 1.Manual 2.Auto 3.Auto(Advanced)"); key = Console.ReadKey(true); var version = config.forceil2cppversion ? config.forceversion : metadata.version; switch (key.KeyChar) { case '2': case '3': if (isElf) { 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 { if (key.KeyChar == '2' ? !il2cpp.Search() : !il2cpp.AdvancedSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0))) { throw new Exception(); } } catch { throw new Exception("ERROR: Unable to process file automatically, try to use other mode."); } break; case '1': { Console.Write("Input CodeRegistration(Parameter 0): "); var codeRegistration = Convert.ToUInt64(Console.ReadLine(), 16); Console.Write("Input MetadataRegistration(Parameter 1): "); var metadataRegistration = Convert.ToUInt64(Console.ReadLine(), 16); if (isElf) { il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, version, metadata.maxmetadataUsages); } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, version, metadata.maxmetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, version, metadata.maxmetadataUsages); } break; } default: return; } var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create), Encoding.UTF8); Console.WriteLine("Dumping..."); //Script var scriptwriter = new StreamWriter(new FileStream("script.py", FileMode.Create), Encoding.UTF8); scriptwriter.WriteLine(Resource1.ida); // //dump image; for (var imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++) { var imageDef = metadata.imageDefs[imageIndex]; writer.Write($"// Image {imageIndex}: {metadata.GetString(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 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 != "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.GetString(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; if (visibility == TYPE_ATTRIBUTE_PUBLIC || visibility == TYPE_ATTRIBUTE_NESTED_PUBLIC) { writer.Write("public "); } else if (visibility == TYPE_ATTRIBUTE_NOT_PUBLIC || visibility == TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM || visibility == TYPE_ATTRIBUTE_NESTED_ASSEMBLY) { writer.Write("internal "); } else if (visibility == TYPE_ATTRIBUTE_NESTED_PRIVATE) { writer.Write("private "); } else if (visibility == TYPE_ATTRIBUTE_NESTED_FAMILY) { writer.Write("protected "); } else if (visibility == TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM) { writer.Write("protected internal "); } 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 && (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 { writer.Write("class "); } writer.Write($"{metadata.GetString(typeDef.nameIndex)}"); if (extends.Count > 0) { writer.Write($" : {string.Join(", ", extends)}"); } writer.Write($" // TypeDefIndex: {idx}\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 pField = metadata.fieldDefs[i]; var pType = il2cpp.types[pField.typeIndex]; var pDefault = metadata.GetFieldDefaultFromIndex(i); writer.Write(GetCustomAttribute(pField.customAttributeIndex, "\t")); writer.Write("\t"); var access = pType.attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK; if (access == FIELD_ATTRIBUTE_PRIVATE) { writer.Write("private "); } else if (access == FIELD_ATTRIBUTE_PUBLIC) { writer.Write("public "); } else if (access == FIELD_ATTRIBUTE_FAMILY) { writer.Write("protected "); } else if (access == FIELD_ATTRIBUTE_ASSEMBLY || access == FIELD_ATTRIBUTE_FAM_AND_ASSEM) { writer.Write("internal "); } else if (access == FIELD_ATTRIBUTE_FAM_OR_ASSEM) { writer.Write("protected internal "); } if ((pType.attrs & FIELD_ATTRIBUTE_LITERAL) != 0) { writer.Write("const "); } else { if ((pType.attrs & FIELD_ATTRIBUTE_STATIC) != 0) { writer.Write("static "); } if ((pType.attrs & FIELD_ATTRIBUTE_INIT_ONLY) != 0) { writer.Write("readonly "); } } writer.Write($"{GetTypeName(pType)} {metadata.GetString(pField.nameIndex)}"); if (pDefault != null && pDefault.dataIndex != -1) { var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex); if (pointer > 0) { var pTypeToUse = il2cpp.types[pDefault.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 = metadata.ReadChar(); 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) { writer.Write($" = \"{multi}\""); } 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 pReturnType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(pReturnType)} {metadata.GetString(propertydef.nameIndex)} {{ "); } else if (propertydef.set > 0) { var methodDef = metadata.methodDefs[typeDef.methodStart + propertydef.set]; writer.Write(GetModifiers(methodDef)); var pParam = metadata.parameterDefs[methodDef.parameterStart]; var pType = il2cpp.types[pParam.typeIndex]; writer.Write($"{GetTypeName(pType)} {metadata.GetString(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 pReturnType = il2cpp.types[methodDef.returnType]; writer.Write($"{GetTypeName(pReturnType)} {metadata.GetString(methodDef.nameIndex)}("); for (var j = 0; j < methodDef.parameterCount; ++j) { var pParam = metadata.parameterDefs[methodDef.parameterStart + j]; var szParamName = metadata.GetString(pParam.nameIndex); var pType = il2cpp.types[pParam.typeIndex]; var szTypeName = GetTypeName(pType); if ((pType.attrs & PARAM_ATTRIBUTE_OPTIONAL) != 0) { writer.Write("optional "); } if ((pType.attrs & PARAM_ATTRIBUTE_OUT) != 0) { writer.Write("out "); } if (j != methodDef.parameterCount - 1) { writer.Write($"{szTypeName} {szParamName}, "); } else { writer.Write($"{szTypeName} {szParamName}"); } } if (methodDef.methodIndex >= 0) { writer.Write("); // 0x{0:X}\n", il2cpp.methodPointers[methodDef.methodIndex]); //Script var name = ToUnicodeString(metadata.GetString(typeDef.nameIndex) + "$$" + metadata.GetString(methodDef.nameIndex)); scriptwriter.WriteLine($"SetMethod(0x{il2cpp.methodPointers[methodDef.methodIndex]:x}, '{name}')"); // } else { writer.Write("); // 0\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 if (il2cpp.version > 16) { foreach (var i in metadata.stringLiteralsdic) { scriptwriter.WriteLine($"SetString(0x{il2cpp.metadataUsages[i.Key]:x}, '{ToUnicodeString(i.Value)}')"); } } // writer.Close(); scriptwriter.Close(); Console.WriteLine("Done !"); break; } } catch (Exception e) { Console.WriteLine($"{e.Message}\r\n{e.StackTrace}"); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(true); } } }
private static bool Init(string il2cppPath, string metadataPath, out Metadata metadata, out Il2Cpp il2Cpp) { Console.WriteLine("Initializing metadata..."); var metadataBytes = File.ReadAllBytes(metadataPath); metadata = new Metadata(new MemoryStream(metadataBytes)); Console.WriteLine($"Metadata Version: {metadata.Version}"); Console.WriteLine("Initializing il2cpp file..."); var il2cppBytes = File.ReadAllBytes(il2cppPath); var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var il2CppMemory = new MemoryStream(il2cppBytes); switch (il2cppMagic) { default: throw new NotSupportedException("ERROR: il2cpp file not supported."); case 0x6D736100: var web = new WebAssembly(il2CppMemory); il2Cpp = web.CreateMemory(); break; case 0x304F534E: var nso = new NSO(il2CppMemory); il2Cpp = nso.UnCompress(); break; case 0x905A4D: //PE il2Cpp = new PE(il2CppMemory); break; case 0x464c457f: //ELF if (il2cppBytes[4] == 2) //ELF64 { il2Cpp = new Elf64(il2CppMemory); } else { il2Cpp = new Elf(il2CppMemory); } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); il2CppMemory = new MemoryStream(il2cppBytes); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O il2Cpp = new Macho64(il2CppMemory); break; case 0xFEEDFACE: // 32bit Mach-O il2Cpp = new Macho(il2CppMemory); break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version; il2Cpp.SetProperties(version, metadata.maxMetadataUsages); Console.WriteLine($"Il2Cpp Version: {il2Cpp.Version}"); if (il2Cpp.Version >= 27 && il2Cpp is ElfBase elf && elf.IsDumped) { Console.WriteLine("Input global-metadata.dat dump address:"); metadata.Address = Convert.ToUInt64(Console.ReadLine(), 16); } Console.WriteLine("Searching..."); try { var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (!flag && il2Cpp is PE) { Console.WriteLine("Use custom PE loader"); il2Cpp = PELoader.Load(il2cppPath); il2Cpp.SetProperties(version, metadata.maxMetadataUsages); flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length); } } if (!flag) { flag = il2Cpp.Search(); } if (!flag) { flag = il2Cpp.SymbolSearch(); } if (!flag) { Console.WriteLine("ERROR: Can't use auto mode to process file, try manual mode."); 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); return(true); } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("ERROR: An error occurred while processing."); return(false); } return(true); }
private static void Init(byte[] il2cppBytes, byte[] metadataBytes) { var sanity = BitConverter.ToUInt32(metadataBytes, 0); if (sanity != 0xFAB11BAF) { throw new Exception("ERROR: Metadata file supplied is not valid metadata file."); } float fixedMetadataVersion; var metadataVersion = BitConverter.ToInt32(metadataBytes, 4); if (metadataVersion == 24) { Console.WriteLine("Input Unity version (Just enter the first two numbers eg. *.*, ****.*): "); var str = Console.ReadLine(); try { var strs = Array.ConvertAll(str.Split('.'), int.Parse); var unityVersion = new Version(strs[0], strs[1]); if (unityVersion >= Unity20191) { fixedMetadataVersion = 24.2f; } else if (unityVersion >= Unity20183) { fixedMetadataVersion = 24.1f; } else { fixedMetadataVersion = metadataVersion; } } catch { throw new Exception("You must enter the correct Unity version number"); } } else { fixedMetadataVersion = metadataVersion; } Console.WriteLine("Initializing metadata..."); metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion); //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var isElf = false; var isPE = false; var is64bit = false; var isNSO = false; switch (il2cppMagic) { default: throw new Exception("ERROR: il2cpp file not supported."); case 0x304F534E: isNSO = true; is64bit = true; break; case 0x905A4D: //PE isPE = true; break; case 0x464c457f: //ELF isElf = true; if (il2cppBytes[4] == 2) //ELF64 { is64bit = true; } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O is64bit = true; break; case 0xFEEDFACE: // 32bit Mach-O break; } Console.WriteLine("Select Mode: 1.Manual 2.Auto 3.Auto(Plus) 4.Auto(Symbol)"); var modeKey = Console.ReadKey(true); var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.version; Console.WriteLine("Initializing il2cpp file..."); if (isNSO) { var nso = new NSO(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); il2cpp = nso.UnCompress(); } else if (isPE) { il2cpp = new PE(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2cpp = new Elf64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2cpp = new Elf(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } } else if (is64bit) { il2cpp = new Macho64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2cpp = new Macho(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } if (modeKey.KeyChar != '1') { Console.WriteLine("Searching..."); } 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(Plus) flag = il2cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); break; case '4': //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."); } }
private static bool Init(string il2cppPath, string metadataPath, string nameTranslationPath, out Metadata metadata, out Il2Cpp il2Cpp) { Console.WriteLine("Initializing metadata..."); var metadataBytes = File.ReadAllBytes(metadataPath); var stringDecryptionInfo = MetadataDecryption.DecryptMetadata(metadataBytes); metadata = new Metadata(new MemoryStream(metadataBytes), stringDecryptionInfo, nameTranslationPath); Console.WriteLine($"Metadata Version: {metadata.Version}"); Console.WriteLine("Initializing il2cpp file..."); var il2cppBytes = File.ReadAllBytes(il2cppPath); var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var il2CppMemory = new MemoryStream(il2cppBytes); switch (il2cppMagic) { default: throw new NotSupportedException("ERROR: il2cpp file not supported."); case 0x6D736100: var web = new WebAssembly(il2CppMemory); il2Cpp = web.CreateMemory(); break; case 0x304F534E: var nso = new NSO(il2CppMemory); il2Cpp = nso.UnCompress(); break; case 0x905A4D: //PE il2Cpp = new PE(il2CppMemory); break; case 0x464c457f: //ELF if (il2cppBytes[4] == 2) //ELF64 { il2Cpp = new Elf64(il2CppMemory); } else { il2Cpp = new Elf(il2CppMemory); } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); il2CppMemory = new MemoryStream(il2cppBytes); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O il2Cpp = new Macho64(il2CppMemory); break; case 0xFEEDFACE: // 32bit Mach-O il2Cpp = new Macho(il2CppMemory); break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version; il2Cpp.SetProperties(version, metadata.maxMetadataUsages); Console.WriteLine($"Il2Cpp Version: {il2Cpp.Version}"); if (il2Cpp.Version >= 27 && il2Cpp is ElfBase elf && elf.IsDumped) { Console.WriteLine("Input global-metadata.dat dump address:"); metadata.Address = Convert.ToUInt64(Console.ReadLine(), 16); } Console.WriteLine("Searching..."); try { //var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); var flag = false; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (!flag && il2Cpp is PE) { Console.WriteLine("Use custom PE loader"); il2Cpp = PELoader.Load(il2cppPath); il2Cpp.SetProperties(version, metadata.maxMetadataUsages); //flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); } } /*if (!flag) * { * flag = il2Cpp.Search(); * } * if (!flag) * { * flag = il2Cpp.SymbolSearch(); * }*/ if (true) { /*Console.WriteLine("ERROR: Can't use auto mode to process file, try manual mode."); * Console.Write("Input CodeRegistration: "); * var codeRegistration = Convert.ToUInt64(Console.ReadLine(), 16); * Console.Write("Input MetadataRegistration: "); * var metadataRegistration = Convert.ToUInt64(Console.ReadLine(), 16);*/ ProcessModuleCollection pms = Process.GetCurrentProcess().Modules; ulong baseaddr = 0; ProcessModule targetModule = null; foreach (ProcessModule pm in pms) { if (pm.ModuleName == "UserAssembly.dll") { baseaddr = (ulong)pm.BaseAddress; targetModule = pm; break; } } Console.WriteLine("baseadr: 0x" + baseaddr.ToString("x2")); ulong codeRegistration = 0; ulong metadataRegistration = 0; // custom search // searching .text for the following pattern: // lea r8, [rip+0x????????] // lea rdx, [rip+0x????????] // lea rcx, [rip+0x????????] // jmp [rip+0x????????] // or... // 4c 8d 05 ?? ?? ?? ?? // 48 8d 15 ?? ?? ?? ?? // 48 8d 0d ?? ?? ?? ?? // e9 // 22 bytes long // .text is always the first section var text_start = ((PE)il2Cpp).Sections[0].VirtualAddress + baseaddr; var text_end = text_start + ((PE)il2Cpp).Sections[0].VirtualSize; // functions are always aligned to 16 bytes const int patternLength = 22; byte[] d = new byte[patternLength]; for (ulong ptr = text_start; ptr < text_end - patternLength; ptr += 0x10) { Marshal.Copy((IntPtr)ptr, d, 0, patternLength); if ( d[0] == 0x4C && d[1] == 0x8D && d[2] == 0x05 && d[7] == 0x48 && d[8] == 0x8D && d[9] == 0x15 && d[14] == 0x48 && d[15] == 0x8D && d[16] == 0x0D && d[21] == 0xE9 ) { codeRegistration = ptr + 21 + BitConverter.ToUInt32(d, 14 + 3); metadataRegistration = ptr + 14 + BitConverter.ToUInt32(d, 7 + 3); Console.WriteLine($"Found the offsets! codeRegistration: 0x{(codeRegistration - baseaddr).ToString("X2")}, metadataRegistration: 0x{(metadataRegistration - baseaddr).ToString("X2")}"); break; } } if (codeRegistration == 0 && metadataRegistration == 0) { Console.WriteLine("Failed to find CodeRegistration and MetadataRegistration, go yell at Khang"); return(false); } il2Cpp.Init(codeRegistration, metadataRegistration); return(true); } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("ERROR: An error occurred while processing."); return(false); } return(true); }
private bool Init(string il2cppPath, string metadataPath, out Metadata metadata, out Il2Cpp il2Cpp) { string Mach_O = "2"; Invoke(new Action(delegate() { if (!use64bitMach_O) { Mach_O = "1"; } })); this.Log("Read config..."); if (File.Exists(realPath + "config.json")) { config = JsonConvert.DeserializeObject <Config>(File.ReadAllText(Application.StartupPath + Path.DirectorySeparatorChar + @"config.json")); } else { config = new Config(); Log("config.json file does not exist. Using defaults", Color.Yellow); } this.Log("Initializing metadata..."); var metadataBytes = File.ReadAllBytes(metadataPath); metadata = new Metadata(new MemoryStream(metadataBytes)); this.Log($"Metadata Version: {metadata.Version}"); this.Log("Initializing il2cpp file..."); var il2cppBytes = File.ReadAllBytes(il2cppPath); var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var il2CppMemory = new MemoryStream(il2cppBytes); switch (il2cppMagic) { default: throw new NotSupportedException("ERROR: il2cpp file not supported."); case 0x6D736100: var web = new WebAssembly(il2CppMemory); il2Cpp = web.CreateMemory(); break; case 0x304F534E: var nso = new NSO(il2CppMemory); il2Cpp = nso.UnCompress(); break; case 0x905A4D: //PE il2Cpp = new PE(il2CppMemory); break; case 0x464c457f: //ELF if (il2cppBytes[4] == 2) //ELF64 { il2Cpp = new Elf64(il2CppMemory); } else { il2Cpp = new Elf(il2CppMemory); } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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 "); } var index = int.Parse(Mach_O) - 1; var magic = machofat.fats[index % 2].magic; il2cppBytes = machofat.GetMacho(index % 2); il2CppMemory = new MemoryStream(il2cppBytes); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O il2Cpp = new Macho64(il2CppMemory); break; case 0xFEEDFACE: // 32bit Mach-O il2Cpp = new Macho(il2CppMemory); break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.Version; il2Cpp.SetProperties(version, metadata.maxMetadataUsages); this.Log($"Il2Cpp Version: {il2Cpp.Version}"); if (il2Cpp.Version >= 27 && il2Cpp is ElfBase elf && elf.IsDumped) { FormDump form = new FormDump(); form.dumpNoteLbl.Text = "Input global-metadata.dat dump address:"; form.Message = 0; if (form.ShowDialog() == DialogResult.OK) { metadata.Address = Convert.ToUInt64(form.ReturnedText, 16); this.Log("Inputted address: " + metadata.Address.ToString("X")); } } this.Log("Searching..."); try { var flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (!flag && il2Cpp is PE) { this.Log("Use custom PE loader"); il2Cpp = PELoader.Load(il2cppPath); il2Cpp.SetProperties(version, metadata.maxMetadataUsages); flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length, metadata.imageDefs.Length); } } if (!flag) { flag = il2Cpp.Search(); } if (!flag) { flag = il2Cpp.SymbolSearch(); } if (!flag) { Log("ERROR: Can't use auto mode to process file, input offset pointers to try manual mode.", Color.Yellow); var codeRegistration = Convert.ToUInt64(CodeRegistrationTxtBox.Text, 16); var metadataRegistration = Convert.ToUInt64(metadataRegistrationTxtBox.Text, 16); il2Cpp.Init(codeRegistration, metadataRegistration); return(true); } } catch (Exception ex) { Log("An error occurred while processing.", Color.Orange); Log(ex.ToString(), Color.Orange); return(false); } return(true); }
private static bool Init(byte[] il2cppBytes, byte[] metadataBytes, string stringVersion, int mode, out Metadata metadata, out Il2Cpp il2Cpp, string[] args) { var sanity = BitConverter.ToUInt32(metadataBytes, 0); if (sanity != 0xFAB11BAF) { throw new Exception("ERROR: Metadata file supplied is not valid metadata file."); } float fixedMetadataVersion; var metadataVersion = BitConverter.ToInt32(metadataBytes, 4); if (metadataVersion == 24) { if (stringVersion == null) { Console.WriteLine("Input Unity version: "); stringVersion = Console.ReadLine(); } try { var versionSplit = Array.ConvertAll(Regex.Replace(stringVersion, @"\D", ".").Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries), int.Parse); var unityVersion = new Version(versionSplit[0], versionSplit[1]); if (unityVersion >= Unity20191) { fixedMetadataVersion = 24.2f; } else if (unityVersion >= Unity20183) { fixedMetadataVersion = 24.1f; } else { fixedMetadataVersion = metadataVersion; } } catch { throw new Exception("You must enter the correct Unity version number"); } } else { fixedMetadataVersion = metadataVersion; } Console.WriteLine("Initializing metadata..."); #if DEBUG_0 int sw = 0; #elif DEBUG_1 int sw = 1; #elif DEBUG_2 int sw = 2; #elif DEBUG_3 int sw = 3; #endif switch (sw) { case 1: metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion, "lobbylist.php?format=json-signed-unix&version=2&minimal=1", "serverlist/lobbylist.php?format=json-signed-unix&version=2&minimal=1" /*"serverlist?format=json-signed-unix&version=2&minimal=1"/*"serverlist/lobbylist.php"/*"serverlist?format=json-signed-unix&version=2&minimal=1"*/, "global-metadata2.dat"); break; case 2: metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion, "https://api.scpslgame.com/", "https://api.southwoodstudios.com/", "global-metadata3.dat"); break; case 3: metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion, "-----BEGIN PUBLIC KEY-----\r\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAmxZRMP03JfPEP/qt7n34Ryi74CDe\r\nRZy4er5dQynKaQ3vl1F4VRsSGN+jBrZPcX3GB2u0OTXNUA8hcIDRhVb+GgYAcDmY\r\n+7utHYAZBK3APSxGn46p1+IAChsgl9r93bQz7AJVxxWHYKEA78jMVz6qKHlqKc6a\r\nkUswVSYosQGvw/Agzb0=\r\n-----END PUBLIC KEY-----", "-----BEGIN PUBLIC KEY-----\r\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEqCycYK8K5jJlNoQPqIpADxUrWwTR\r\nudWDIbw/VSJzKb7NMeeQfKsvq1Wd8A+7bzx21pVGS3UYrgJfC3bS5rtsMA==\r\n-----END PUBLIC KEY-----", "global-metadata4.dat"); break; default: metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion, ".scpslgame.com/", ".southwoodstudios.com/", "global-metadata.dat"); //metadata = new Metadata(new MemoryStream(metadataBytes), fixedMetadataVersion, "https://test.scpslgame.com/", "https://test.scpslgame.com/", "global-metadata.dat"); break; } //判断il2cpp的magic var il2cppMagic = BitConverter.ToUInt32(il2cppBytes, 0); var isElf = false; var isPE = false; var is64bit = false; var isNSO = false; switch (il2cppMagic) { default: throw new Exception("ERROR: il2cpp file not supported."); case 0x304F534E: isNSO = true; is64bit = true; break; case 0x905A4D: //PE isPE = true; break; case 0x464c457f: //ELF isElf = true; if (il2cppBytes[4] == 2) //ELF64 { is64bit = true; } break; case 0xCAFEBABE: //FAT Mach-O case 0xBEBAFECA: var machofat = new MachoFat(new MemoryStream(il2cppBytes)); 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; il2cppBytes = machofat.GetMacho(index % 2); if (magic == 0xFEEDFACF) { goto case 0xFEEDFACF; } else { goto case 0xFEEDFACE; } case 0xFEEDFACF: // 64bit Mach-O is64bit = true; break; case 0xFEEDFACE: // 32bit Mach-O break; } var version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.version; Console.WriteLine("Initializing il2cpp file..."); if (isNSO) { var nso = new NSO(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); il2Cpp = nso.UnCompress(); } else if (isPE) { il2Cpp = new PE(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else if (isElf) { if (is64bit) { il2Cpp = new Elf64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2Cpp = new Elf(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } } else if (is64bit) { il2Cpp = new Macho64(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } else { il2Cpp = new Macho(new MemoryStream(il2cppBytes), version, metadata.maxMetadataUsages); } if (mode == 0) { Console.WriteLine("Select Mode: 1.Manual 2.Auto 3.Auto(Plus) 4.Auto(Symbol)"); var modeKey = Console.ReadKey(true); mode = int.Parse(modeKey.KeyChar.ToString()); } if (mode != 1) { Console.WriteLine("Searching..."); } try { bool flag; switch (mode) { 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(Plus) flag = il2Cpp.PlusSearch(metadata.methodDefs.Count(x => x.methodIndex >= 0), metadata.typeDefs.Length); break; case 4: //Auto(Symbol) flag = il2Cpp.SymbolSearch(); break; default: Console.WriteLine("ERROR: You have to choose a mode."); return(false); } if (!flag) { throw new Exception(); } } catch { throw new Exception("ERROR: Can't use this mode to process file, try another mode."); } return(true); }
public IL2CppDump(Stream il2cppStream, Stream metaStream, Config config = null) { metadata = new Metadata(metaStream); this.config = config ?? new Config(); var buffer = new byte[5]; il2cppStream.Read(buffer, 0, 5); il2cppStream.Seek(0, SeekOrigin.Begin); int version = config.ForceIl2CppVersion ? config.ForceVersion : metadata.version; uint magic = BitConverter.ToUInt32(buffer, 0); checkMagic: switch (magic) { case PE: il2cpp = new PE(il2cppStream, version, metadata.maxMetadataUsages); break; case ELF: if (buffer[4] == 2) { il2cpp = new Elf64(il2cppStream, version, metadata.maxMetadataUsages); } else { il2cpp = new Elf(il2cppStream, version, metadata.maxMetadataUsages); } break; case FAT: case FAT_LE: var machofat = new MachoFat(il2cppStream); int index = 0; uint preferredMagic = 0; switch (this.config.PreferredMachoVersion) { case MachoVersion.Macho32: preferredMagic = MACHO_32; break; case MachoVersion.Macho64: preferredMagic = MACHO_64; break; } for (int i = 0; i < machofat.fats.Length; i++) { if (machofat.fats[i].magic == preferredMagic) { index = i; magic = preferredMagic; break; } } Stream fatStream = il2cppStream; il2cppStream = new MemoryStream(machofat.GetMacho(index)); fatStream.Close(); goto checkMagic; case MACHO_64: il2cpp = new Macho64(il2cppStream, version, metadata.maxMetadataUsages); break; case MACHO_32: il2cpp = new Macho(il2cppStream, version, metadata.maxMetadataUsages); break; default: throw new InvalidDataException("Unknown IL2Cpp binary format."); } }