重构,添加通用处理类

This commit is contained in:
Perfare 2017-04-14 22:36:10 +08:00
parent 5c0a706d6a
commit bbfb533b7f
50 changed files with 1312 additions and 5050 deletions

View file

@ -6,7 +6,7 @@ using System.Text;
namespace Il2CppDumper
{
class Elf : Il2Cpp
class Elf : Il2CppGeneric
{
private elf_header elf_header;
private program_header_table[] program_table_element;
@ -14,8 +14,14 @@ namespace Il2CppDumper
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)
public Elf(Stream stream, int version) : base(stream)
{
this.version = version;
@namespace = "Il2CppDumper.v" + version + ".";
if (version < 21)
Search = Searchv20;
else
Search = Searchv21;
elf_header = new elf_header();
elf_header.m_dwFormat = ReadUInt32();
elf_header.m_arch = ReadByte();
@ -44,18 +50,23 @@ namespace Il2CppDumper
program_table_element = ReadClassArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
}
public Elf(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
public Elf(Stream stream, ulong codeRegistration, ulong metadataRegistration, int version) : this(stream, version)
{
Init(codeRegistration, metadataRegistration);
}
public override uint MapVATR(uint uiAddr)
protected override dynamic MapVATR(dynamic 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 override bool Auto()
private bool Searchv20()
{
throw new NotSupportedException("未完工");
}
private bool Searchv21()
{
//取.dynamic
var dynamic = new elf_32_shdr();

View file

@ -42,58 +42,36 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="v20\Dump.cs" />
<Compile Include="v20\Elf.cs" />
<Compile Include="v20\Il2Cpp.cs" />
<Compile Include="v20\Macho.cs" />
<Compile Include="v20\Metadata.cs" />
<Compile Include="v21\64bit\Dump.cs" />
<Compile Include="v21\64bit\Il2Cpp.cs" />
<Compile Include="Elf.cs" />
<Compile Include="Il2CppGeneric.cs" />
<Compile Include="Il2CppGenericClass.cs" />
<Compile Include="Macho.cs" />
<Compile Include="MetadataGeneric.cs" />
<Compile Include="MetadataGenericClass.cs" />
<Compile Include="MyCopy.cs" />
<Compile Include="v16\64bit\Il2CppClass.cs" />
<Compile Include="v20\64bit\Il2CppClass.cs" />
<Compile Include="v21\64bit\Il2CppClass.cs" />
<Compile Include="v21\64bit\Macho.cs" />
<Compile Include="ArmHelper.cs" />
<Compile Include="DefineConstants.cs" />
<Compile Include="v21\Elf.cs" />
<Compile Include="ElfClass.cs" />
<Compile Include="v21\Il2Cpp.cs" />
<Compile Include="v21\Il2CppClass.cs" />
<Compile Include="v21\Macho.cs" />
<Compile Include="MachoClass.cs" />
<Compile Include="MachoFat.cs" />
<Compile Include="v21\Metadata.cs" />
<Compile Include="v21\MetadataClass.cs" />
<Compile Include="MyBinaryReader.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="v16\Dump.cs" />
<Compile Include="v16\Il2Cpp.cs" />
<Compile Include="v16\Il2CppClass.cs" />
<Compile Include="v16\Macho.cs" />
<Compile Include="v16\Metadata.cs" />
<Compile Include="v16\MetadataClass.cs" />
<Compile Include="v20\Il2CppClass.cs" />
<Compile Include="v20\MetadataClass.cs" />
<Compile Include="v22\64bit\Dump.cs" />
<Compile Include="v22\64bit\Il2Cpp.cs" />
<Compile Include="v22\64bit\Il2CppClass.cs" />
<Compile Include="v22\64bit\Macho.cs" />
<Compile Include="v22\Dump.cs" />
<Compile Include="v22\Elf.cs" />
<Compile Include="v22\Il2Cpp.cs" />
<Compile Include="v22\Il2CppClass.cs" />
<Compile Include="v22\Macho.cs" />
<Compile Include="v22\Metadata.cs" />
<Compile Include="v22\MetadataClass.cs" />
<Compile Include="v23\64bit\Dump.cs" />
<Compile Include="v23\64bit\Il2Cpp.cs" />
<Compile Include="v23\64bit\Il2CppClass.cs" />
<Compile Include="v23\64bit\Macho.cs" />
<Compile Include="v23\Dump.cs" />
<Compile Include="v23\Elf.cs" />
<Compile Include="v23\Il2Cpp.cs" />
<Compile Include="Macho64.cs" />
<Compile Include="v23\Il2CppClass.cs" />
<Compile Include="v23\Macho.cs" />
<Compile Include="v23\Metadata.cs" />
<Compile Include="v23\MetadataClass.cs" />
</ItemGroup>
<ItemGroup />

View file

@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using static Il2CppDumper.MyCopy;
namespace Il2CppDumper
{
abstract class Il2CppGeneric : MyBinaryReader
{
protected int version;
protected string @namespace;
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public ulong[] methodPointers;
public ulong[] customAttributeGenerators;
protected long[] fieldOffsets;
public Il2CppType[] types;
private Dictionary<ulong, Il2CppType> typesdic = new Dictionary<ulong, Il2CppType>();
protected bool isNew21;
public Func<bool> Search;
protected abstract dynamic MapVATR(dynamic uiAddr);
protected Il2CppGeneric(Stream stream) : base(stream) { }
protected void Init(ulong codeRegistration, ulong metadataRegistration)
{
var MapVATR = GetType().GetMethod("MapVATRGeneric");
//pCodeRegistration
var t = Type.GetType(@namespace + "Il2CppCodeRegistration");
var m = MapVATR.MakeGenericMethod(t);
Copy(out pCodeRegistration, m.Invoke(this, new object[] { codeRegistration }));
//pMetadataRegistration
t = Type.GetType(@namespace + "Il2CppMetadataRegistration");
m = MapVATR.MakeGenericMethod(t);
Copy(out pMetadataRegistration, m.Invoke(this, new object[] { metadataRegistration }));
methodPointers = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount), x => (ulong)x);
customAttributeGenerators = Array.ConvertAll(MapVATR<uint>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount), x => (ulong)x);
fieldOffsets = Array.ConvertAll(MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount), x => (long)x);
//TODO 在21版本中存在两种FieldOffset通过对第一非0数值进行判断确认是指针还是int
isNew21 = version > 21 || (version == 21 && fieldOffsets.First(x => x > 0) > 100);
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
t = Type.GetType(@namespace + "Il2CppType");
m = MapVATR.MakeGenericMethod(t);
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
Copy(out types[i], m.Invoke(this, new object[] { ptypes[i] }));
types[i].Init();
typesdic.Add(ptypes[i], types[i]);
}
}
protected void Init64(ulong codeRegistration, ulong metadataRegistration)
{
var MapVATR = GetType().GetMethod("MapVATRGeneric");
//pCodeRegistration
var t = Type.GetType(@namespace + "Il2CppCodeRegistration");
var m = MapVATR.MakeGenericMethod(t);
Copy(out pCodeRegistration, m.Invoke(this, new object[] { codeRegistration }));
//pMetadataRegistration
t = Type.GetType(@namespace + "Il2CppMetadataRegistration");
m = MapVATR.MakeGenericMethod(t);
Copy(out pMetadataRegistration, m.Invoke(this, new object[] { metadataRegistration }));
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<long>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
//TODO 在21版本中存在两种FieldOffset通过对第一非0数值进行判断确认是指针还是int
isNew21 = version > 21 || (version == 21 && fieldOffsets.First(x => x > 0) > 100);
var ptypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
t = Type.GetType(@namespace + "Il2CppType");
m = MapVATR.MakeGenericMethod(t);
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
Copy(out types[i], m.Invoke(this, new object[] { ptypes[i] }));
types[i].Init();
typesdic.Add(ptypes[i], types[i]);
}
}
public virtual long GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType, int fieldIndex)
{
if (isNew21)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((uint)ptr) + 4 * fieldIndexInType;
return ReadInt32();
}
return 0;
}
return fieldOffsets[fieldIndex];
}
protected T[] MapVATR<T>(dynamic uiAddr, long count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
public T MapVATRGeneric<T>(dynamic uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public Il2CppGenericClass GetIl2CppGenericClass(ulong pointer)
{
Il2CppGenericClass re;
var t = Type.GetType(@namespace + "Il2CppGenericClass");
var MapVATR = GetType().GetMethod("MapVATRGeneric");
var m = MapVATR.MakeGenericMethod(t);
dynamic o = m.Invoke(this, new object[] { pointer });
Copy(out re, o);
re.context = new Il2CppGenericContext { class_inst = o.context.class_inst };
return re;
}
public Il2CppGenericInst GetIl2CppGenericInst(ulong pointer)
{
Il2CppGenericInst re;
var t = Type.GetType(@namespace + "Il2CppGenericInst");
var MapVATR = GetType().GetMethod("MapVATRGeneric");
var m = MapVATR.MakeGenericMethod(t);
Copy(out re, m.Invoke(this, new object[] { pointer }));
return re;
}
public Il2CppType GetIl2CppType(ulong pointer)
{
return typesdic[pointer];
/*Il2CppType re;
var t = Type.GetType(@namespace + "Il2CppType");
var MapVATR = GetType().GetMethod("MapVATRGeneric");
var m = MapVATR.MakeGenericMethod(t);
Copy(out re, m.Invoke(this, new object[] { pointer }));
return re;*/
}
public virtual ulong[] GetPointers(ulong pointer, long count)
{
var pointers = Array.ConvertAll(MapVATR<uint>(pointer, count), x => (ulong)x);
return pointers;
}
public Il2CppArrayType GetIl2CppArrayType(ulong pointer)
{
Il2CppArrayType re;
var t = Type.GetType(@namespace + "Il2CppArrayType");
var MapVATR = GetType().GetMethod("MapVATRGeneric");
var m = MapVATR.MakeGenericMethod(t);
Copy(out re, m.Invoke(this, new object[] { pointer }));
return re;
}
}
}

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Il2CppDumper
{
public class Il2CppCodeRegistration
{
public ulong methodPointersCount;
public ulong methodPointers;
public long customAttributeCount;
public ulong customAttributeGenerators;
}
public class Il2CppMetadataRegistration
{
public long typesCount;
public ulong types;
public long fieldOffsetsCount;
public ulong fieldOffsets;
}
public enum Il2CppTypeEnum
{
IL2CPP_TYPE_END = 0x00, /* End of List */
IL2CPP_TYPE_VOID = 0x01,
IL2CPP_TYPE_BOOLEAN = 0x02,
IL2CPP_TYPE_CHAR = 0x03,
IL2CPP_TYPE_I1 = 0x04,
IL2CPP_TYPE_U1 = 0x05,
IL2CPP_TYPE_I2 = 0x06,
IL2CPP_TYPE_U2 = 0x07,
IL2CPP_TYPE_I4 = 0x08,
IL2CPP_TYPE_U4 = 0x09,
IL2CPP_TYPE_I8 = 0x0a,
IL2CPP_TYPE_U8 = 0x0b,
IL2CPP_TYPE_R4 = 0x0c,
IL2CPP_TYPE_R8 = 0x0d,
IL2CPP_TYPE_STRING = 0x0e,
IL2CPP_TYPE_PTR = 0x0f, /* arg: <type> token */
IL2CPP_TYPE_BYREF = 0x10, /* arg: <type> token */
IL2CPP_TYPE_VALUETYPE = 0x11, /* arg: <type> token */
IL2CPP_TYPE_CLASS = 0x12, /* arg: <type> token */
IL2CPP_TYPE_VAR = 0x13, /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */
IL2CPP_TYPE_ARRAY = 0x14, /* type, rank, boundsCount, bound1, loCount, lo1 */
IL2CPP_TYPE_GENERICINST = 0x15, /* <type> <type-arg-count> <type-1> \x{2026} <type-n> */
IL2CPP_TYPE_TYPEDBYREF = 0x16,
IL2CPP_TYPE_I = 0x18,
IL2CPP_TYPE_U = 0x19,
IL2CPP_TYPE_FNPTR = 0x1b, /* arg: full method signature */
IL2CPP_TYPE_OBJECT = 0x1c,
IL2CPP_TYPE_SZARRAY = 0x1d, /* 0-based one-dim-array */
IL2CPP_TYPE_MVAR = 0x1e, /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer) */
IL2CPP_TYPE_CMOD_REQD = 0x1f, /* arg: typedef or typeref token */
IL2CPP_TYPE_CMOD_OPT = 0x20, /* optional arg: typedef or typref token */
IL2CPP_TYPE_INTERNAL = 0x21, /* CLR internal type */
IL2CPP_TYPE_MODIFIER = 0x40, /* Or with the following types */
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
IL2CPP_TYPE_ENUM = 0x55 /* an enumeration */
}
public class Il2CppType
{
public ulong datapoint;
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
public uint num_mods { get; set; }
public uint byref { get; set; }
public uint pinned { get; set; }
public void Init()
{
var str = Convert.ToString(bits, 2);
if (str.Length != 32)
{
str = new string(Enumerable.Repeat('0', 32 - str.Length).Concat(str.ToCharArray()).ToArray());
}
attrs = Convert.ToUInt32(str.Substring(16, 16), 2);
type = (Il2CppTypeEnum)Convert.ToInt32(str.Substring(8, 8), 2);
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Union { dummy = datapoint };
}
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}
}
public class Il2CppGenericClass
{
public long typeDefinitionIndex; /* the generic type definition */
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
}
public class Il2CppGenericContext
{
/* The instantiation corresponding to the class generic parameters */
public ulong class_inst;
}
public class Il2CppGenericInst
{
public ulong type_argc;
public ulong type_argv;
}
public class Il2CppArrayType
{
public ulong etype;
}
}

