mirror of
https://github.com/Perfare/Il2CppDumper.git
synced 2025-01-10 03:27:28 -03:00
重构,添加通用处理类
This commit is contained in:
parent
5c0a706d6a
commit
bbfb533b7f
50 changed files with 1312 additions and 5050 deletions
|
@ -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();
|
|
@ -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 />
|
||||
|
|
159
Il2CppDumper/Il2CppGeneric.cs
Normal file
159
Il2CppDumper/Il2CppGeneric.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
125
Il2CppDumper/Il2CppGenericClass.cs
Normal file
125
Il2CppDumper/Il2CppGenericClass.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
121
Il2CppDumper/MetadataGeneric.cs
Normal file
121
Il2CppDumper/MetadataGeneric.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
92
Il2CppDumper/MetadataGenericClass.cs
Normal file
92
Il2CppDumper/MetadataGenericClass.cs
Normal 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
27
Il2CppDumper/MyCopy.cs
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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++)
|
||||
|
|
155
Il2CppDumper/v16/64bit/Il2CppClass.cs
Normal file
155
Il2CppDumper/v16/64bit/Il2CppClass.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
158
Il2CppDumper/v20/64bit/Il2CppClass.cs
Normal file
158
Il2CppDumper/v20/64bit/Il2CppClass.cs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppDumper
|
||||
namespace Il2CppDumper.v21
|
||||
{
|
||||
public class Il2CppGlobalMetadataHeader
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue