277 lines
10 KiB
C#
277 lines
10 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.Json;
|
|
|
|
namespace Il2CppDumper
|
|
{
|
|
class Program
|
|
{
|
|
private static Config config;
|
|
|
|
[STAThread]
|
|
static void Main(string[] args)
|
|
{
|
|
config = JsonSerializer.Deserialize<Config>(File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + @"config.json"));
|
|
string il2cppPath = null;
|
|
string metadataPath = null;
|
|
string outputDir = null;
|
|
|
|
if (args.Length == 1)
|
|
{
|
|
if (args[0] == "-h" || args[0] == "--help" || args[0] == "/?" || args[0] == "/h")
|
|
{
|
|
ShowHelp();
|
|
return;
|
|
}
|
|
}
|
|
if (args.Length > 3)
|
|
{
|
|
ShowHelp();
|
|
return;
|
|
}
|
|
if (args.Length > 1)
|
|
{
|
|
foreach (var arg in args)
|
|
{
|
|
if (File.Exists(arg))
|
|
{
|
|
var file = File.ReadAllBytes(arg);
|
|
if (BitConverter.ToUInt32(file, 0) == 0xFAB11BAF)
|
|
{
|
|
metadataPath = arg;
|
|
}
|
|
else
|
|
{
|
|
il2cppPath = arg;
|
|
}
|
|
}
|
|
else if (Directory.Exists(arg))
|
|
{
|
|
outputDir = Path.GetFullPath(arg) + Path.DirectorySeparatorChar;
|
|
}
|
|
}
|
|
}
|
|
outputDir ??= AppDomain.CurrentDomain.BaseDirectory;
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
if (il2cppPath == null)
|
|
{
|
|
var ofd = new OpenFileDialog
|
|
{
|
|
Filter = "Il2Cpp binary file|*.*"
|
|
};
|
|
if (ofd.ShowDialog())
|
|
{
|
|
il2cppPath = ofd.FileName;
|
|
ofd.Filter = "global-metadata|global-metadata.dat";
|
|
if (ofd.ShowDialog())
|
|
{
|
|
metadataPath = ofd.FileName;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (il2cppPath == null)
|
|
{
|
|
ShowHelp();
|
|
return;
|
|
}
|
|
if (metadataPath == null)
|
|
{
|
|
Console.WriteLine($"ERROR: Metadata file not found or encrypted.");
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (Init(il2cppPath, metadataPath, out var metadata, out var il2Cpp))
|
|
{
|
|
Dump(metadata, il2Cpp, outputDir);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
}
|
|
}
|
|
if (config.RequireAnyKey)
|
|
{
|
|
Console.WriteLine("Press any key to exit...");
|
|
Console.ReadKey(true);
|
|
}
|
|
}
|
|
|
|
static void ShowHelp()
|
|
{
|
|
Console.WriteLine($"usage: {AppDomain.CurrentDomain.FriendlyName} <executable-file> <global-metadata> <output-directory>");
|
|
}
|
|
|
|
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.metadataUsagesCount);
|
|
Console.WriteLine($"Il2Cpp Version: {il2Cpp.Version}");
|
|
if (config.ForceDump || il2Cpp.CheckDump())
|
|
{
|
|
if (il2Cpp is ElfBase elf)
|
|
{
|
|
Console.WriteLine("Detected this may be a dump file.");
|
|
Console.WriteLine("Input il2cpp dump address or input 0 to force continue:");
|
|
var DumpAddr = Convert.ToUInt64(Console.ReadLine(), 16);
|
|
if (DumpAddr != 0)
|
|
{
|
|
il2Cpp.ImageBase = DumpAddr;
|
|
il2Cpp.IsDumped = true;
|
|
if (!config.NoRedirectedPointer)
|
|
{
|
|
elf.Reload();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
il2Cpp.IsDumped = true;
|
|
}
|
|
}
|
|
|
|
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.metadataUsagesCount);
|
|
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);
|
|
}
|
|
if (il2Cpp.Version >= 27 && il2Cpp.IsDumped)
|
|
{
|
|
var typeDef = metadata.typeDefs[0];
|
|
var il2CppType = il2Cpp.types[typeDef.byvalTypeIndex];
|
|
metadata.ImageBase = il2CppType.data.typeHandle - metadata.header.typeDefinitionsOffset;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
Console.WriteLine("ERROR: An error occurred while processing.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static void Dump(Metadata metadata, Il2Cpp il2Cpp, string outputDir)
|
|
{
|
|
Console.WriteLine("Dumping...");
|
|
var executor = new Il2CppExecutor(metadata, il2Cpp);
|
|
var decompiler = new Il2CppDecompiler(executor);
|
|
decompiler.Decompile(config, outputDir);
|
|
Console.WriteLine("Done!");
|
|
if (config.GenerateStruct)
|
|
{
|
|
Console.WriteLine("Generate struct...");
|
|
var scriptGenerator = new StructGenerator(executor);
|
|
scriptGenerator.WriteScript(outputDir);
|
|
Console.WriteLine("Done!");
|
|
}
|
|
if (config.GenerateDummyDll)
|
|
{
|
|
Console.WriteLine("Generate dummy dll...");
|
|
DummyAssemblyExporter.Export(executor, outputDir, config.DummyDllAddToken);
|
|
Console.WriteLine("Done!");
|
|
}
|
|
}
|
|
}
|
|
}
|