View file

@ -7,15 +7,21 @@ using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper
{
class Macho : Il2Cpp
class Macho : Il2CppGeneric
{
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)
public Macho(Stream stream, int version) : base(stream)
{
this.version = version;
@namespace = "Il2CppDumper.v" + version + ".";
if (version < 21)
Search = Searchv16;
else
Search = Searchv21;
Position += 16;//skip
var ncmds = ReadUInt32();
Position += 8;//skip
@ -40,7 +46,7 @@ namespace Il2CppDumper
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 });
sections.Add(new MachoSection { section_name = section_name, address = address, size = size, offset = offset2, end = end });
Position += 24;
}
}
@ -49,18 +55,18 @@ namespace Il2CppDumper
}
}
public Macho(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
public Macho(Stream stream, ulong codeRegistration, ulong metadataRegistration, int version) : this(stream, version)
{
Init(codeRegistration, metadataRegistration);
}
public override uint MapVATR(uint uiAddr)
protected override dynamic MapVATR(dynamic uiAddr)
{
var section = sections.First(x => uiAddr >= x.address && uiAddr <= x.end);
return uiAddr - (section.address - section.offset);
}
public override bool Auto()
private bool Searchv21()
{
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);
@ -100,5 +106,46 @@ namespace Il2CppDumper
}
return false;
}
private bool Searchv16()
{
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 + 22u;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
}
}

View file

@ -5,17 +5,23 @@ using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v22._64bit
namespace Il2CppDumper
{
class Macho : Il2Cpp
class Macho64 : Il2CppGeneric
{
private List<MachoSection64bit> sections = new List<MachoSection64bit>();
private static byte[] FeatureBytes1 = { 0x2, 0x0, 0x80, 0xD2 };//MOV X2, #0
private static byte[] FeatureBytes2 = { 0x3, 0x0, 0x80, 0x52 };//MOV W3, #0
public Macho(Stream stream) : base(stream)
public Macho64(Stream stream, int version) : base(stream)
{
this.version = version;
@namespace = "Il2CppDumper.v" + version + "._64bit.";
if (version < 21)
Search = Searchv16;
else
Search = Searchv21;
Position += 16;//skip
var ncmds = ReadUInt32();
Position += 12;//skip
@ -40,7 +46,7 @@ namespace Il2CppDumper.v22._64bit
var size = ReadUInt64();
var offset2 = (uint)ReadUInt64();
var end = address + size;
sections.Add(new MachoSection64bit() { section_name = section_name, address = address, size = size, offset = offset2, end = end });
sections.Add(new MachoSection64bit { section_name = section_name, address = address, size = size, offset = offset2, end = end });
Position += 24;
}
}
@ -49,18 +55,45 @@ namespace Il2CppDumper.v22._64bit
}
}
public Macho(Stream stream, ulong codeRegistration, ulong metadataRegistration) : this(stream)
public Macho64(Stream stream, ulong codeRegistration, ulong metadataRegistration, int version) : this(stream, version)
{
Init(codeRegistration, metadataRegistration);
Init64(codeRegistration, metadataRegistration);
}
public override ulong MapVATR(ulong uiAddr)
protected override dynamic MapVATR(dynamic uiAddr)
{
var section = sections.First(x => uiAddr >= x.address && uiAddr <= x.end);
return uiAddr - (section.address - section.offset);
}
public override bool Auto()
public override long GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType, int fieldIndex)
{
if (isNew21)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((ulong)ptr) + 4ul * (ulong)fieldIndexInType;
return ReadInt32();
}
return 0;
}
return fieldOffsets[fieldIndex];
}
public override ulong[] GetPointers(ulong pointer, long count)
{
var pointers = MapVATR<ulong>(pointer, count);
return pointers;
}
private bool Searchv16()
{
throw new NotSupportedException("未完工");
}
private bool Searchv21()
{
var __mod_init_func = sections.First(x => x.section_name == "__mod_init_func");
var addrs = ReadClassArray<ulong>(__mod_init_func.offset, (long)__mod_init_func.size / 8);
@ -86,7 +119,7 @@ namespace Il2CppDumper.v22._64bit
metadataRegistration += decodeAdd(ReadBytes(4));
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
Init64(codeRegistration, metadataRegistration);
return true;
}
}

