支持Mach-O和x86格式

添加导出parent,property和attribute
完善导出修饰符
修复部分错误,强化异常处理
This commit is contained in:
Perfare 2017-03-29 23:21:43 +08:00
parent c69a3bb078
commit 62e9fa972a
11 changed files with 605 additions and 333 deletions

View file

@ -1,20 +1,28 @@
internal static class DefineConstants
namespace Il2CppDumper
{
public const int FIELD_ATTRIBUTE_PRIVATE = 0x0001;
public const int FIELD_ATTRIBUTE_PUBLIC = 0x0006;
public const int FIELD_ATTRIBUTE_STATIC = 0x0010;
public const int FIELD_ATTRIBUTE_INIT_ONLY = 0x0020;
public const int METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007;
public const int METHOD_ATTRIBUTE_PRIVATE = 0x0001;
public const int METHOD_ATTRIBUTE_PUBLIC = 0x0006;
public const int METHOD_ATTRIBUTE_STATIC = 0x0010;
public const int METHOD_ATTRIBUTE_VIRTUAL = 0x0040;
public const int TYPE_ATTRIBUTE_VISIBILITY_MASK = 0x00000007;
public const int TYPE_ATTRIBUTE_PUBLIC = 0x00000001;
public const int TYPE_ATTRIBUTE_INTERFACE = 0x00000020;
public const int TYPE_ATTRIBUTE_ABSTRACT = 0x00000080;
public const int TYPE_ATTRIBUTE_SEALED = 0x00000100;
public const int TYPE_ATTRIBUTE_SERIALIZABLE = 0x00002000;
public const int PARAM_ATTRIBUTE_OUT = 0x0002;
public const int PARAM_ATTRIBUTE_OPTIONAL = 0x0010;
internal static class DefineConstants
{
public const int FIELD_ATTRIBUTE_FIELD_ACCESS_MASK = 0x0007;
public const int FIELD_ATTRIBUTE_PRIVATE = 0x0001;
public const int FIELD_ATTRIBUTE_FAMILY = 0x0004;
public const int FIELD_ATTRIBUTE_PUBLIC = 0x0006;
public const int FIELD_ATTRIBUTE_STATIC = 0x0010;
public const int FIELD_ATTRIBUTE_INIT_ONLY = 0x0020;
public const int METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007;
public const int METHOD_ATTRIBUTE_PRIVATE = 0x0001;
public const int METHOD_ATTRIBUTE_FAMILY = 0x0004;
public const int METHOD_ATTRIBUTE_PUBLIC = 0x0006;
public const int METHOD_ATTRIBUTE_STATIC = 0x0010;
public const int METHOD_ATTRIBUTE_VIRTUAL = 0x0040;
public const int METHOD_ATTRIBUTE_ABSTRACT = 0x0400;
public const int TYPE_ATTRIBUTE_VISIBILITY_MASK = 0x00000007;
public const int TYPE_ATTRIBUTE_NOT_PUBLIC = 0x00000000;
public const int TYPE_ATTRIBUTE_PUBLIC = 0x00000001;
public const int TYPE_ATTRIBUTE_INTERFACE = 0x00000020;
public const int TYPE_ATTRIBUTE_ABSTRACT = 0x00000080;
public const int TYPE_ATTRIBUTE_SEALED = 0x00000100;
public const int TYPE_ATTRIBUTE_SERIALIZABLE = 0x00002000;
public const int PARAM_ATTRIBUTE_OUT = 0x0002;
public const int PARAM_ATTRIBUTE_OPTIONAL = 0x0010;
}
}

View file

@ -6,23 +6,22 @@ using System.Text;
namespace Il2CppDumper
{
class Elf : MyBinaryReader
class Elf : Il2Cpp
{
public elf_header elf_header;
public program_header_table[] program_table_element;
private elf_header elf_header;
private program_header_table[] program_table_element;
private static byte[] ARMFeatureBytes = { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
private static byte[] X86FeatureBytes = { 0x55, 0x89, 0xE5, 0x53, 0x83, 0xE4, 0xF0, 0x83, 0xEC, 0x20, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B };
public Elf(Stream stream) : base(stream)
{
elf_header = new elf_header();
elf_header.m_dwFormat = ReadUInt32();
if (elf_header.m_dwFormat != 0x464c457f)
{
throw new Exception("ERROR: il2cpp lib provided is not a valid ELF file.");
}
elf_header.m_arch = ReadByte();
if (elf_header.m_arch == 2)//64
{
throw new Exception("ERROR: 64 bit so files are not supported.");
throw new Exception("ERROR: 64 bit not supported.");
}
elf_header.m_endian = ReadByte();
elf_header.m_version = ReadByte();
@ -45,20 +44,108 @@ namespace Il2CppDumper
program_table_element = ReadClassArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
}
public uint MapVATR(uint uiAddr)
public Elf(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
protected override uint MapVATR(uint uiAddr)
{
var program_header_table = program_table_element.First(x => uiAddr >= x.p_vaddr && uiAddr <= (x.p_vaddr + x.p_memsz));
return uiAddr - (program_header_table.p_vaddr - program_header_table.p_offset);
}
public T MapVATR<T>(uint uiAddr) where T : new()
public override bool Auto()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
//取.dynamic
var dynamic = new elf_32_shdr();
var PT_DYNAMIC = program_table_element.First(x => x.p_type == 2u);
dynamic.sh_offset = PT_DYNAMIC.p_offset;
dynamic.sh_size = PT_DYNAMIC.p_filesz;
//从.dynamic获取_GLOBAL_OFFSET_TABLE_和.init_array
uint _GLOBAL_OFFSET_TABLE_ = 0;
var init_array = new elf_32_shdr();
Position = dynamic.sh_offset;
var dynamicend = dynamic.sh_offset + dynamic.sh_size;
while (Position < dynamicend)
{
var tag = ReadInt32();
if (tag == 3)//DT_PLTGOT
{
_GLOBAL_OFFSET_TABLE_ = ReadUInt32();
}
else if (tag == 25)//DT_INIT_ARRAY
{
init_array.sh_offset = MapVATR(ReadUInt32());
}
else if (tag == 27)//DT_INIT_ARRAYSZ
{
init_array.sh_size = ReadUInt32();
}
else
{
Position += 4;//skip
}
}
if (_GLOBAL_OFFSET_TABLE_ != 0)
{
//从.init_array获取函数
var addrs = ReadClassArray<uint>(init_array.sh_offset, (int)init_array.sh_size / 4);
foreach (var i in addrs)
{
if (i > 0)
{
Position = i;
if (elf_header.e_machine == 0x28)
{
var buff = ReadBytes(12);
if (ARMFeatureBytes.SequenceEqual(buff))
{
Position = i + 0x2c;
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = subaddr + 0x28;
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Position = subaddr + 0x2C;
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = MapVATR(ptr);
var metadataRegistration = ReadUInt32();
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
else if (elf_header.e_machine == 0x3)
{
var buff = ReadBytes(16);
if (X86FeatureBytes.SequenceEqual(buff))
{
Position = i + 0x18;
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = subaddr + 0x2C;
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Position = subaddr + 0x22;
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = MapVATR(ptr);
var metadataRegistration = ReadUInt32();
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
else
{
Console.WriteLine("ERROR: Automatic processing does not support this ELF file.");
}
}
}
}
else
{
Console.WriteLine("ERROR: Unable to get GOT form PT_DYNAMIC.");
}
return false;
}
}
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
#pragma warning disable CS0649
namespace Il2CppDumper
{
class elf_header
@ -64,7 +64,6 @@ namespace Il2CppDumper
public uint p_memsz;
public uint p_flags;
public uint p_align;
//public byte[] p_data;忽略
}
class elf_32_shdr

View file

@ -6,29 +6,23 @@ using System.Text;
namespace Il2CppDumper
{
class Il2Cpp : Elf
abstract class Il2Cpp : MyBinaryReader
{
Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppMetadataRegistration pMetadataRegistration;
public Il2CppCodeRegistration pCodeRegistration;
public Il2Cpp(Stream stream) : base(stream)
{
if (!Auto())
{
throw new Exception("ERROR: Unable to process file automatically, try to use manual mode.");
}
}
public abstract bool Auto();
protected abstract uint MapVATR(uint uiAddr);
public Il2Cpp(Stream stream, uint codeRegistration, uint metadataRegistration) : base(stream)
{
Init(codeRegistration, metadataRegistration);
}
private void Init(uint codeRegistration, uint metadataRegistration)
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
pCodeRegistration.methodPointers = MapVATR<uint>(pCodeRegistration.pmethodPointers, (int)pCodeRegistration.methodPointersCount);
pCodeRegistration.customAttributeGenerators = MapVATR<uint>(pCodeRegistration.pcustomAttributeGenerators, pCodeRegistration.customAttributeCount);
pMetadataRegistration.fieldOffsets = MapVATR<int>(pMetadataRegistration.pfieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var types = MapVATR<uint>(pMetadataRegistration.ptypes, pMetadataRegistration.typesCount);
pMetadataRegistration.types = new Il2CppType[pMetadataRegistration.typesCount];
@ -47,77 +41,22 @@ namespace Il2CppDumper
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = pMetadataRegistration.fieldOffsets[typeIndex];
Position = ptr + 4 * fieldIndexInType;
return ReadInt32();
if (ptr >= 0)
{
Position = MapVATR((uint)ptr) + 4 * fieldIndexInType;
return ReadInt32();
}
return 0;
}
public bool Auto()
public T MapVATR<T>(uint uiAddr) where T : new()
{
//函数特征码
var bytes = new byte[] { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
//取.dynamic
var dynamic = new elf_32_shdr();
var PT_DYNAMIC = program_table_element.First(x => x.p_type == 2u);
dynamic.sh_offset = PT_DYNAMIC.p_offset;
dynamic.sh_size = PT_DYNAMIC.p_filesz;
//从.dynamic获取_GLOBAL_OFFSET_TABLE_和.init_array
uint _GLOBAL_OFFSET_TABLE_ = 0;
var init_array = new elf_32_shdr();
Position = dynamic.sh_offset;
var dynamicend = dynamic.sh_offset + dynamic.sh_size;
while (Position < dynamicend)
{
var tag = ReadInt32();
if (tag == 3)//DT_PLTGOT
{
_GLOBAL_OFFSET_TABLE_ = ReadUInt32();
continue;
}
else if (tag == 25)//DT_INIT_ARRAY
{
init_array.sh_offset = MapVATR(ReadUInt32());
continue;
}
else if (tag == 27)//DT_INIT_ARRAYSZ
{
init_array.sh_size = ReadUInt32();
continue;
}
Position += 4;
}
if (_GLOBAL_OFFSET_TABLE_ != 0)
{
//从.init_array获取函数
var addrs = ReadClassArray<uint>(init_array.sh_offset, (int)init_array.sh_size / 4);
foreach (var i in addrs)
{
if (i != 0)
{
Position = i;
var buff = ReadBytes(12);
if (bytes.SequenceEqual(buff))
{
Position = i + 0x2c;
var subaddr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = subaddr + 0x28;
var codeRegistration = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Position = subaddr + 0x2C;
var ptr = ReadUInt32() + _GLOBAL_OFFSET_TABLE_;
Position = MapVATR(ptr);
var metadataRegistration = ReadUInt32();
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
else
{
Console.WriteLine("ERROR: Unable to get GOT form PT_DYNAMIC.");
}
return false;
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable CS0649
namespace Il2CppDumper
{
public class Il2CppCodeRegistration
@ -23,14 +23,12 @@ namespace Il2CppDumper
public uint invokerPointersCount;
public uint invokerPointers;
public int customAttributeCount;
public uint customAttributeGenerators;
public uint pcustomAttributeGenerators;
public int guidCount;
public uint guids; // Il2CppGuid
public uint[] methodPointers
{
get; set;
}
public uint[] methodPointers { get; set; }
public uint[] customAttributeGenerators { get; set; }
}
class Il2CppMetadataRegistration
@ -54,15 +52,9 @@ namespace Il2CppDumper
public uint metadataUsagesCount;
public uint metadataUsages;
public int[] fieldOffsets
{
get; set;
}
public int[] fieldOffsets { get; set; }
public Il2CppType[] types
{
get; set;
}
public Il2CppType[] types { get; set; }
}
public enum Il2CppTypeEnum
@ -136,41 +128,13 @@ namespace Il2CppDumper
public class Anonymous
{
public uint dummy;
public int klassIndex
{
get
{
return (int)dummy;
}
}
public uint type
{
get
{
return dummy;
}
}
public uint array
{
get
{
return dummy;
}
}
public int genericParameterIndex
{
get
{
return (int)dummy;
}
}
public uint generic_class
{
get
{
return dummy;
}
}
public int klassIndex => (int)dummy;
public uint type => dummy;
public uint array => dummy;
public int genericParameterIndex => (int)dummy;
public uint generic_class => dummy;
}
}

View file

@ -34,6 +34,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@ -46,6 +47,8 @@
<Compile Include="ElfClass.cs" />
<Compile Include="Il2Cpp.cs" />
<Compile Include="Il2CppClass.cs" />
<Compile Include="Macho.cs" />
<Compile Include="MachoClass.cs" />
<Compile Include="Metadata.cs" />
<Compile Include="MetadataClass.cs" />
<Compile Include="MyBinaryReader.cs" />

110
Il2CppDumper/Macho.cs Normal file
View file

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper
{
class Macho : Il2Cpp
{
private List<MachoSection> sections = new List<MachoSection>();
private static byte[] FeatureBytes1 = { 0x0, 0x22 };//MOVS R2, #0
private static byte[] FeatureBytes2 = { 0x78, 0x44, 0x79, 0x44 };//ADD R0, PC and ADD R1, PC
public Macho(Stream stream) : base(stream)
{
Position += 16;//skip
var ncmds = ReadUInt32();
Position += 8;//skip
for (int i = 0; i < ncmds; i++)
{
var offset = Position;
var loadCommandType = ReadUInt32();
var command_size = ReadUInt32();
if (loadCommandType == 1) //SEGMENT
{
var segment_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
if (segment_name == "__TEXT" || segment_name == "__DATA")
{
Position += 24;//skip
var number_of_sections = ReadUInt32();
Position += 4;//skip
for (int j = 0; j < number_of_sections; j++)
{
var section_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
Position += 16;
var address = ReadUInt32();
var size = ReadUInt32();
var offset2 = ReadUInt32();
var end = address + size;
sections.Add(new MachoSection() { section_name = section_name, address = address, size = size, offset = offset2, end = end });
Position += 24;
}
}
}
Position = offset + command_size;//skip
}
}
public Macho(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
protected override uint MapVATR(uint uiAddr)
{
var section = sections.First(x => uiAddr >= x.address && uiAddr <= x.end);
return uiAddr - (section.address - section.offset);
}
public override bool Auto()
{
var __mod_init_func = sections.First(x => x.section_name == "__mod_init_func");
var addrs = ReadClassArray<uint>(__mod_init_func.offset, (int)__mod_init_func.size / 4);
foreach (var a in addrs)
{
if (a > 0)
{
var i = a - 1;
Position = MapVATR(i);
Position += 4;
var buff = ReadBytes(2);
if (FeatureBytes1.SequenceEqual(buff))
{
Position += 12;
buff = ReadBytes(4);
if (FeatureBytes2.SequenceEqual(buff))
{
Position = MapVATR(i) + 10;
var subaddr = decodeMov(ReadBytes(8)) + i + 24u - 1u;
var rsubaddr = MapVATR(subaddr);
Position = rsubaddr;
var ptr = decodeMov(ReadBytes(8)) + subaddr + 16u;
Position = MapVATR(ptr);
var metadataRegistration = ReadUInt32();
Position = rsubaddr + 8;
buff = ReadBytes(4);
Position = rsubaddr + 14;
buff = buff.Concat(ReadBytes(4)).ToArray();
var codeRegistration = decodeMov(buff) + subaddr + 26u;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
private uint decodeMov(byte[] asm)
{
var low = (ushort)(asm[2] + ((asm[3] & 0x70) << 4) + ((asm[1] & 0x04) << 9) + ((asm[0] & 0x0f) << 12));
var high = (ushort)(asm[6] + ((asm[7] & 0x70) << 4) + ((asm[5] & 0x04) << 9) + ((asm[4] & 0x0f) << 12));
return (uint)((high << 16) + low);
}
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Il2CppDumper
{
class MachoSection
{
public string section_name;
public uint address;
public uint size;
public uint offset;
public uint end;
}
}

View file

@ -6,7 +6,7 @@ namespace Il2CppDumper
{
class Metadata : MyBinaryReader
{
Il2CppGlobalMetadataHeader pMetadataHdr;
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
@ -15,6 +15,9 @@ namespace Il2CppDumper
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
public Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributesInfos;
public int[] attributeTypes;
public Metadata(Stream stream) : base(stream)
{
@ -38,8 +41,14 @@ namespace Il2CppDumper
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//GetFieldDefaultFromIndex
//GetFieldDefaultValuesFromIndex
fieldDefaultValues = ReadClassArray<Il2CppFieldDefaultValue>(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(typeof(Il2CppFieldDefaultValue)));
//GetPropertyDefinitionFromIndex
propertyDefs = ReadClassArray<Il2CppPropertyDefinition>(pMetadataHdr.propertiesOffset, pMetadataHdr.propertiesCount / MySizeOf(typeof(Il2CppPropertyDefinition)));
//GetAttributesInfoFromIndex
attributesInfos = ReadClassArray<Il2CppCustomAttributeTypeRange>(pMetadataHdr.attributesInfoOffset, pMetadataHdr.attributesInfoCount / MySizeOf(typeof(Il2CppCustomAttributeTypeRange)));
//GetAttributeTypesFromIndex
attributeTypes = ReadClassArray<int>(pMetadataHdr.attributeTypesOffset, pMetadataHdr.attributeTypesCount / 4);
}
public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx)

View file

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
#pragma warning disable CS0649
namespace Il2CppDumper
{
class Il2CppGlobalMetadataHeader
@ -177,4 +177,20 @@ namespace Il2CppDumper
public int typeIndex;
public int dataIndex;
}
public class Il2CppPropertyDefinition
{
public int nameIndex;
public int get;
public int set;
public uint attrs;
public int customAttributeIndex;
public uint token;
}
public class Il2CppCustomAttributeTypeRange
{
public int start;
public int count;
}
}

View file

@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper
{
@ -11,184 +12,292 @@ namespace Il2CppDumper
static Metadata metadata;
static Il2Cpp il2cpp;
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
try
var ofd = new OpenFileDialog();
ofd.Filter = "ELF file or Mach-O file|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
if (key.KeyChar == '2')
var il2cppfile = File.ReadAllBytes(ofd.FileName);
ofd.Filter = "global-metadata|global-metadata.dat";
if (ofd.ShowDialog() == DialogResult.OK)
{
metadata = new Metadata(new MemoryStream(File.ReadAllBytes("global-metadata.dat")));
il2cpp = new Il2Cpp(new MemoryStream(File.ReadAllBytes("libil2cpp.so")));
}
else if (key.KeyChar == '1')
{
Console.Write("Input CodeRegistration(R0): ");
var codeRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(File.ReadAllBytes("global-metadata.dat")));
il2cpp = new Il2Cpp(new MemoryStream(File.ReadAllBytes("libil2cpp.so")), codeRegistration, metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//dump_image();
for (int imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++)
{
var imageDef = metadata.imageDefs[imageIndex];
writer.Write($"// Image {imageIndex}: {metadata.GetString(imageDef.nameIndex)} - {imageDef.typeStart}\n");
}
for (int idx = 0; idx < metadata.uiNumTypes; ++idx)
{
//dump_class(i);
var typeDef = metadata.typeDefs[idx];
writer.Write($"// Namespace: {metadata.GetString(typeDef.namespaceIndex)}\n");
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
writer.Write("[Serializable]\n");
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == DefineConstants.TYPE_ATTRIBUTE_PUBLIC)
writer.Write("public ");
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0)
writer.Write("abstract ");
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0)
writer.Write("sealed ");
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0)
writer.Write("interface ");
else
writer.Write("class ");
writer.Write($"{metadata.GetString(typeDef.nameIndex)} // TypeDefIndex: {idx}\n{{\n");
writer.Write("\t// Fields\n");
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
for (int i = typeDef.fieldStart; i < fieldEnd; ++i)
try
{
//dump_field(i, idx, i - typeDef.fieldStart);
var pField = metadata.fieldDefs[i];
var pType = il2cpp.GetTypeFromTypeIndex(pField.typeIndex);
var pDefault = metadata.GetFieldDefaultFromIndex(i);
writer.Write("\t");
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) == DefineConstants.FIELD_ATTRIBUTE_PRIVATE)
writer.Write("private ");
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PUBLIC) == DefineConstants.FIELD_ATTRIBUTE_PUBLIC)
writer.Write("public ");
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_STATIC) != 0)
writer.Write("static ");
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_INIT_ONLY) != 0)
writer.Write("readonly ");
writer.Write($"{get_type_name(pType)} {metadata.GetString(pField.nameIndex)}");
if (pDefault != null && pDefault.dataIndex != -1)
//判断magic
var macig = BitConverter.ToUInt32(il2cppfile, 0);
var isElf = false;
if (macig == 0x464c457f) //Elf
{
var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex);
Il2CppType pTypeToUse = il2cpp.GetTypeFromTypeIndex(pDefault.typeIndex);
if (pointer > 0)
{
metadata.Position = pointer;
object multi = null;
switch (pTypeToUse.type)
{
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
multi = metadata.ReadBoolean();
break;
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
multi = metadata.ReadByte();
break;
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
multi = metadata.ReadChar();
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}");
}
isElf = true;
}
writer.Write("; // 0x{0:x}\n", il2cpp.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart));
}
writer.Write("\t// Methods\n");
var methodEnd = typeDef.methodStart + typeDef.method_count;
for (int i = typeDef.methodStart; i < methodEnd; ++i)
{
//dump_method(i);
var methodDef = metadata.methodDefs[i];
writer.Write("\t");
Il2CppType pReturnType = il2cpp.GetTypeFromTypeIndex(methodDef.returnType);
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PRIVATE)
writer.Write("private ");
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == DefineConstants.METHOD_ATTRIBUTE_PUBLIC)
writer.Write("public ");
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_VIRTUAL) != 0)
writer.Write("virtual ");
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_STATIC) != 0)
writer.Write("static ");
writer.Write($"{get_type_name(pReturnType)} {metadata.GetString(methodDef.nameIndex)}(");
for (int j = 0; j < methodDef.parameterCount; ++j)
else if (macig != 0xFEEDFACE) //32-bit mach object file
{
Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j];
string szParamName = metadata.GetString(pParam.nameIndex);
Il2CppType pType = il2cpp.GetTypeFromTypeIndex(pParam.typeIndex);
string szTypeName = get_type_name(pType);
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0)
writer.Write("optional ");
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OUT) != 0)
writer.Write("out ");
if (j != methodDef.parameterCount - 1)
{
writer.Write($"{szTypeName} {szParamName}, ");
}
throw new Exception("ERROR: il2cpp file not supported.");
}
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(File.ReadAllBytes(ofd.FileName)));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile));
else
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
writer.Write($"{szTypeName} {szParamName}");
throw new Exception("ERROR: Unable to process file automatically, try to use manual mode.");
}
}
if (methodDef.methodIndex >= 0)
writer.Write("); // {0:x} - {1}\n", il2cpp.pCodeRegistration.methodPointers[methodDef.methodIndex], methodDef.methodIndex);
else if (key.KeyChar == '1')
{
Console.Write("Input CodeRegistration(R0): ");
var codeRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(File.ReadAllBytes(ofd.FileName)));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration);
}
else
writer.Write("); // 0 - -1\n");
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//dump_image();
for (int imageIndex = 0; imageIndex < metadata.uiImageCount; imageIndex++)
{
var imageDef = metadata.imageDefs[imageIndex];
writer.Write($"// Image {imageIndex}: {metadata.GetString(imageDef.nameIndex)} - {imageDef.typeStart}\n");
}
for (int 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.GetTypeFromTypeIndex(typeDef.parentIndex);
var parentname = get_type_name(parent);
if (parentname != "object")
writer.Write($" : {parentname}");
}
writer.Write($" // TypeDefIndex: {idx}\n{{\n");
if (typeDef.field_count > 0)
{
writer.Write("\t// Fields\n");
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
for (int i = typeDef.fieldStart; i < fieldEnd; ++i)
{
//dump_field(i, idx, i - typeDef.fieldStart);
var pField = metadata.fieldDefs[i];
var pType = il2cpp.GetTypeFromTypeIndex(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);
Il2CppType pTypeToUse = il2cpp.GetTypeFromTypeIndex(pDefault.typeIndex);
if (pointer > 0)
{
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();
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));
}
writer.Write("\n");
}
if (typeDef.property_count > 0)
{
//dump_property(i);
writer.Write("\t// Properties\n");
var propertyEnd = typeDef.propertyStart + typeDef.property_count;
for (int i = typeDef.propertyStart; i < propertyEnd; ++i)
{
var propertydef = metadata.propertyDefs[i];
writer.Write(GetCustomAttribute(propertydef.customAttributeIndex, "\t"));
writer.Write("\t");
var tmp = propertydef.get >= 0 ? propertydef.get : propertydef.set;
if (tmp >= 0)
{
var methodDef = metadata.methodDefs[typeDef.methodStart + propertydef.get];
var pReturnType = il2cpp.GetTypeFromTypeIndex(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)} {{ ");
if (propertydef.get >= 0)
writer.Write("get; ");
if (propertydef.set >= 0)
writer.Write("set; ");
writer.Write("}");
}
writer.Write("\n");
}
writer.Write("\n");
}
if (typeDef.method_count > 0)
{
writer.Write("\t// Methods\n");
var methodEnd = typeDef.methodStart + typeDef.method_count;
for (int i = typeDef.methodStart; i < methodEnd; ++i)
{
//dump_method(i);
var methodDef = metadata.methodDefs[i];
writer.Write(GetCustomAttribute(methodDef.customAttributeIndex, "\t"));
writer.Write("\t");
Il2CppType pReturnType = il2cpp.GetTypeFromTypeIndex(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 (int j = 0; j < methodDef.parameterCount; ++j)
{
Il2CppParameterDefinition pParam =
metadata.parameterDefs[methodDef.parameterStart + j];
string szParamName = metadata.GetString(pParam.nameIndex);
Il2CppType pType = il2cpp.GetTypeFromTypeIndex(pParam.typeIndex);
string 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.pCodeRegistration.methodPointers[methodDef.methodIndex]);
else
writer.Write("); // 0\n");
}
}
writer.Write("}\n");
}
catch (Exception e)
{
Console.WriteLine("ERROR: Some errors in dumping");
writer.Write("/*");
writer.Write($"{e.Message}\r\n{e.StackTrace}\r\n");
writer.Write("*/\n}\n");
}
}
writer.Close();
Console.WriteLine("Done !");
}
writer.Write("}\n");
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
writer.Close();
Console.WriteLine("Done !");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
private static string get_type_name(Il2CppType pType)
@ -238,6 +347,18 @@ namespace Il2CppDumper
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (int i = 0; i < attributeTypeRange.count; i++)
{
var typeIndex = metadata.attributeTypes[attributeTypeRange.start + i];
sb.AppendFormat("{0}[{1}] // {2:x}\n", padding, get_type_name(il2cpp.GetTypeFromTypeIndex(typeIndex)), il2cpp.pCodeRegistration.customAttributeGenerators[index]);
}
return sb.ToString();
}
static string[] szTypeString =
{
"END",