View file

@ -0,0 +1,121 @@
using System;
using System.Collections;
using System.IO;
using System.Linq;
using static Il2CppDumper.MyCopy;
namespace Il2CppDumper
{
class MetadataGeneric : MyBinaryReader
{
public int version;
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributesInfos;
public int[] attributeTypes;
public MetadataGeneric(Stream stream) : base(stream)
{
var sanity = ReadUInt32();
if (sanity != 0xFAB11BAF)
throw new Exception("ERROR: Metadata file supplied is not valid metadata file.");
version = ReadInt32();
if (version != 16 && version != 20 && version != 21 && version != 22 && version != 23)
throw new Exception($"ERROR: Metadata file supplied is not a supported version[{version}].");
Position = 0;
//pMetadataHdr
var @namespace = "Il2CppDumper.v" + version + ".";
var ReadClass = GetType().GetMethod("ReadClass", Type.EmptyTypes);
var ReadClassArray = GetType().GetMethod("ReadClassArray");
var m = ReadClass.MakeGenericMethod(Type.GetType(@namespace + "Il2CppGlobalMetadataHeader"));
Copy(out pMetadataHdr, m.Invoke(this, null));
//ImageDefinition
var t = Type.GetType(@namespace + "Il2CppImageDefinition");
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(t);
m = ReadClassArray.MakeGenericMethod(t);
Copy(out imageDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.imagesOffset, uiImageCount }));
//TypeDefinition
t = Type.GetType(@namespace + "Il2CppTypeDefinition");
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(t);
m = ReadClassArray.MakeGenericMethod(t);
Copy(out typeDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.typeDefinitionsOffset, uiNumTypes }));
//MethodDefinition
t = Type.GetType(@namespace + "Il2CppMethodDefinition");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out methodDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(t) }));
//ParameterDefinition
t = Type.GetType(@namespace + "Il2CppParameterDefinition");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out parameterDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(t) }));
//FieldDefinition
t = Type.GetType(@namespace + "Il2CppFieldDefinition");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out fieldDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(t) }));
//FieldDefaultValue
t = Type.GetType(@namespace + "Il2CppFieldDefaultValue");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out fieldDefaultValues, (IList)m.Invoke(this, new object[] { pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(t) }));
//PropertyDefinition
t = Type.GetType(@namespace + "Il2CppPropertyDefinition");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out propertyDefs, (IList)m.Invoke(this, new object[] { pMetadataHdr.propertiesOffset, pMetadataHdr.propertiesCount / MySizeOf(t) }));
if (version > 20)
{
//CustomAttributeTypeRange
t = Type.GetType(@namespace + "Il2CppCustomAttributeTypeRange");
m = ReadClassArray.MakeGenericMethod(t);
Copy(out attributesInfos, (IList)m.Invoke(this, new object[] { pMetadataHdr.attributesInfoOffset, pMetadataHdr.attributesInfoCount / MySizeOf(t) }));
//AttributeTypes
attributeTypes = ReadClassArray<int>(pMetadataHdr.attributeTypesOffset, pMetadataHdr.attributeTypesCount / 4);
}
}
public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private static int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}

View file

@ -0,0 +1,92 @@
namespace Il2CppDumper
{
public class Il2CppGlobalMetadataHeader
{
public int stringOffset; // string data for metadata
public int propertiesOffset; // Il2CppPropertyDefinition
public int propertiesCount;
public int methodsOffset; // Il2CppMethodDefinition
public int methodsCount;
public int fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
public int fieldDefaultValuesCount;
public int fieldAndParameterDefaultValueDataOffset; // uint8_t
public int parametersOffset; // Il2CppParameterDefinition
public int parametersCount;
public int fieldsOffset; // Il2CppFieldDefinition
public int fieldsCount;
public int typeDefinitionsOffset; // Il2CppTypeDefinition
public int typeDefinitionsCount;
public int imagesOffset; // Il2CppImageDefinition
public int imagesCount;
public int attributesInfoOffset; // Il2CppCustomAttributeTypeRange
public int attributesInfoCount;
public int attributeTypesOffset; // TypeIndex
public int attributeTypesCount;
}
public class Il2CppImageDefinition
{
public int nameIndex;
public int typeStart;
}
public class Il2CppTypeDefinition
{
public int nameIndex;
public int namespaceIndex;
public int customAttributeIndex;
public int parentIndex;
public uint flags;
public int fieldStart;
public int methodStart;
public int propertyStart;
public ushort method_count;
public ushort property_count;
public ushort field_count;
}
public class Il2CppMethodDefinition
{
public int nameIndex;
public int returnType;
public int parameterStart;
public int customAttributeIndex;
public int methodIndex;
public ushort parameterCount;
public ushort flags;
}
public class Il2CppParameterDefinition
{
public int nameIndex;
public int typeIndex;
}
public class Il2CppFieldDefinition
{
public int nameIndex;
public int typeIndex;
public int customAttributeIndex;
}
public class Il2CppFieldDefaultValue
{
public int fieldIndex;
public int typeIndex;
public int dataIndex;
}
public class Il2CppPropertyDefinition
{
public int nameIndex;
public int get;
public int set;
public int customAttributeIndex;
}
public class Il2CppCustomAttributeTypeRange
{
public int start;
public int count;
}
}

27
Il2CppDumper/MyCopy.cs Normal file
View file

@ -0,0 +1,27 @@
using System.Collections;
namespace Il2CppDumper
{
static class MyCopy
{
public static void Copy<T1, T2>(out T1 o1, T2 o2) where T1 : new()
{
o1 = new T1();
var t2 = o2.GetType();
foreach (var field in o1.GetType().GetFields())
{
if (field.FieldType.IsPrimitive)
field.SetValue(o1, t2.GetField(field.Name)?.GetValue(o2));
}
}
public static void Copy<T1>(out T1[] o1, IList o2) where T1 : new()
{
o1 = new T1[o2.Count];
for (int i = 0; i < o1.Length; i++)
{
Copy(out o1[i], o2[i]);
}
}
}
}

View file

@ -9,8 +9,8 @@ namespace Il2CppDumper
{
class Program
{
static Metadata metadata;
static Il2Cpp il2cpp;
static MetadataGeneric metadata;
static Il2CppGeneric il2cpp;
[STAThread]
static void Main(string[] args)
@ -25,347 +25,326 @@ namespace Il2CppDumper
{
try
{
var metadatafile = File.ReadAllBytes(ofd.FileName);
//判断Metadata的magic和version
var metadatamagic = BitConverter.ToUInt32(metadatafile, 0);
if (metadatamagic != 0xFAB11BAF)
{
throw new Exception("ERROR: Metadata file supplied is not valid metadata file.");
}
var metadataversion = BitConverter.ToUInt32(metadatafile, 4);
switch (metadataversion)
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: Metadata file supplied is not a supported version[{metadataversion}].");
case 16:
v16.Dump.Dumpv16(il2cppfile, metadatafile);
break;
case 23:
v23.Dump.Dumpv23(il2cppfile, metadatafile);
break;
case 21:
case 22:
//判断il2cpp的magic
var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0);
var isElf = false;
switch (il2cppmagic)
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')
{
default:
throw new Exception("ERROR: il2cpp file not supported.");
case 0x464c457f:
isElf = true;
goto case 0xFEEDFACE;
case 0xCAFEBABE:
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
_64bit.Dump.Dump64bit(il2cppfile, metadatafile);
break;
case 0xFEEDFACE:// 32-bit mach object file
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile));
else
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), metadata.version);
else if (is64bit)
il2cpp = new Macho64(new MemoryStream(il2cppfile), metadata.version);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), metadata.version);
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);
else if (is64bit)
il2cpp = new Macho64(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, metadata.version);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration, metadata.version);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
}
}
@ -389,31 +368,28 @@ namespace Il2CppDumper
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var generic_class = il2cpp.GetIl2CppGenericClass(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
for (var i = 0; i < pInst.type_argc; ++i)
var pInst = il2cpp.GetIl2CppGenericInst(generic_class.context.class_inst);
var pointers = il2cpp.GetPointers(pInst.type_argv, (long)pInst.type_argc);
for (uint i = 0; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
var pOriType = il2cpp.GetIl2CppType(pointers[i]);
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
var arrayType = il2cpp.GetIl2CppArrayType(pType.data.array);
var type = il2cpp.GetIl2CppType(arrayType.etype);
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
var type = il2cpp.GetIl2CppType(pType.data.type);
ret = $"{get_type_name(type)}[]";
}
else
@ -428,6 +404,8 @@ namespace Il2CppDumper
private static string GetCustomAttribute(int index, string padding = "")
{
if (metadata.version < 21)
return "";
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var i = 0; i < attributeTypeRange.count; i++)

View file

@ -0,0 +1,155 @@
using System;
using System.Linq;
namespace Il2CppDumper.v16._64bit
{
public class Il2CppCodeRegistration
{
public ulong methodPointersCount;
public ulong methodPointers;
public ulong delegateWrappersFromNativeToManagedCount;
public ulong delegateWrappersFromNativeToManaged; // note the double indirection to handle different calling conventions
public ulong delegateWrappersFromManagedToNativeCount;
public ulong delegateWrappersFromManagedToNative;
public ulong marshalingFunctionsCount;
public ulong marshalingFunctions;
public ulong genericMethodPointersCount;
public ulong genericMethodPointers;
public ulong invokerPointersCount;
public ulong invokerPointers;
public long customAttributeCount;
public ulong customAttributeGenerators;
}
public class Il2CppMetadataRegistration
{
public long genericClassesCount;
public ulong genericClasses;
public long genericInstsCount;
public ulong genericInsts;
public long genericMethodTableCount;
public ulong genericMethodTable;
public long typesCount;
public ulong types;
public long methodSpecsCount;
public ulong methodSpecs;
public long methodReferencesCount;
public ulong methodReferences;
public long fieldOffsetsCount;
public ulong fieldOffsets;
public long typeDefinitionsSizesCount;
public ulong typeDefinitionsSizes;
}
public enum Il2CppTypeEnum
{
IL2CPP_TYPE_END = 0x00, /* End of List */
IL2CPP_TYPE_VOID = 0x01,
IL2CPP_TYPE_BOOLEAN = 0x02,
IL2CPP_TYPE_CHAR = 0x03,
IL2CPP_TYPE_I1 = 0x04,
IL2CPP_TYPE_U1 = 0x05,
IL2CPP_TYPE_I2 = 0x06,
IL2CPP_TYPE_U2 = 0x07,
IL2CPP_TYPE_I4 = 0x08,
IL2CPP_TYPE_U4 = 0x09,
IL2CPP_TYPE_I8 = 0x0a,
IL2CPP_TYPE_U8 = 0x0b,
IL2CPP_TYPE_R4 = 0x0c,
IL2CPP_TYPE_R8 = 0x0d,
IL2CPP_TYPE_STRING = 0x0e,
IL2CPP_TYPE_PTR = 0x0f, /* arg: <type> token */
IL2CPP_TYPE_BYREF = 0x10, /* arg: <type> token */
IL2CPP_TYPE_VALUETYPE = 0x11, /* arg: <type> token */
IL2CPP_TYPE_CLASS = 0x12, /* arg: <type> token */
IL2CPP_TYPE_VAR = 0x13, /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */
IL2CPP_TYPE_ARRAY = 0x14, /* type, rank, boundsCount, bound1, loCount, lo1 */
IL2CPP_TYPE_GENERICINST = 0x15, /* <type> <type-arg-count> <type-1> \x{2026} <type-n> */
IL2CPP_TYPE_TYPEDBYREF = 0x16,
IL2CPP_TYPE_I = 0x18,
IL2CPP_TYPE_U = 0x19,
IL2CPP_TYPE_FNPTR = 0x1b, /* arg: full method signature */
IL2CPP_TYPE_OBJECT = 0x1c,
IL2CPP_TYPE_SZARRAY = 0x1d, /* 0-based one-dim-array */
IL2CPP_TYPE_MVAR = 0x1e, /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer) */
IL2CPP_TYPE_CMOD_REQD = 0x1f, /* arg: typedef or typeref token */
IL2CPP_TYPE_CMOD_OPT = 0x20, /* optional arg: typedef or typref token */
IL2CPP_TYPE_INTERNAL = 0x21, /* CLR internal type */
IL2CPP_TYPE_MODIFIER = 0x40, /* Or with the following types */
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
IL2CPP_TYPE_ENUM = 0x55 /* an enumeration */
}
public class Il2CppType
{
public ulong datapoint;
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
public uint num_mods { get; set; }
public uint byref { get; set; }
public uint pinned { get; set; }
public void Init()
{
var str = Convert.ToString(bits, 2);
if (str.Length != 32)
{
str = new string(Enumerable.Repeat('0', 32 - str.Length).Concat(str.ToCharArray()).ToArray());
}
attrs = Convert.ToUInt32(str.Substring(16, 16), 2);
type = (Il2CppTypeEnum)Convert.ToInt32(str.Substring(8, 8), 2);
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Union { dummy = datapoint };
}
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}
}
public class Il2CppGenericClass
{
public long typeDefinitionIndex; /* the generic type definition */
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
public ulong cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */
}
public class Il2CppGenericContext
{
/* The instantiation corresponding to the class generic parameters */
public ulong class_inst;
/* The instantiation corresponding to the method generic parameters */
public ulong method_inst;
}
public class Il2CppGenericInst
{
public ulong type_argc;
public ulong type_argv;
}
public class Il2CppArrayType
{
public ulong etype;
public byte rank;
public byte numsizes;
public byte numlobounds;
public ulong sizes;
public ulong lobounds;
}
}

View file

@ -1,369 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v16
{
class Dump
{
static Metadata metadata;
static Macho il2cpp;
public static void Dumpv16(byte[] il2cppfile, byte[] metadatafile)
{
//判断il2cpp的magic
var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0);
switch (il2cppmagic)
{
default:
throw new Exception("ERROR: il2cpp file not supported.");
case 0xCAFEBABE:
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
_64bit.Dump.Dump64bit(il2cppfile, metadatafile);
break;
case 0xFEEDFACE: // 32-bit mach object file
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration, metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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");
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 (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("\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();
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(i));
}
writer.Write("\n");
}
if (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("\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 (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("\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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
}
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
for (var i = 0; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
}
}

View file

@ -1,48 +0,0 @@
using System.IO;
namespace Il2CppDumper.v16
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public uint[] methodPointers;
private int[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract uint MapVATR(uint uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
fieldOffsets = MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int fieldIndex)
{
return fieldOffsets[fieldIndex];
}
public T MapVATR<T>(uint uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Il2CppDumper.v16
{
@ -91,7 +88,7 @@ namespace Il2CppDumper.v16
public class Il2CppType
{
public uint datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -111,17 +108,15 @@ namespace Il2CppDumper.v16
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public uint dummy;
public int klassIndex => (int)dummy;
public uint type => dummy;
public uint array => dummy;
public int genericParameterIndex => (int)dummy;
public uint generic_class => dummy;
}
@ -142,7 +137,6 @@ namespace Il2CppDumper.v16
public uint method_inst;
}
public class Il2CppGenericInst
{
public uint type_argc;

View file

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v16
{
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 (var 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 (var 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);
}
public 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 + 22u;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
}
}

View file

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v16
{
class Metadata : MyBinaryReader
{
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Metadata(Stream stream) : base(stream)
{
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
//GetTypeDefFromIndex
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
//GetMethodDefinition
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
//GetParameterFromIndex
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//GetFieldDefaultValuesFromIndex
fieldDefaultValues = ReadClassArray<Il2CppFieldDefaultValue>(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(typeof(Il2CppFieldDefaultValue)));
//GetPropertyDefinitionFromIndex
propertyDefs = ReadClassArray<Il2CppPropertyDefinition>(pMetadataHdr.propertiesOffset, pMetadataHdr.propertiesCount / MySizeOf(typeof(Il2CppPropertyDefinition)));
}
public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}

View file

@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Il2CppDumper.v20._64bit
{
public class Il2CppCodeRegistration
{
public ulong methodPointersCount;
public ulong methodPointers;
public ulong delegateWrappersFromNativeToManagedCount;
public ulong delegateWrappersFromNativeToManaged; // note the double indirection to handle different calling conventions
public ulong delegateWrappersFromManagedToNativeCount;
public ulong delegateWrappersFromManagedToNative;
public ulong marshalingFunctionsCount;
public ulong marshalingFunctions;
public ulong genericMethodPointersCount;
public ulong genericMethodPointers;
public ulong invokerPointersCount;
public ulong invokerPointers;
public long customAttributeCount;
public ulong customAttributeGenerators;
}
public class Il2CppMetadataRegistration
{
public long genericClassesCount;
public ulong genericClasses;
public long genericInstsCount;
public ulong genericInsts;
public long genericMethodTableCount;
public ulong genericMethodTable;
public long typesCount;
public ulong types;
public long methodSpecsCount;
public ulong methodSpecs;
public long fieldOffsetsCount;
public ulong fieldOffsets;
public long typeDefinitionsSizesCount;
public ulong typeDefinitionsSizes;
public ulong metadataUsagesCount;
public ulong metadataUsages;
}
public enum Il2CppTypeEnum
{
IL2CPP_TYPE_END = 0x00, /* End of List */
IL2CPP_TYPE_VOID = 0x01,
IL2CPP_TYPE_BOOLEAN = 0x02,
IL2CPP_TYPE_CHAR = 0x03,
IL2CPP_TYPE_I1 = 0x04,
IL2CPP_TYPE_U1 = 0x05,
IL2CPP_TYPE_I2 = 0x06,
IL2CPP_TYPE_U2 = 0x07,
IL2CPP_TYPE_I4 = 0x08,
IL2CPP_TYPE_U4 = 0x09,
IL2CPP_TYPE_I8 = 0x0a,
IL2CPP_TYPE_U8 = 0x0b,
IL2CPP_TYPE_R4 = 0x0c,
IL2CPP_TYPE_R8 = 0x0d,
IL2CPP_TYPE_STRING = 0x0e,
IL2CPP_TYPE_PTR = 0x0f, /* arg: <type> token */
IL2CPP_TYPE_BYREF = 0x10, /* arg: <type> token */
IL2CPP_TYPE_VALUETYPE = 0x11, /* arg: <type> token */
IL2CPP_TYPE_CLASS = 0x12, /* arg: <type> token */
IL2CPP_TYPE_VAR = 0x13, /* Generic parameter in a generic type definition, represented as number (compressed unsigned integer) number */
IL2CPP_TYPE_ARRAY = 0x14, /* type, rank, boundsCount, bound1, loCount, lo1 */
IL2CPP_TYPE_GENERICINST = 0x15, /* <type> <type-arg-count> <type-1> \x{2026} <type-n> */
IL2CPP_TYPE_TYPEDBYREF = 0x16,
IL2CPP_TYPE_I = 0x18,
IL2CPP_TYPE_U = 0x19,
IL2CPP_TYPE_FNPTR = 0x1b, /* arg: full method signature */
IL2CPP_TYPE_OBJECT = 0x1c,
IL2CPP_TYPE_SZARRAY = 0x1d, /* 0-based one-dim-array */
IL2CPP_TYPE_MVAR = 0x1e, /* Generic parameter in a generic method definition, represented as number (compressed unsigned integer) */
IL2CPP_TYPE_CMOD_REQD = 0x1f, /* arg: typedef or typeref token */
IL2CPP_TYPE_CMOD_OPT = 0x20, /* optional arg: typedef or typref token */
IL2CPP_TYPE_INTERNAL = 0x21, /* CLR internal type */
IL2CPP_TYPE_MODIFIER = 0x40, /* Or with the following types */
IL2CPP_TYPE_SENTINEL = 0x41, /* Sentinel for varargs method signature */
IL2CPP_TYPE_PINNED = 0x45, /* Local var that points to pinned object */
IL2CPP_TYPE_ENUM = 0x55 /* an enumeration */
}
public class Il2CppType
{
public ulong datapoint;
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
public uint num_mods { get; set; }
public uint byref { get; set; }
public uint pinned { get; set; }
public void Init()
{
var str = Convert.ToString(bits, 2);
if (str.Length != 32)
{
str = new string(Enumerable.Repeat('0', 32 - str.Length).Concat(str.ToCharArray()).ToArray());
}
attrs = Convert.ToUInt32(str.Substring(16, 16), 2);
type = (Il2CppTypeEnum)Convert.ToInt32(str.Substring(8, 8), 2);
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Union { dummy = datapoint };
}
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}
}
public class Il2CppGenericClass
{
public long typeDefinitionIndex; /* the generic type definition */
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
public ulong cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */
}
public class Il2CppGenericContext
{
/* The instantiation corresponding to the class generic parameters */
public ulong class_inst;
/* The instantiation corresponding to the method generic parameters */
public ulong method_inst;
}
public class Il2CppGenericInst
{
public ulong type_argc;
public ulong type_argv;
}
public class Il2CppArrayType
{
public ulong etype;
public byte rank;
public byte numsizes;
public byte numlobounds;
public ulong sizes;
public ulong lobounds;
}
}

View file

@ -1,381 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v20
{
class Dump
{
static Metadata metadata;
static Il2Cpp il2cpp;
public static void Dumpv20(byte[] il2cppfile, byte[] metadatafile)
{
//判断il2cpp的magic
var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0);
var isElf = false;
switch (il2cppmagic)
{
default:
throw new Exception("ERROR: il2cpp file not supported.");
case 0x464c457f:
isElf = true;
goto case 0xFEEDFACE;
case 0xCAFEBABE:
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
_64bit.Dump.Dump64bit(il2cppfile, metadatafile);
break;
case 0xFEEDFACE: // 32-bit mach object file
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile));
else
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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");
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 (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("\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();
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(i));
}
writer.Write("\n");
}
if (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("\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 (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("\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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
}
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
for (var i = 0; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
}
}

View file

@ -1,153 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v20
{
class Elf : Il2Cpp
{
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();
elf_header.m_arch = ReadByte();
if (elf_header.m_arch == 2)//64
{
throw new Exception("ERROR: 64 bit not supported.");
}
elf_header.m_endian = ReadByte();
elf_header.m_version = ReadByte();
elf_header.m_osabi = ReadByte();
elf_header.m_osabi_ver = ReadByte();
elf_header.e_pad = ReadBytes(7);
elf_header.e_type = ReadUInt16();
elf_header.e_machine = ReadUInt16();
elf_header.e_version = ReadUInt32();
elf_header.e_entry = ReadUInt32();
elf_header.e_phoff = ReadUInt32();
elf_header.e_shoff = ReadUInt32();
elf_header.e_flags = ReadUInt32();
elf_header.e_ehsize = ReadUInt16();
elf_header.e_phentsize = ReadUInt16();
elf_header.e_phnum = ReadUInt16();
elf_header.e_shentsize = ReadUInt16();
elf_header.e_shnum = ReadUInt16();
elf_header.e_shtrndx = ReadUInt16();
program_table_element = ReadClassArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
}
public Elf(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
public 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);
}
//TODO 需要验证
public override bool Auto()
{
throw new NotSupportedException("Auto no supported");
/*//取.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

@ -1,48 +0,0 @@
using System.IO;
namespace Il2CppDumper.v20
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public uint[] methodPointers;
private int[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract uint MapVATR(uint uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
fieldOffsets = MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int fieldIndex)
{
return fieldOffsets[fieldIndex];
}
public T MapVATR<T>(uint uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -91,7 +91,7 @@ namespace Il2CppDumper.v20
public class Il2CppType
{
public uint datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -111,17 +111,15 @@ namespace Il2CppDumper.v20
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public uint dummy;
public int klassIndex => (int)dummy;
public uint type => dummy;
public uint array => dummy;
public int genericParameterIndex => (int)dummy;
public uint generic_class => dummy;
}
@ -142,7 +140,6 @@ namespace Il2CppDumper.v20
public uint method_inst;
}
public class Il2CppGenericInst
{
public uint type_argc;

View file

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v20
{
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 (var 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 (var 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);
}
public 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 + 22u;
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
}
}

View file

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v20
{
class Metadata : MyBinaryReader
{
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Metadata(Stream stream) : base(stream)
{
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
//GetTypeDefFromIndex
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
//GetMethodDefinition
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
//GetParameterFromIndex
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//GetFieldDefaultValuesFromIndex
fieldDefaultValues = ReadClassArray<Il2CppFieldDefaultValue>(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(typeof(Il2CppFieldDefaultValue)));
//GetPropertyDefinitionFromIndex
propertyDefs = ReadClassArray<Il2CppPropertyDefinition>(pMetadataHdr.propertiesOffset, pMetadataHdr.propertiesCount / MySizeOf(typeof(Il2CppPropertyDefinition)));
}
public Il2CppFieldDefaultValue GetFieldDefaultFromIndex(int idx)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}

View file

@ -1,367 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper._64bit
{
class Dump
{
static Metadata metadata;
static Macho il2cpp;
public static void Dump64bit(byte[] il2cppfile, byte[] metadatafile)
{
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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);
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<ulong>(pInst.type_argv, (long)pInst.type_argc);
for (var i = 0u; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var 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.types[typeIndex]), il2cpp.customAttributeGenerators[index]);
}
return sb.ToString();
}
}
}

View file

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper._64bit
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public ulong[] methodPointers;
public ulong[] customAttributeGenerators;
private long[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract ulong MapVATR(ulong uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(ulong codeRegistration, ulong metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<long>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((ulong)ptr) + 8u * (ulong)fieldIndexInType;
return ReadInt32();
}
return 0;
}
public T MapVATR<T>(ulong uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(ulong uiAddr, long count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -95,7 +95,7 @@ namespace Il2CppDumper._64bit
public class Il2CppType
{
public ulong datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -115,17 +115,15 @@ namespace Il2CppDumper._64bit
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}
@ -146,7 +144,6 @@ namespace Il2CppDumper._64bit
public ulong method_inst;
}
public class Il2CppGenericInst
{
public ulong type_argc;

View file

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper._64bit
{
class Macho : Il2Cpp
{
private List<MachoSection64bit> sections = new List<MachoSection64bit>();
private static byte[] FeatureBytes1 = { 0x2, 0x0, 0x80, 0xD2 };//MOV X2, #0
private static byte[] FeatureBytes2 = { 0x3, 0x0, 0x80, 0x52 };//MOV W3, #0
public Macho(Stream stream) : base(stream)
{
Position += 16;//skip
var ncmds = ReadUInt32();
Position += 12;//skip
for (var i = 0; i < ncmds; i++)
{
var offset = Position;
var loadCommandType = ReadUInt32();
var command_size = ReadUInt32();
if (loadCommandType == 0x19) //SEGMENT_64
{
var segment_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
if (segment_name == "__TEXT" || segment_name == "__DATA")
{
Position += 40;//skip
var number_of_sections = ReadUInt32();
Position += 4;//skip
for (var j = 0; j < number_of_sections; j++)
{
var section_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
Position += 16;//skip
var address = ReadUInt64();
var size = ReadUInt64();
var offset2 = (uint)ReadUInt64();
var end = address + size;
sections.Add(new MachoSection64bit() { section_name = section_name, address = address, size = size, offset = offset2, end = end });
Position += 24;
}
}
}
Position = offset + command_size;//skip
}
}
public Macho(Stream stream, ulong codeRegistration, ulong metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
public override ulong MapVATR(ulong 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<ulong>(__mod_init_func.offset, (long)__mod_init_func.size / 8);
foreach (var i in addrs)
{
if (i > 0)
{
Position = MapVATR(i);
var buff = ReadBytes(4);
if (FeatureBytes1.SequenceEqual(buff))
{
buff = ReadBytes(4);
if (FeatureBytes2.SequenceEqual(buff))
{
Position += 8;
var subaddr = decodeAdr(i + 16, ReadBytes(4));
var rsubaddr = MapVATR(subaddr);
Position = rsubaddr;
var codeRegistration = decodeAdrp(subaddr, ReadBytes(4));
codeRegistration += decodeAdd(ReadBytes(4));
Position = rsubaddr + 8;
var metadataRegistration = decodeAdrp(subaddr + 8, ReadBytes(4));
metadataRegistration += decodeAdd(ReadBytes(4));
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
}
}

View file

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public uint[] methodPointers;
public uint[] customAttributeGenerators;
private int[] fieldOffsets;
public Il2CppType[] types;
private bool isNew21;
public abstract bool Auto();
public abstract uint MapVATR(uint uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<uint>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
//TODO 在21版本中存在两种FieldOffset通过对第一非0数值进行判断确认是指针还是int
isNew21 = fieldOffsets.First(x => x > 0) > 1000;
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType, int fieldIndex)
{
if (isNew21)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((uint)ptr) + 4 * fieldIndexInType;
return ReadInt32();
}
return 0;
}
return fieldOffsets[fieldIndex];
}
public T MapVATR<T>(uint uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -4,7 +4,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Il2CppDumper
namespace Il2CppDumper.v21
{
public class Il2CppCodeRegistration
{
@ -95,7 +95,7 @@ namespace Il2CppDumper
public class Il2CppType
{
public uint datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -115,17 +115,15 @@ namespace Il2CppDumper
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public uint dummy;
public int klassIndex => (int)dummy;
public uint type => dummy;
public uint array => dummy;
public int genericParameterIndex => (int)dummy;
public uint generic_class => dummy;
}
@ -146,7 +144,6 @@ namespace Il2CppDumper
public uint method_inst;
}
public class Il2CppGenericInst
{
public uint type_argc;

View file

@ -1,86 +0,0 @@
using System;
using System.IO;
using System.Linq;
namespace Il2CppDumper
{
class Metadata : MyBinaryReader
{
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributesInfos;
public int[] attributeTypes;
public Metadata(Stream stream) : base(stream)
{
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
//GetTypeDefFromIndex
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
//GetMethodDefinition
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
//GetParameterFromIndex
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//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)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Il2CppDumper
namespace Il2CppDumper.v21
{
public class Il2CppGlobalMetadataHeader
{

View file

@ -1,367 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v22._64bit
{
class Dump
{
static Metadata metadata;
static Macho il2cpp;
public static void Dump64bit(byte[] il2cppfile, byte[] metadatafile)
{
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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);
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<ulong>(pInst.type_argv, (long)pInst.type_argc);
for (var i = 0u; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var 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.types[typeIndex]), il2cpp.customAttributeGenerators[index]);
}
return sb.ToString();
}
}
}

View file

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v22._64bit
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public ulong[] methodPointers;
public ulong[] customAttributeGenerators;
private long[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract ulong MapVATR(ulong uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(ulong codeRegistration, ulong metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<long>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((ulong)ptr) + 8u * (ulong)fieldIndexInType;
return ReadInt32();
}
return 0;
}
public T MapVATR<T>(ulong uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(ulong uiAddr, long count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -97,7 +97,7 @@ namespace Il2CppDumper.v22._64bit
public class Il2CppType
{
public ulong datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -117,17 +117,15 @@ namespace Il2CppDumper.v22._64bit
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}
@ -148,7 +146,6 @@ namespace Il2CppDumper.v22._64bit
public ulong method_inst;
}
public class Il2CppGenericInst
{
public ulong type_argc;

View file

@ -1,398 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v22
{
class Dump
{
static Metadata metadata;
static Il2Cpp il2cpp;
public static void Dumpv22(byte[] il2cppfile, byte[] metadatafile)
{
//判断il2cpp的magic
var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0);
var isElf = false;
switch (il2cppmagic)
{
default:
throw new Exception("ERROR: il2cpp file not supported.");
case 0x464c457f:
isElf = true;
goto case 0xFEEDFACE;
case 0xCAFEBABE:
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
_64bit.Dump.Dump64bit(il2cppfile, metadatafile);
break;
case 0xFEEDFACE: // 32-bit mach object file
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile));
else
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
}
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
for (var i = 0; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var 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.types[typeIndex]), il2cpp.customAttributeGenerators[index]);
}
return sb.ToString();
}
}
}

View file

@ -1,151 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v22
{
class Elf : Il2Cpp
{
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();
elf_header.m_arch = ReadByte();
if (elf_header.m_arch == 2)//64
{
throw new Exception("ERROR: 64 bit not supported.");
}
elf_header.m_endian = ReadByte();
elf_header.m_version = ReadByte();
elf_header.m_osabi = ReadByte();
elf_header.m_osabi_ver = ReadByte();
elf_header.e_pad = ReadBytes(7);
elf_header.e_type = ReadUInt16();
elf_header.e_machine = ReadUInt16();
elf_header.e_version = ReadUInt32();
elf_header.e_entry = ReadUInt32();
elf_header.e_phoff = ReadUInt32();
elf_header.e_shoff = ReadUInt32();
elf_header.e_flags = ReadUInt32();
elf_header.e_ehsize = ReadUInt16();
elf_header.e_phentsize = ReadUInt16();
elf_header.e_phnum = ReadUInt16();
elf_header.e_shentsize = ReadUInt16();
elf_header.e_shnum = ReadUInt16();
elf_header.e_shtrndx = ReadUInt16();
program_table_element = ReadClassArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
}
public Elf(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
public 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 override bool Auto()
{
//取.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

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v22
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public uint[] methodPointers;
public uint[] customAttributeGenerators;
private int[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract uint MapVATR(uint uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<uint>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((uint)ptr) + 4 * fieldIndexInType;
return ReadInt32();
}
return 0;
}
public T MapVATR<T>(uint uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -97,7 +97,7 @@ namespace Il2CppDumper.v22
public class Il2CppType
{
public uint datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -117,17 +117,15 @@ namespace Il2CppDumper.v22
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public uint dummy;
public int klassIndex => (int)dummy;
public uint type => dummy;
public uint array => dummy;
public int genericParameterIndex => (int)dummy;
public uint generic_class => dummy;
}
@ -148,7 +146,6 @@ namespace Il2CppDumper.v22
public uint method_inst;
}
public class Il2CppGenericInst
{
public uint type_argc;

View file

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v22
{
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 (var 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 (var 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);
}
public 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;
}
}
}

View file

@ -1,86 +0,0 @@
using System;
using System.IO;
using System.Linq;
namespace Il2CppDumper.v22
{
class Metadata : MyBinaryReader
{
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributesInfos;
public int[] attributeTypes;
public Metadata(Stream stream) : base(stream)
{
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
//GetTypeDefFromIndex
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
//GetMethodDefinition
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
//GetParameterFromIndex
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//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)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}

View file

@ -1,367 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v23._64bit
{
class Dump
{
static Metadata metadata;
static Macho il2cpp;
public static void Dump64bit(byte[] il2cppfile, byte[] metadatafile)
{
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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);
metadata = new Metadata(new MemoryStream(metadatafile));
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<ulong>(pInst.type_argv, (long)pInst.type_argc);
for (var i = 0u; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var 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.types[typeIndex]), il2cpp.customAttributeGenerators[index]);
}
return sb.ToString();
}
}
}

View file

@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v23._64bit
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public ulong[] methodPointers;
public ulong[] customAttributeGenerators;
private long[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract ulong MapVATR(ulong uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(ulong codeRegistration, ulong metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<ulong>(pCodeRegistration.methodPointers, (long)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<ulong>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<long>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<ulong>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((ulong)ptr) + 8u * (ulong)fieldIndexInType;
return ReadInt32();
}
return 0;
}
public T MapVATR<T>(ulong uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(ulong uiAddr, long count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -90,7 +90,7 @@ namespace Il2CppDumper.v23._64bit
public class Il2CppType
{
public ulong datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -110,17 +110,15 @@ namespace Il2CppDumper.v23._64bit
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public ulong dummy;
public long klassIndex => (long)dummy;
public ulong type => dummy;
public ulong array => dummy;
public long genericParameterIndex => (long)dummy;
public ulong generic_class => dummy;
}

View file

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v23._64bit
{
class Macho : Il2Cpp
{
private List<MachoSection64bit> sections = new List<MachoSection64bit>();
private static byte[] FeatureBytes1 = { 0x2, 0x0, 0x80, 0xD2 };//MOV X2, #0
private static byte[] FeatureBytes2 = { 0x3, 0x0, 0x80, 0x52 };//MOV W3, #0
public Macho(Stream stream) : base(stream)
{
Position += 16;//skip
var ncmds = ReadUInt32();
Position += 12;//skip
for (var i = 0; i < ncmds; i++)
{
var offset = Position;
var loadCommandType = ReadUInt32();
var command_size = ReadUInt32();
if (loadCommandType == 0x19) //SEGMENT_64
{
var segment_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
if (segment_name == "__TEXT" || segment_name == "__DATA")
{
Position += 40;//skip
var number_of_sections = ReadUInt32();
Position += 4;//skip
for (var j = 0; j < number_of_sections; j++)
{
var section_name = Encoding.UTF8.GetString(ReadBytes(16)).TrimEnd('\0');
Position += 16;//skip
var address = ReadUInt64();
var size = ReadUInt64();
var offset2 = (uint)ReadUInt64();
var end = address + size;
sections.Add(new MachoSection64bit() { section_name = section_name, address = address, size = size, offset = offset2, end = end });
Position += 24;
}
}
}
Position = offset + command_size;//skip
}
}
public Macho(Stream stream, ulong codeRegistration, ulong metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
public override ulong MapVATR(ulong 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<ulong>(__mod_init_func.offset, (long)__mod_init_func.size / 8);
foreach (var i in addrs)
{
if (i > 0)
{
Position = MapVATR(i);
var buff = ReadBytes(4);
if (FeatureBytes1.SequenceEqual(buff))
{
buff = ReadBytes(4);
if (FeatureBytes2.SequenceEqual(buff))
{
Position += 8;
var subaddr = decodeAdr(i + 16, ReadBytes(4));
var rsubaddr = MapVATR(subaddr);
Position = rsubaddr;
var codeRegistration = decodeAdrp(subaddr, ReadBytes(4));
codeRegistration += decodeAdd(ReadBytes(4));
Position = rsubaddr + 8;
var metadataRegistration = decodeAdrp(subaddr + 8, ReadBytes(4));
metadataRegistration += decodeAdd(ReadBytes(4));
Console.WriteLine("CodeRegistration : {0:x}", codeRegistration);
Console.WriteLine("MetadataRegistration : {0:x}", metadataRegistration);
Init(codeRegistration, metadataRegistration);
return true;
}
}
}
}
return false;
}
}
}

View file

@ -1,398 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using static Il2CppDumper.DefineConstants;
namespace Il2CppDumper.v23
{
class Dump
{
static Metadata metadata;
static Il2Cpp il2cpp;
public static void Dumpv23(byte[] il2cppfile, byte[] metadatafile)
{
//判断il2cpp的magic
var il2cppmagic = BitConverter.ToUInt32(il2cppfile, 0);
var isElf = false;
switch (il2cppmagic)
{
default:
throw new Exception("ERROR: il2cpp file not supported.");
case 0x464c457f:
isElf = true;
goto case 0xFEEDFACE;
case 0xCAFEBABE:
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
_64bit.Dump.Dump64bit(il2cppfile, metadatafile);
break;
case 0xFEEDFACE: // 32-bit mach object file
Console.WriteLine("Select Mode: 1. Manual 2.Auto");
var key = Console.ReadKey(true);
if (key.KeyChar == '2')
{
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile));
else
il2cpp = new Macho(new MemoryStream(il2cppfile));
if (!il2cpp.Auto())
{
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.ToUInt32(Console.ReadLine(), 16);
Console.Write("Input MetadataRegistration(R1): ");
var metadataRegistration = Convert.ToUInt32(Console.ReadLine(), 16);
metadata = new Metadata(new MemoryStream(metadatafile));
if (isElf)
il2cpp = new Elf(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
else
il2cpp = new Macho(new MemoryStream(il2cppfile), codeRegistration,
metadataRegistration);
}
else
{
return;
}
var writer = new StreamWriter(new FileStream("dump.cs", FileMode.Create));
Console.WriteLine("Dumping...");
//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 (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();
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 (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 (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]);
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");
}
}
writer.Close();
Console.WriteLine("Done !");
break;
}
}
private static string get_type_name(Il2CppType pType)
{
string ret;
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
{
var klass = metadata.typeDefs[pType.data.klassIndex];
ret = metadata.GetString(klass.nameIndex);
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
{
var generic_class = il2cpp.MapVATR<Il2CppGenericClass>(pType.data.generic_class);
var pMainDef = metadata.typeDefs[generic_class.typeDefinitionIndex];
ret = metadata.GetString(pMainDef.nameIndex);
var typeNames = new List<string>();
var pInst = il2cpp.MapVATR<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = il2cpp.MapVATR<uint>(pInst.type_argv, (int)pInst.type_argc);
for (var i = 0; i < pInst.type_argc; ++i)
{
var pOriType = il2cpp.MapVATR<Il2CppType>(pointers[i]);
pOriType.Init();
typeNames.Add(get_type_name(pOriType));
}
ret += $"<{string.Join(", ", typeNames)}>";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
{
var arrayType = il2cpp.MapVATR<Il2CppArrayType>(pType.data.array);
var type = il2cpp.MapVATR<Il2CppType>(arrayType.etype);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY)
{
var type = il2cpp.MapVATR<Il2CppType>(pType.data.type);
type.Init();
ret = $"{get_type_name(type)}[]";
}
else
{
if ((int)pType.type >= szTypeString.Length)
ret = "unknow";
else
ret = szTypeString[(int)pType.type];
}
return ret;
}
private static string GetCustomAttribute(int index, string padding = "")
{
var attributeTypeRange = metadata.attributesInfos[index];
var sb = new StringBuilder();
for (var 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.types[typeIndex]), il2cpp.customAttributeGenerators[index]);
}
return sb.ToString();
}
}
}

View file

@ -1,151 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v23
{
class Elf : Il2Cpp
{
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();
elf_header.m_arch = ReadByte();
if (elf_header.m_arch == 2)//64
{
throw new Exception("ERROR: 64 bit not supported.");
}
elf_header.m_endian = ReadByte();
elf_header.m_version = ReadByte();
elf_header.m_osabi = ReadByte();
elf_header.m_osabi_ver = ReadByte();
elf_header.e_pad = ReadBytes(7);
elf_header.e_type = ReadUInt16();
elf_header.e_machine = ReadUInt16();
elf_header.e_version = ReadUInt32();
elf_header.e_entry = ReadUInt32();
elf_header.e_phoff = ReadUInt32();
elf_header.e_shoff = ReadUInt32();
elf_header.e_flags = ReadUInt32();
elf_header.e_ehsize = ReadUInt16();
elf_header.e_phentsize = ReadUInt16();
elf_header.e_phnum = ReadUInt16();
elf_header.e_shentsize = ReadUInt16();
elf_header.e_shnum = ReadUInt16();
elf_header.e_shtrndx = ReadUInt16();
program_table_element = ReadClassArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
}
public Elf(Stream stream, uint codeRegistration, uint metadataRegistration) : this(stream)
{
Init(codeRegistration, metadataRegistration);
}
public 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 override bool Auto()
{
//取.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

@ -1,56 +0,0 @@
using System.IO;
namespace Il2CppDumper.v23
{
abstract class Il2Cpp : MyBinaryReader
{
private Il2CppMetadataRegistration pMetadataRegistration;
private Il2CppCodeRegistration pCodeRegistration;
public uint[] methodPointers;
public uint[] customAttributeGenerators;
private int[] fieldOffsets;
public Il2CppType[] types;
public abstract bool Auto();
public abstract uint MapVATR(uint uiAddr);
protected Il2Cpp(Stream stream) : base(stream) { }
protected void Init(uint codeRegistration, uint metadataRegistration)
{
pCodeRegistration = MapVATR<Il2CppCodeRegistration>(codeRegistration);
pMetadataRegistration = MapVATR<Il2CppMetadataRegistration>(metadataRegistration);
methodPointers = MapVATR<uint>(pCodeRegistration.methodPointers, (int)pCodeRegistration.methodPointersCount);
customAttributeGenerators = MapVATR<uint>(pCodeRegistration.customAttributeGenerators, pCodeRegistration.customAttributeCount);
fieldOffsets = MapVATR<int>(pMetadataRegistration.fieldOffsets, pMetadataRegistration.fieldOffsetsCount);
var ptypes = MapVATR<uint>(pMetadataRegistration.types, pMetadataRegistration.typesCount);
types = new Il2CppType[pMetadataRegistration.typesCount];
for (var i = 0; i < pMetadataRegistration.typesCount; ++i)
{
types[i] = MapVATR<Il2CppType>(ptypes[i]);
types[i].Init();
}
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType)
{
var ptr = fieldOffsets[typeIndex];
if (ptr >= 0)
{
Position = MapVATR((uint)ptr) + 4 * fieldIndexInType;
return ReadInt32();
}
return 0;
}
public T MapVATR<T>(uint uiAddr) where T : new()
{
return ReadClass<T>(MapVATR(uiAddr));
}
public T[] MapVATR<T>(uint uiAddr, int count) where T : new()
{
return ReadClassArray<T>(MapVATR(uiAddr), count);
}
}
}

View file

@ -90,7 +90,7 @@ namespace Il2CppDumper.v23
public class Il2CppType
{
public uint datapoint;
public Anonymous data { get; set; }
public Union data { get; set; }
public uint bits;
public uint attrs { get; set; }
public Il2CppTypeEnum type { get; set; }
@ -110,17 +110,15 @@ namespace Il2CppDumper.v23
num_mods = Convert.ToUInt32(str.Substring(2, 6), 2);
byref = Convert.ToUInt32(str.Substring(1, 1), 2);
pinned = Convert.ToUInt32(str.Substring(0, 1), 2);
data = new Anonymous() { dummy = datapoint };
data = new Union { dummy = datapoint };
}
public class Anonymous
public class Union
{
public uint 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

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using static Il2CppDumper.ArmHelper;
namespace Il2CppDumper.v23
{
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 (var 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 (var 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);
}
public 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;
}
}
}

View file

@ -1,88 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Il2CppDumper.v23
{
class Metadata : MyBinaryReader
{
private Il2CppGlobalMetadataHeader pMetadataHdr;
public int uiImageCount;
public int uiNumTypes;
public Il2CppImageDefinition[] imageDefs;
public Il2CppTypeDefinition[] typeDefs;
public Il2CppMethodDefinition[] methodDefs;
public Il2CppParameterDefinition[] parameterDefs;
public Il2CppFieldDefinition[] fieldDefs;
private Il2CppFieldDefaultValue[] fieldDefaultValues;
public Il2CppPropertyDefinition[] propertyDefs;
public Il2CppCustomAttributeTypeRange[] attributesInfos;
public int[] attributeTypes;
public Metadata(Stream stream) : base(stream)
{
pMetadataHdr = ReadClass<Il2CppGlobalMetadataHeader>();
uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
imageDefs = ReadClassArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
//GetTypeDefFromIndex
typeDefs = ReadClassArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
//GetMethodDefinition
methodDefs = ReadClassArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
//GetParameterFromIndex
parameterDefs = ReadClassArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
//GetFieldDefFromIndex
fieldDefs = ReadClassArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
//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)
{
return fieldDefaultValues.FirstOrDefault(x => x.fieldIndex == idx);
}
public int GetDefaultValueFromIndex(int idx)
{
return pMetadataHdr.fieldAndParameterDefaultValueDataOffset + idx;
}
public string GetString(int idx)
{
return ReadStringToNull(pMetadataHdr.stringOffset + idx);
}
private int MySizeOf(Type type)
{
var size = 0;
foreach (var i in type.GetFields())
{
if (i.FieldType == typeof(int))
{
size += 4;
}
else if (i.FieldType == typeof(uint))
{
size += 4;
}
else if (i.FieldType == typeof(short))
{
size += 2;
}
else if (i.FieldType == typeof(ushort))
{
size += 2;
}
}
return size;
}
}
}