Separate project from Il2Cpp2Proto
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "Bin2Object"]
|
||||
path = Bin2Object
|
||||
url = https://github.com/djkaty/Bin2Object
|
||||
1
Bin2Object
Submodule
1
Bin2Object
Submodule
Submodule Bin2Object added at 8cb9cc95df
161
Il2CppDumper/Il2CppDumper.cs
Normal file
161
Il2CppDumper/Il2CppDumper.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2017 Katy Coe - https://www.djkaty.com - https://github.com/djlaty
|
||||
// All rights reserved
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public class Il2CppDumper
|
||||
{
|
||||
private readonly Il2CppProcessor il2cpp;
|
||||
|
||||
public Il2CppDumper(Il2CppProcessor proc) {
|
||||
il2cpp = proc;
|
||||
}
|
||||
|
||||
public void WriteFile(string outFile) {
|
||||
using (var writer = new StreamWriter(new FileStream(outFile, FileMode.Create))) {
|
||||
var metadata = il2cpp.Metadata;
|
||||
|
||||
for (int imageIndex = 0; imageIndex < metadata.Images.Length; imageIndex++) {
|
||||
var imageDef = metadata.Images[imageIndex];
|
||||
writer.Write($"// Image {imageIndex}: {metadata.GetImageName(imageDef)} - {imageDef.typeStart}\n");
|
||||
}
|
||||
for (int idx = 0; idx < metadata.Types.Length; ++idx) {
|
||||
var typeDef = metadata.Types[idx];
|
||||
writer.Write($"// Namespace: {metadata.GetTypeNamespace(typeDef)}\n");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
|
||||
writer.Write("[Serializable]\n");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) ==
|
||||
DefineConstants.TYPE_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_ABSTRACT) != 0)
|
||||
writer.Write("abstract ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_SEALED) != 0)
|
||||
writer.Write("sealed ");
|
||||
if ((typeDef.flags & DefineConstants.TYPE_ATTRIBUTE_INTERFACE) != 0)
|
||||
writer.Write("interface ");
|
||||
else
|
||||
writer.Write("class ");
|
||||
writer.Write($"{metadata.GetTypeName(typeDef)} // TypeDefIndex: {idx}\n{{\n");
|
||||
writer.Write("\t// Fields\n");
|
||||
var fieldEnd = typeDef.fieldStart + typeDef.field_count;
|
||||
for (int i = typeDef.fieldStart; i < fieldEnd; ++i) {
|
||||
var pField = metadata.Fields[i];
|
||||
var pType = il2cpp.Code.GetTypeFromTypeIndex(pField.typeIndex);
|
||||
var pDefault = metadata.GetFieldDefaultFromIndex(i);
|
||||
writer.Write("\t");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PRIVATE) ==
|
||||
DefineConstants.FIELD_ATTRIBUTE_PRIVATE)
|
||||
writer.Write("private ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_PUBLIC) ==
|
||||
DefineConstants.FIELD_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_STATIC) != 0)
|
||||
writer.Write("static ");
|
||||
if ((pType.attrs & DefineConstants.FIELD_ATTRIBUTE_INIT_ONLY) != 0)
|
||||
writer.Write("readonly ");
|
||||
writer.Write($"{il2cpp.GetTypeName(pType)} {metadata.GetString(pField.nameIndex)}");
|
||||
if (pDefault != null && pDefault.dataIndex != -1) {
|
||||
var pointer = metadata.GetDefaultValueFromIndex(pDefault.dataIndex);
|
||||
Il2CppType pTypeToUse = il2cpp.Code.GetTypeFromTypeIndex(pDefault.typeIndex);
|
||||
if (pointer > 0) {
|
||||
metadata.Position = pointer;
|
||||
object multi = null;
|
||||
switch (pTypeToUse.type) {
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN:
|
||||
multi = metadata.ReadBoolean();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U1:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I1:
|
||||
multi = metadata.ReadByte();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CHAR:
|
||||
multi = metadata.ReadChar();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U2:
|
||||
multi = metadata.ReadUInt16();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I2:
|
||||
multi = metadata.ReadInt16();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U4:
|
||||
multi = metadata.ReadUInt32();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I4:
|
||||
multi = metadata.ReadInt32();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_U8:
|
||||
multi = metadata.ReadUInt64();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_I8:
|
||||
multi = metadata.ReadInt64();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_R4:
|
||||
multi = metadata.ReadSingle();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_R8:
|
||||
multi = metadata.ReadDouble();
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_STRING:
|
||||
var uiLen = metadata.ReadInt32();
|
||||
multi = Encoding.UTF8.GetString(metadata.ReadBytes(uiLen));
|
||||
break;
|
||||
}
|
||||
if (multi is string)
|
||||
writer.Write($" = \"{multi}\"");
|
||||
else if (multi != null)
|
||||
writer.Write($" = {multi}");
|
||||
}
|
||||
}
|
||||
writer.Write("; // 0x{0:x}\n",
|
||||
il2cpp.Code.GetFieldOffsetFromIndex(idx, i - typeDef.fieldStart));
|
||||
}
|
||||
writer.Write("\t// Methods\n");
|
||||
var methodEnd = typeDef.methodStart + typeDef.method_count;
|
||||
for (int i = typeDef.methodStart; i < methodEnd; ++i) {
|
||||
var methodDef = metadata.Methods[i];
|
||||
writer.Write("\t");
|
||||
Il2CppType pReturnType = il2cpp.Code.GetTypeFromTypeIndex(methodDef.returnType);
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) ==
|
||||
DefineConstants.METHOD_ATTRIBUTE_PRIVATE)
|
||||
writer.Write("private ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) ==
|
||||
DefineConstants.METHOD_ATTRIBUTE_PUBLIC)
|
||||
writer.Write("public ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_VIRTUAL) != 0)
|
||||
writer.Write("virtual ");
|
||||
if ((methodDef.flags & DefineConstants.METHOD_ATTRIBUTE_STATIC) != 0)
|
||||
writer.Write("static ");
|
||||
|
||||
writer.Write($"{il2cpp.GetTypeName(pReturnType)} {metadata.GetString(methodDef.nameIndex)}(");
|
||||
for (int j = 0; j < methodDef.parameterCount; ++j) {
|
||||
Il2CppParameterDefinition pParam = metadata.parameterDefs[methodDef.parameterStart + j];
|
||||
string szParamName = metadata.GetString(pParam.nameIndex);
|
||||
Il2CppType pType = il2cpp.Code.GetTypeFromTypeIndex(pParam.typeIndex);
|
||||
string szTypeName = il2cpp.GetTypeName(pType);
|
||||
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0)
|
||||
writer.Write("optional ");
|
||||
if ((pType.attrs & DefineConstants.PARAM_ATTRIBUTE_OUT) != 0)
|
||||
writer.Write("out ");
|
||||
if (j != methodDef.parameterCount - 1) {
|
||||
writer.Write($"{szTypeName} {szParamName}, ");
|
||||
}
|
||||
else {
|
||||
writer.Write($"{szTypeName} {szParamName}");
|
||||
}
|
||||
}
|
||||
if (methodDef.methodIndex >= 0)
|
||||
writer.Write("); // {0:x} - {1}\n",
|
||||
il2cpp.Code.PtrCodeRegistration.methodPointers[methodDef.methodIndex],
|
||||
methodDef.methodIndex);
|
||||
else
|
||||
writer.Write("); // 0 - -1\n");
|
||||
}
|
||||
writer.Write("}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Il2CppDumper/Il2CppDumper.csproj
Normal file
12
Il2CppDumper/Il2CppDumper.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Il2CppInspector\Il2CppInspector.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
52
Il2CppDumper/Program.cs
Normal file
52
Il2CppDumper/Program.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2017 Katy Coe - https://www.djkaty.com - https://github.com/djlaty
|
||||
// All rights reserved
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public class App
|
||||
{
|
||||
static void Main(string[] args) {
|
||||
|
||||
// Command-line usage: dotnet run [<binary-file> [<metadata-file> [<output-file>]]]
|
||||
// Defaults to libil2cpp.so or GameAssembly.dll if binary file not specified
|
||||
string imageFile = "libil2cpp.so";
|
||||
string metaFile = "global-metadata.dat";
|
||||
string outFile = "types.cs";
|
||||
|
||||
if (args.Length == 0)
|
||||
if (!File.Exists(imageFile))
|
||||
imageFile = "GameAssembly.dll";
|
||||
|
||||
if (args.Length >= 1)
|
||||
imageFile = args[0];
|
||||
|
||||
if (args.Length >= 2)
|
||||
metaFile = args[1];
|
||||
|
||||
if (args.Length >= 3)
|
||||
outFile = args[2];
|
||||
|
||||
// Check files
|
||||
if (!File.Exists(imageFile)) {
|
||||
Console.Error.WriteLine($"File {imageFile} does not exist");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
if (!File.Exists(metaFile)) {
|
||||
Console.Error.WriteLine($"File {metaFile} does not exist");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
// Analyze data
|
||||
var il2cpp = Il2CppProcessor.LoadFromFile(imageFile, metaFile);
|
||||
if (il2cpp == null)
|
||||
Environment.Exit(1);
|
||||
|
||||
// Write output file
|
||||
var dumper = new Il2CppDumper(il2cpp);
|
||||
dumper.WriteFile(outFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Il2CppInspector.sln
Normal file
34
Il2CppInspector.sln
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.9
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bin2Object", "Bin2Object\Bin2Object\Bin2Object.csproj", "{55382D6C-01B6-4AFD-850C-7A79DAB6F270}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppInspector", "Il2CppInspector\Il2CppInspector.csproj", "{E4721466-CC6F-47EB-AD48-F4DE70D77E5C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Il2CppDumper", "Il2CppDumper\Il2CppDumper.csproj", "{EA4C27DF-4640-48DF-8CAF-5587884CAF30}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{55382D6C-01B6-4AFD-850C-7A79DAB6F270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{55382D6C-01B6-4AFD-850C-7A79DAB6F270}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{55382D6C-01B6-4AFD-850C-7A79DAB6F270}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{55382D6C-01B6-4AFD-850C-7A79DAB6F270}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4721466-CC6F-47EB-AD48-F4DE70D77E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E4721466-CC6F-47EB-AD48-F4DE70D77E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E4721466-CC6F-47EB-AD48-F4DE70D77E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4721466-CC6F-47EB-AD48-F4DE70D77E5C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EA4C27DF-4640-48DF-8CAF-5587884CAF30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EA4C27DF-4640-48DF-8CAF-5587884CAF30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EA4C27DF-4640-48DF-8CAF-5587884CAF30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EA4C27DF-4640-48DF-8CAF-5587884CAF30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
20
Il2CppInspector/DefineConstants.cs
Normal file
20
Il2CppInspector/DefineConstants.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
public static class DefineConstants
|
||||
{
|
||||
public const int FIELD_ATTRIBUTE_PRIVATE = 0x0001;
|
||||
public const int FIELD_ATTRIBUTE_PUBLIC = 0x0006;
|
||||
public const int FIELD_ATTRIBUTE_STATIC = 0x0010;
|
||||
public const int FIELD_ATTRIBUTE_INIT_ONLY = 0x0020;
|
||||
public const int METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007;
|
||||
public const int METHOD_ATTRIBUTE_PRIVATE = 0x0001;
|
||||
public const int METHOD_ATTRIBUTE_PUBLIC = 0x0006;
|
||||
public const int METHOD_ATTRIBUTE_STATIC = 0x0010;
|
||||
public const int METHOD_ATTRIBUTE_VIRTUAL = 0x0040;
|
||||
public const int TYPE_ATTRIBUTE_VISIBILITY_MASK = 0x00000007;
|
||||
public const int TYPE_ATTRIBUTE_PUBLIC = 0x00000001;
|
||||
public const int TYPE_ATTRIBUTE_INTERFACE = 0x00000020;
|
||||
public const int TYPE_ATTRIBUTE_ABSTRACT = 0x00000080;
|
||||
public const int TYPE_ATTRIBUTE_SEALED = 0x00000100;
|
||||
public const int TYPE_ATTRIBUTE_SERIALIZABLE = 0x00002000;
|
||||
public const int PARAM_ATTRIBUTE_OUT = 0x0002;
|
||||
public const int PARAM_ATTRIBUTE_OPTIONAL = 0x0010;
|
||||
}
|
||||
89
Il2CppInspector/ElfHeaders.cs
Normal file
89
Il2CppInspector/ElfHeaders.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
internal class elf_header
|
||||
{
|
||||
// 0x7f followed by ELF in ascii
|
||||
public uint m_dwFormat;
|
||||
|
||||
// 1 - 32 bit
|
||||
// 2 - 64 bit
|
||||
public byte m_arch;
|
||||
|
||||
// 1 - little endian
|
||||
// 2 - big endian
|
||||
public byte m_endian;
|
||||
|
||||
// 1 is original elf format
|
||||
public byte m_version;
|
||||
|
||||
// set based on OS, refer to OSABI enum
|
||||
public byte m_osabi;
|
||||
|
||||
// refer to elf documentation
|
||||
public byte m_osabi_ver;
|
||||
|
||||
// unused
|
||||
[ArrayLength(FixedSize=7)]
|
||||
public byte[] e_pad;//byte[7]
|
||||
|
||||
// 1 - relocatable
|
||||
// 2 - executable
|
||||
// 3 - shared
|
||||
// 4 - core
|
||||
public ushort e_type;
|
||||
|
||||
// refer to isa enum
|
||||
public ushort e_machine;
|
||||
|
||||
public uint e_version;
|
||||
|
||||
public uint e_entry;
|
||||
public uint e_phoff;
|
||||
public uint e_shoff;
|
||||
public uint e_flags;
|
||||
public ushort e_ehsize;
|
||||
public ushort e_phentsize;
|
||||
public ushort e_phnum;
|
||||
public ushort e_shentsize;
|
||||
public ushort e_shnum;
|
||||
public ushort e_shtrndx;
|
||||
}
|
||||
|
||||
internal class program_header_table
|
||||
{
|
||||
public uint p_type;
|
||||
public uint p_offset;
|
||||
public uint p_vaddr;
|
||||
public uint p_paddr;
|
||||
public uint p_filesz;
|
||||
public uint p_memsz;
|
||||
public uint p_flags;
|
||||
public uint p_align;
|
||||
//public byte[] p_data;忽略
|
||||
}
|
||||
|
||||
internal class elf_32_shdr
|
||||
{
|
||||
public uint sh_name;
|
||||
public uint sh_type;
|
||||
public uint sh_flags;
|
||||
public uint sh_addr;
|
||||
public uint sh_offset;
|
||||
public uint sh_size;
|
||||
public uint sh_link;
|
||||
public uint sh_info;
|
||||
public uint sh_addralign;
|
||||
public uint sh_entsize;
|
||||
}
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
93
Il2CppInspector/ElfReader.cs
Normal file
93
Il2CppInspector/ElfReader.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
internal class ElfReader : FileFormatReader<ElfReader>
|
||||
{
|
||||
private program_header_table[] program_table_element;
|
||||
private elf_header elf_header;
|
||||
|
||||
public ElfReader(Stream stream) : base(stream) { }
|
||||
|
||||
public override string Arch {
|
||||
get {
|
||||
switch (elf_header.e_machine) {
|
||||
case 0x03:
|
||||
return "x86";
|
||||
case 0x28:
|
||||
return "ARM";
|
||||
default:
|
||||
return "Unsupported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool Init() {
|
||||
elf_header = ReadObject<elf_header>();
|
||||
|
||||
if (elf_header.m_dwFormat != 0x464c457f) {
|
||||
// Not an ELF file
|
||||
return false;
|
||||
}
|
||||
if (elf_header.m_arch == 2)//64
|
||||
{
|
||||
// 64-bit not supported
|
||||
return false;
|
||||
}
|
||||
program_table_element = ReadArray<program_header_table>(elf_header.e_phoff, elf_header.e_phnum);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override uint[] GetSearchLocations() {
|
||||
// Find dynamic section
|
||||
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;
|
||||
|
||||
// We need GOT, INIT_ARRAY and INIT_ARRAYSZ
|
||||
uint _GLOBAL_OFFSET_TABLE_ = 0;
|
||||
var init_array = new elf_32_shdr();
|
||||
Position = dynamic.sh_offset;
|
||||
var dynamicend = dynamic.sh_offset + dynamic.sh_size;
|
||||
while (Position < dynamicend) {
|
||||
var tag = ReadInt32();
|
||||
if (tag == 3) //DT_PLTGOT
|
||||
{
|
||||
_GLOBAL_OFFSET_TABLE_ = ReadUInt32();
|
||||
continue;
|
||||
}
|
||||
else if (tag == 25) //DT_INIT_ARRAY
|
||||
{
|
||||
init_array.sh_offset = MapVATR(ReadUInt32());
|
||||
continue;
|
||||
}
|
||||
else if (tag == 27) //DT_INIT_ARRAYSZ
|
||||
{
|
||||
init_array.sh_size = ReadUInt32();
|
||||
continue;
|
||||
}
|
||||
Position += 4;
|
||||
}
|
||||
if (_GLOBAL_OFFSET_TABLE_ == 0)
|
||||
throw new InvalidOperationException("Unable to get GLOBAL_OFFSET_TABLE from PT_DYNAMIC");
|
||||
GlobalOffset = _GLOBAL_OFFSET_TABLE_;
|
||||
return ReadArray<uint>(init_array.sh_offset, (int) init_array.sh_size / 4);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Il2CppInspector/FileFormatReader.cs
Normal file
70
Il2CppInspector/FileFormatReader.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public interface IFileFormatReader
|
||||
{
|
||||
BinaryObjectReader Stream { get; }
|
||||
long Position { get; set; }
|
||||
string Arch { get; }
|
||||
uint GlobalOffset { get; }
|
||||
uint[] GetSearchLocations();
|
||||
U ReadMappedObject<U>(uint uiAddr) where U : new();
|
||||
U[] ReadMappedArray<U>(uint uiAddr, int count) where U : new();
|
||||
uint MapVATR(uint uiAddr);
|
||||
|
||||
byte[] ReadBytes(int count);
|
||||
ulong ReadUInt64();
|
||||
uint ReadUInt32();
|
||||
ushort ReadUInt16();
|
||||
byte ReadByte();
|
||||
}
|
||||
|
||||
internal class FileFormatReader<T> : BinaryObjectReader, IFileFormatReader where T : FileFormatReader<T>
|
||||
{
|
||||
public FileFormatReader(Stream stream) : base(stream) { }
|
||||
|
||||
public BinaryObjectReader Stream => this;
|
||||
|
||||
public uint GlobalOffset { get; protected set; }
|
||||
|
||||
public virtual string Arch => throw new NotImplementedException();
|
||||
|
||||
public static T Load(string filename) {
|
||||
using (var stream = new FileStream(filename, FileMode.Open))
|
||||
return Load(stream);
|
||||
}
|
||||
|
||||
public static T Load(Stream stream) {
|
||||
stream.Position = 0;
|
||||
var pe = (T) Activator.CreateInstance(typeof(T), stream);
|
||||
return pe.Init() ? pe : null;
|
||||
}
|
||||
|
||||
// Confirm file is valid and set up RVA mappings
|
||||
protected virtual bool Init() => throw new NotImplementedException();
|
||||
|
||||
// Find search locations in the machine code for Il2Cpp data
|
||||
public virtual uint[] GetSearchLocations() => throw new NotImplementedException();
|
||||
|
||||
// Map an RVA to an offset into the file image
|
||||
public virtual uint MapVATR(uint uiAddr) => throw new NotImplementedException();
|
||||
|
||||
// Retrieve object(s) from specified RVA(s)
|
||||
public U ReadMappedObject<U>(uint uiAddr) where U : new() {
|
||||
return ReadObject<U>(MapVATR(uiAddr));
|
||||
}
|
||||
|
||||
public U[] ReadMappedArray<U>(uint uiAddr, int count) where U : new() {
|
||||
return ReadArray<U>(MapVATR(uiAddr), count);
|
||||
}
|
||||
}
|
||||
}
|
||||
207
Il2CppInspector/Il2CppClasses.cs
Normal file
207
Il2CppInspector/Il2CppClasses.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public class Il2CppCodeRegistration
|
||||
{
|
||||
public uint methodPointersCount;
|
||||
public uint pmethodPointers;
|
||||
public uint delegateWrappersFromNativeToManagedCount;
|
||||
public uint delegateWrappersFromNativeToManaged; // note the double indirection to handle different calling conventions
|
||||
public uint delegateWrappersFromManagedToNativeCount;
|
||||
public uint delegateWrappersFromManagedToNative;
|
||||
public uint marshalingFunctionsCount;
|
||||
public uint marshalingFunctions;
|
||||
public uint ccwMarshalingFunctionsCount;
|
||||
public uint ccwMarshalingFunctions;
|
||||
public uint genericMethodPointersCount;
|
||||
public uint genericMethodPointers;
|
||||
public uint invokerPointersCount;
|
||||
public uint invokerPointers;
|
||||
public int customAttributeCount;
|
||||
public uint customAttributeGenerators;
|
||||
public int guidCount;
|
||||
public uint guids; // Il2CppGuid
|
||||
|
||||
public uint[] methodPointers
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CS0649
|
||||
public class Il2CppMetadataRegistration
|
||||
{
|
||||
public int genericClassesCount;
|
||||
public uint genericClasses;
|
||||
public int genericInstsCount;
|
||||
public uint genericInsts;
|
||||
public int genericMethodTableCount;
|
||||
public uint genericMethodTable; // Il2CppGenericMethodFunctionsDefinitions
|
||||
public int typesCount;
|
||||
public uint ptypes;
|
||||
public int methodSpecsCount;
|
||||
public uint methodSpecs;
|
||||
|
||||
public int fieldOffsetsCount;
|
||||
public uint pfieldOffsets;
|
||||
|
||||
public int typeDefinitionsSizesCount;
|
||||
public uint typeDefinitionsSizes;
|
||||
public uint metadataUsagesCount;
|
||||
public uint metadataUsages;
|
||||
|
||||
public int[] fieldOffsets
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public Il2CppType[] types
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0649
|
||||
|
||||
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 uint datapoint;
|
||||
public Anonymous 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 Anonymous() { dummy = datapoint };
|
||||
}
|
||||
|
||||
public class Anonymous
|
||||
{
|
||||
public uint dummy;
|
||||
public int klassIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)dummy;
|
||||
}
|
||||
}
|
||||
public uint type
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
public uint array
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
public int genericParameterIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)dummy;
|
||||
}
|
||||
}
|
||||
public uint generic_class
|
||||
{
|
||||
get
|
||||
{
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Il2CppGenericClass
|
||||
{
|
||||
public int typeDefinitionIndex; /* the generic type definition */
|
||||
public Il2CppGenericContext context; /* a context that contains the type instantiation doesn't contain any method instantiation */
|
||||
public uint cached_class; /* if present, the Il2CppClass corresponding to the instantiation. */
|
||||
}
|
||||
|
||||
public class Il2CppGenericContext
|
||||
{
|
||||
/* The instantiation corresponding to the class generic parameters */
|
||||
public uint class_inst;
|
||||
/* The instantiation corresponding to the method generic parameters */
|
||||
public uint method_inst;
|
||||
}
|
||||
|
||||
|
||||
public class Il2CppGenericInst
|
||||
{
|
||||
public uint type_argc;
|
||||
public uint type_argv;
|
||||
}
|
||||
|
||||
public class Il2CppArrayType
|
||||
{
|
||||
public uint etype;
|
||||
public byte rank;
|
||||
public byte numsizes;
|
||||
public byte numlobounds;
|
||||
public uint sizes;
|
||||
public uint lobounds;
|
||||
}
|
||||
}
|
||||
15
Il2CppInspector/Il2CppInspector.csproj
Normal file
15
Il2CppInspector/Il2CppInspector.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.5</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Bin2Object\Bin2Object\Bin2Object.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
137
Il2CppInspector/Il2CppProcessor.cs
Normal file
137
Il2CppInspector/Il2CppProcessor.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public class Il2CppProcessor
|
||||
{
|
||||
public Il2CppReader Code { get; }
|
||||
public Metadata Metadata { get; }
|
||||
|
||||
public Il2CppProcessor(Il2CppReader code, Metadata metadata) {
|
||||
Code = code;
|
||||
Metadata = metadata;
|
||||
}
|
||||
|
||||
public static Il2CppProcessor LoadFromFile(string codeFile, string metadataFile) {
|
||||
// Load the metadata file
|
||||
var metadata = new Metadata(new MemoryStream(File.ReadAllBytes(metadataFile)));
|
||||
|
||||
// Load the il2cpp code file (try ELF and PE)
|
||||
var memoryStream = new MemoryStream(File.ReadAllBytes(codeFile));
|
||||
IFileFormatReader stream = (IFileFormatReader) ElfReader.Load(memoryStream) ?? PEReader.Load(memoryStream);
|
||||
if (stream == null) {
|
||||
Console.Error.WriteLine("Unsupported executable file format");
|
||||
return null;
|
||||
}
|
||||
|
||||
Il2CppReader il2cpp;
|
||||
|
||||
// We are currently supporting x86 and ARM architectures
|
||||
switch (stream.Arch) {
|
||||
case "x86":
|
||||
il2cpp = new Il2CppReaderX86(stream);
|
||||
break;
|
||||
case "ARM":
|
||||
il2cpp = new Il2CppReaderARM(stream);
|
||||
break;
|
||||
default:
|
||||
Console.Error.WriteLine("Unsupported architecture");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find code and metadata regions
|
||||
if (!il2cpp.Load()) {
|
||||
Console.Error.WriteLine("Could not process IL2CPP image");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Il2CppProcessor(il2cpp, metadata);
|
||||
}
|
||||
|
||||
public string GetTypeName(Il2CppType pType) {
|
||||
string ret;
|
||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_CLASS || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) {
|
||||
Il2CppTypeDefinition klass = Metadata.Types[pType.data.klassIndex];
|
||||
ret = Metadata.GetString(klass.nameIndex);
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) {
|
||||
Il2CppGenericClass generic_class = Code.Image.ReadMappedObject<Il2CppGenericClass>(pType.data.generic_class);
|
||||
Il2CppTypeDefinition pMainDef = Metadata.Types[generic_class.typeDefinitionIndex];
|
||||
ret = Metadata.GetString(pMainDef.nameIndex);
|
||||
var typeNames = new List<string>();
|
||||
Il2CppGenericInst pInst = Code.Image.ReadMappedObject<Il2CppGenericInst>(generic_class.context.class_inst);
|
||||
var pointers = Code.Image.ReadMappedArray<uint>(pInst.type_argv, (int)pInst.type_argc);
|
||||
for (int i = 0; i < pInst.type_argc; ++i) {
|
||||
var pOriType = Code.Image.ReadMappedObject<Il2CppType>(pointers[i]);
|
||||
pOriType.Init();
|
||||
typeNames.Add(GetTypeName(pOriType));
|
||||
}
|
||||
ret += $"<{string.Join(", ", typeNames)}>";
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY) {
|
||||
Il2CppArrayType arrayType = Code.Image.ReadMappedObject<Il2CppArrayType>(pType.data.array);
|
||||
var type = Code.Image.ReadMappedObject<Il2CppType>(arrayType.etype);
|
||||
type.Init();
|
||||
ret = $"{GetTypeName(type)}[]";
|
||||
}
|
||||
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY) {
|
||||
var type = Code.Image.ReadMappedObject<Il2CppType>(pType.data.type);
|
||||
type.Init();
|
||||
ret = $"{GetTypeName(type)}[]";
|
||||
}
|
||||
else {
|
||||
if ((int)pType.type >= szTypeString.Length)
|
||||
ret = "unknow";
|
||||
else
|
||||
ret = szTypeString[(int)pType.type];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private readonly string[] szTypeString =
|
||||
{
|
||||
"END",
|
||||
"void",
|
||||
"bool",
|
||||
"char",
|
||||
"sbyte",
|
||||
"byte",
|
||||
"short",
|
||||
"ushort",
|
||||
"int",
|
||||
"uint",
|
||||
"long",
|
||||
"ulong",
|
||||
"float",
|
||||
"double",
|
||||
"string",
|
||||
"PTR",//eg. void*
|
||||
"BYREF",
|
||||
"VALUETYPE",
|
||||
"CLASS",
|
||||
"T",
|
||||
"ARRAY",
|
||||
"GENERICINST",
|
||||
"TYPEDBYREF",
|
||||
"None",
|
||||
"IntPtr",
|
||||
"UIntPtr",
|
||||
"None",
|
||||
"FNPTR",
|
||||
"object",
|
||||
"SZARRAY",
|
||||
"T",
|
||||
"CMOD_REQD",
|
||||
"CMOD_OPT",
|
||||
"INTERNAL",
|
||||
};
|
||||
}
|
||||
}
|
||||
68
Il2CppInspector/Il2CppReader.cs
Normal file
68
Il2CppInspector/Il2CppReader.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public abstract class Il2CppReader
|
||||
{
|
||||
public IFileFormatReader Image { get; }
|
||||
|
||||
protected Il2CppReader(IFileFormatReader stream) {
|
||||
Image = stream;
|
||||
}
|
||||
|
||||
protected Il2CppReader(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) {
|
||||
Image = stream;
|
||||
Configure(codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
public Il2CppCodeRegistration PtrCodeRegistration { get; protected set; }
|
||||
public Il2CppMetadataRegistration PtrMetadataRegistration { get; protected set; }
|
||||
|
||||
// Architecture-specific search function
|
||||
protected abstract (uint, uint) Search(uint loc, uint globalOffset);
|
||||
|
||||
// Check all search locations
|
||||
public bool Load() {
|
||||
var addrs = Image.GetSearchLocations();
|
||||
foreach (var loc in addrs)
|
||||
if (loc != 0) {
|
||||
var (code, metadata) = Search(loc, Image.GlobalOffset);
|
||||
if (code != 0) {
|
||||
Configure(code, metadata);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void Configure(uint codeRegistration, uint metadataRegistration) {
|
||||
PtrCodeRegistration = Image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
|
||||
PtrMetadataRegistration = Image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
|
||||
PtrCodeRegistration.methodPointers = Image.ReadMappedArray<uint>(PtrCodeRegistration.pmethodPointers,
|
||||
(int) PtrCodeRegistration.methodPointersCount);
|
||||
PtrMetadataRegistration.fieldOffsets = Image.ReadMappedArray<int>(PtrMetadataRegistration.pfieldOffsets,
|
||||
PtrMetadataRegistration.fieldOffsetsCount);
|
||||
var types = Image.ReadMappedArray<uint>(PtrMetadataRegistration.ptypes, PtrMetadataRegistration.typesCount);
|
||||
PtrMetadataRegistration.types = new Il2CppType[PtrMetadataRegistration.typesCount];
|
||||
for (int i = 0; i < PtrMetadataRegistration.typesCount; ++i) {
|
||||
PtrMetadataRegistration.types[i] = Image.ReadMappedObject<Il2CppType>(types[i]);
|
||||
PtrMetadataRegistration.types[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public Il2CppType GetTypeFromTypeIndex(int idx) {
|
||||
return PtrMetadataRegistration.types[idx];
|
||||
}
|
||||
|
||||
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType) {
|
||||
var ptr = PtrMetadataRegistration.fieldOffsets[typeIndex];
|
||||
Image.Stream.Position = Image.MapVATR((uint) ptr) + 4 * fieldIndexInType;
|
||||
return Image.Stream.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Il2CppInspector/Il2CppReaderARM.cs
Normal file
64
Il2CppInspector/Il2CppReaderARM.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
internal class Il2CppReaderARM : Il2CppReader
|
||||
{
|
||||
public Il2CppReaderARM(IFileFormatReader stream) : base(stream) { }
|
||||
|
||||
public Il2CppReaderARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { }
|
||||
|
||||
protected override (uint, uint) Search(uint loc, uint globalOffset) {
|
||||
// Assembly bytes to search for at start of each function
|
||||
uint metadataRegistration, codeRegistration;
|
||||
|
||||
// ARM
|
||||
var bytes = new byte[] { 0x1c, 0x0, 0x9f, 0xe5, 0x1c, 0x10, 0x9f, 0xe5, 0x1c, 0x20, 0x9f, 0xe5 };
|
||||
Image.Position = loc;
|
||||
var buff = Image.ReadBytes(12);
|
||||
if (bytes.SequenceEqual(buff)) {
|
||||
Image.Position = loc + 0x2c;
|
||||
var subaddr = Image.ReadUInt32() + globalOffset;
|
||||
Image.Position = subaddr + 0x28;
|
||||
codeRegistration = Image.ReadUInt32() + globalOffset;
|
||||
Image.Position = subaddr + 0x2C;
|
||||
var ptr = Image.ReadUInt32() + globalOffset;
|
||||
Image.Position = Image.MapVATR(ptr);
|
||||
metadataRegistration = Image.ReadUInt32();
|
||||
return (codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
// ARMv7 Thumb (T1)
|
||||
// http://liris.cnrs.fr/~mmrissa/lib/exe/fetch.php?media=armv7-a-r-manual.pdf - A8.8.106
|
||||
// http://armconverter.com/hextoarm/
|
||||
bytes = new byte[] { 0x2d, 0xe9, 0x00, 0x48, 0xeb, 0x46 };
|
||||
Image.Position = loc;
|
||||
buff = Image.ReadBytes(6);
|
||||
if (!bytes.SequenceEqual(buff))
|
||||
return (0, 0);
|
||||
bytes = new byte[] { 0x00, 0x23, 0x00, 0x22, 0xbd, 0xe8, 0x00, 0x48 };
|
||||
Image.Position += 0x10;
|
||||
buff = Image.ReadBytes(8);
|
||||
if (!bytes.SequenceEqual(buff))
|
||||
return (0, 0);
|
||||
Image.Position = loc + 6;
|
||||
Image.Position = (Image.MapVATR(decodeMovImm32(Image.ReadBytes(8))) & 0xfffffffc) + 0x0e;
|
||||
metadataRegistration = decodeMovImm32(Image.ReadBytes(8));
|
||||
codeRegistration = decodeMovImm32(Image.ReadBytes(8));
|
||||
return (codeRegistration, metadataRegistration);
|
||||
}
|
||||
|
||||
private uint decodeMovImm32(byte[] asm) {
|
||||
ushort low = (ushort) (asm[2] + ((asm[3] & 0x70) << 4) + ((asm[1] & 0x04) << 9) + ((asm[0] & 0x0f) << 12));
|
||||
ushort high = (ushort) (asm[6] + ((asm[7] & 0x70) << 4) + ((asm[5] & 0x04) << 9) + ((asm[4] & 0x0f) << 12));
|
||||
return (uint) ((high << 16) + low);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Il2CppInspector/Il2CppReaderX86.cs
Normal file
58
Il2CppInspector/Il2CppReaderX86.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
internal class Il2CppReaderX86 : Il2CppReader
|
||||
{
|
||||
public Il2CppReaderX86(IFileFormatReader stream) : base(stream) { }
|
||||
public Il2CppReaderX86(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { }
|
||||
protected override (uint, uint) Search(uint loc, uint globalOffset) {
|
||||
uint funcPtr, metadata, code;
|
||||
|
||||
// Variant 1
|
||||
|
||||
// Assembly bytes to search for at start of each function
|
||||
var bytes = new byte[] { 0x6A, 0x00, 0x6A, 0x00, 0x68 };
|
||||
Image.Position = loc;
|
||||
var buff = Image.ReadBytes(5);
|
||||
if (bytes.SequenceEqual(buff)) {
|
||||
// Next 4 bytes are the function pointer being pushed onto the stack
|
||||
funcPtr = Image.ReadUInt32();
|
||||
|
||||
// Start of next instruction
|
||||
if (Image.ReadByte() != 0xB9)
|
||||
return (0, 0);
|
||||
|
||||
// Jump to Il2CppCodegenRegistration
|
||||
Image.Position = Image.MapVATR(funcPtr) + 6;
|
||||
metadata = Image.ReadUInt32();
|
||||
Image.Position = Image.MapVATR(funcPtr) + 11;
|
||||
code = Image.ReadUInt32();
|
||||
return (code, metadata);
|
||||
}
|
||||
|
||||
// Variant 2
|
||||
bytes = new byte[] { 0x55, 0x89, 0xE5, 0x53, 0x83, 0xE4, 0xF0, 0x83, 0xEC, 0x20, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B };
|
||||
Image.Position = loc;
|
||||
buff = Image.ReadBytes(16);
|
||||
if (!bytes.SequenceEqual(buff))
|
||||
return (0, 0);
|
||||
|
||||
Image.Position += 8;
|
||||
funcPtr = Image.MapVATR(Image.ReadUInt32() + globalOffset);
|
||||
if (funcPtr > Image.Stream.BaseStream.Length)
|
||||
return (0, 0);
|
||||
Image.Position = funcPtr + 0x22;
|
||||
metadata = Image.ReadUInt32() + globalOffset;
|
||||
Image.Position = funcPtr + 0x2C;
|
||||
code = Image.ReadUInt32() + globalOffset;
|
||||
return (code, metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Il2CppInspector/Metadata.cs
Normal file
99
Il2CppInspector/Metadata.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2017 Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
public class Metadata : BinaryObjectReader
|
||||
{
|
||||
private Il2CppGlobalMetadataHeader pMetadataHdr;
|
||||
|
||||
public Il2CppImageDefinition[] Images { get; }
|
||||
public Il2CppTypeDefinition[] Types { get; }
|
||||
public Il2CppMethodDefinition[] Methods { get; }
|
||||
public Il2CppParameterDefinition[] parameterDefs;
|
||||
public Il2CppFieldDefinition[] Fields { get; }
|
||||
public Il2CppFieldDefaultValue[] fieldDefaultValues;
|
||||
|
||||
public string GetImageName(Il2CppImageDefinition image) => GetString(image.nameIndex);
|
||||
public string GetTypeNamespace(Il2CppTypeDefinition type) => GetString(type.namespaceIndex);
|
||||
public string GetTypeName(Il2CppTypeDefinition type) => GetString(type.nameIndex);
|
||||
|
||||
|
||||
|
||||
public Metadata(Stream stream) : base(stream)
|
||||
{
|
||||
pMetadataHdr = ReadObject<Il2CppGlobalMetadataHeader>();
|
||||
if (pMetadataHdr.sanity != 0xFAB11BAF)
|
||||
{
|
||||
throw new Exception("ERROR: Metadata file supplied is not valid metadata file.");
|
||||
}
|
||||
if (pMetadataHdr.version != 21 && pMetadataHdr.version != 22)
|
||||
{
|
||||
throw new Exception($"ERROR: Metadata file supplied is not a supported version[{pMetadataHdr.version}].");
|
||||
}
|
||||
var uiImageCount = pMetadataHdr.imagesCount / MySizeOf(typeof(Il2CppImageDefinition));
|
||||
var uiNumTypes = pMetadataHdr.typeDefinitionsCount / MySizeOf(typeof(Il2CppTypeDefinition));
|
||||
Images = ReadArray<Il2CppImageDefinition>(pMetadataHdr.imagesOffset, uiImageCount);
|
||||
//GetTypeDefFromIndex
|
||||
Types = ReadArray<Il2CppTypeDefinition>(pMetadataHdr.typeDefinitionsOffset, uiNumTypes);
|
||||
//GetMethodDefinition
|
||||
Methods = ReadArray<Il2CppMethodDefinition>(pMetadataHdr.methodsOffset, pMetadataHdr.methodsCount / MySizeOf(typeof(Il2CppMethodDefinition)));
|
||||
//GetParameterFromIndex
|
||||
parameterDefs = ReadArray<Il2CppParameterDefinition>(pMetadataHdr.parametersOffset, pMetadataHdr.parametersCount / MySizeOf(typeof(Il2CppParameterDefinition)));
|
||||
//GetFieldDefFromIndex
|
||||
Fields = ReadArray<Il2CppFieldDefinition>(pMetadataHdr.fieldsOffset, pMetadataHdr.fieldsCount / MySizeOf(typeof(Il2CppFieldDefinition)));
|
||||
//GetFieldDefaultFromIndex
|
||||
fieldDefaultValues = ReadArray<Il2CppFieldDefaultValue>(pMetadataHdr.fieldDefaultValuesOffset, pMetadataHdr.fieldDefaultValuesCount / MySizeOf(typeof(Il2CppFieldDefaultValue)));
|
||||
}
|
||||
|
||||
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 ReadNullTerminatedString(pMetadataHdr.stringOffset + idx);
|
||||
}
|
||||
|
||||
private int MySizeOf(Type type)
|
||||
{
|
||||
int size = 0;
|
||||
foreach (var i in type.GetTypeInfo().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
182
Il2CppInspector/MetadataClass.cs
Normal file
182
Il2CppInspector/MetadataClass.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public class Il2CppGlobalMetadataHeader
|
||||
{
|
||||
public uint sanity;
|
||||
public int version;
|
||||
public int stringLiteralOffset; // string data for managed code
|
||||
public int stringLiteralCount;
|
||||
public int stringLiteralDataOffset;
|
||||
public int stringLiteralDataCount;
|
||||
public int stringOffset; // string data for metadata
|
||||
public int stringCount;
|
||||
public int eventsOffset; // Il2CppEventDefinition
|
||||
public int eventsCount;
|
||||
public int propertiesOffset; // Il2CppPropertyDefinition
|
||||
public int propertiesCount;
|
||||
public int methodsOffset; // Il2CppMethodDefinition
|
||||
public int methodsCount;
|
||||
public int parameterDefaultValuesOffset; // Il2CppParameterDefaultValue
|
||||
public int parameterDefaultValuesCount;
|
||||
public int fieldDefaultValuesOffset; // Il2CppFieldDefaultValue
|
||||
public int fieldDefaultValuesCount;
|
||||
public int fieldAndParameterDefaultValueDataOffset; // uint8_t
|
||||
public int fieldAndParameterDefaultValueDataCount;
|
||||
public int fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize
|
||||
public int fieldMarshaledSizesCount;
|
||||
public int parametersOffset; // Il2CppParameterDefinition
|
||||
public int parametersCount;
|
||||
public int fieldsOffset; // Il2CppFieldDefinition
|
||||
public int fieldsCount;
|
||||
public int genericParametersOffset; // Il2CppGenericParameter
|
||||
public int genericParametersCount;
|
||||
public int genericParameterConstraintsOffset; // TypeIndex
|
||||
public int genericParameterConstraintsCount;
|
||||
public int genericContainersOffset; // Il2CppGenericContainer
|
||||
public int genericContainersCount;
|
||||
public int nestedTypesOffset; // TypeDefinitionIndex
|
||||
public int nestedTypesCount;
|
||||
public int interfacesOffset; // TypeIndex
|
||||
public int interfacesCount;
|
||||
public int vtableMethodsOffset; // EncodedMethodIndex
|
||||
public int vtableMethodsCount;
|
||||
public int interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair
|
||||
public int interfaceOffsetsCount;
|
||||
public int typeDefinitionsOffset; // Il2CppTypeDefinition
|
||||
public int typeDefinitionsCount;
|
||||
public int rgctxEntriesOffset; // Il2CppRGCTXDefinition
|
||||
public int rgctxEntriesCount;
|
||||
public int imagesOffset; // Il2CppImageDefinition
|
||||
public int imagesCount;
|
||||
public int assembliesOffset; // Il2CppAssemblyDefinition
|
||||
public int assembliesCount;
|
||||
public int metadataUsageListsOffset; // Il2CppMetadataUsageList
|
||||
public int metadataUsageListsCount;
|
||||
public int metadataUsagePairsOffset; // Il2CppMetadataUsagePair
|
||||
public int metadataUsagePairsCount;
|
||||
public int fieldRefsOffset; // Il2CppFieldRef
|
||||
public int fieldRefsCount;
|
||||
public int referencedAssembliesOffset; // int
|
||||
public int referencedAssembliesCount;
|
||||
public int attributesInfoOffset; // Il2CppCustomAttributeTypeRange
|
||||
public int attributesInfoCount;
|
||||
public int attributeTypesOffset; // TypeIndex
|
||||
public int attributeTypesCount;
|
||||
}
|
||||
|
||||
public class Il2CppImageDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int assemblyIndex;
|
||||
|
||||
public int typeStart;
|
||||
public uint typeCount;
|
||||
|
||||
public int entryPointIndex;
|
||||
public uint token;
|
||||
}
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public class Il2CppTypeDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int namespaceIndex;
|
||||
public int customAttributeIndex;
|
||||
public int byvalTypeIndex;
|
||||
public int byrefTypeIndex;
|
||||
|
||||
public int declaringTypeIndex;
|
||||
public int parentIndex;
|
||||
public int elementTypeIndex; // we can probably remove this one. Only used for enums
|
||||
|
||||
public int rgctxStartIndex;
|
||||
public int rgctxCount;
|
||||
|
||||
public int genericContainerIndex;
|
||||
|
||||
public int delegateWrapperFromManagedToNativeIndex;
|
||||
public int marshalingFunctionsIndex;
|
||||
public int ccwFunctionIndex;
|
||||
public int guidIndex;
|
||||
|
||||
public uint flags;
|
||||
|
||||
public int fieldStart;
|
||||
public int methodStart;
|
||||
public int eventStart;
|
||||
public int propertyStart;
|
||||
public int nestedTypesStart;
|
||||
public int interfacesStart;
|
||||
public int vtableStart;
|
||||
public int interfaceOffsetsStart;
|
||||
|
||||
public ushort method_count;
|
||||
public ushort property_count;
|
||||
public ushort field_count;
|
||||
public ushort event_count;
|
||||
public ushort nested_type_count;
|
||||
public ushort vtable_count;
|
||||
public ushort interfaces_count;
|
||||
public ushort interface_offsets_count;
|
||||
|
||||
// bitfield to portably encode boolean values as single bits
|
||||
// 01 - valuetype;
|
||||
// 02 - enumtype;
|
||||
// 03 - has_finalize;
|
||||
// 04 - has_cctor;
|
||||
// 05 - is_blittable;
|
||||
// 06 - is_import;
|
||||
// 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128)
|
||||
public uint bitfield;
|
||||
public uint token;
|
||||
}
|
||||
|
||||
public class Il2CppMethodDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int declaringType;
|
||||
public int returnType;
|
||||
public int parameterStart;
|
||||
public int customAttributeIndex;
|
||||
public int genericContainerIndex;
|
||||
public int methodIndex;
|
||||
public int invokerIndex;
|
||||
public int delegateWrapperIndex;
|
||||
public int rgctxStartIndex;
|
||||
public int rgctxCount;
|
||||
public uint token;
|
||||
public ushort flags;
|
||||
public ushort iflags;
|
||||
public ushort slot;
|
||||
public ushort parameterCount;
|
||||
}
|
||||
|
||||
public class Il2CppParameterDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public uint token;
|
||||
public int customAttributeIndex;
|
||||
public int typeIndex;
|
||||
}
|
||||
|
||||
public class Il2CppFieldDefinition
|
||||
{
|
||||
public int nameIndex;
|
||||
public int typeIndex;
|
||||
public int customAttributeIndex;
|
||||
public uint token;
|
||||
}
|
||||
|
||||
public class Il2CppFieldDefaultValue
|
||||
{
|
||||
public int fieldIndex;
|
||||
public int typeIndex;
|
||||
public int dataIndex;
|
||||
}
|
||||
}
|
||||
78
Il2CppInspector/PEHeaders.cs
Normal file
78
Il2CppInspector/PEHeaders.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
internal class COFFHeader
|
||||
{
|
||||
public ushort Machine;
|
||||
public ushort NumberOfSections;
|
||||
public uint TimeDateStamp;
|
||||
public uint PointerToSymbolTable;
|
||||
public uint NumberOfSymbols;
|
||||
public ushort SizeOfOptionalHeader;
|
||||
public ushort Characteristics;
|
||||
}
|
||||
|
||||
internal class PEOptHeader
|
||||
{
|
||||
public ushort signature;
|
||||
public byte MajorLinkerVersion;
|
||||
public byte MinorLinkerVersion;
|
||||
public uint SizeOfCode;
|
||||
public uint SizeOfInitializedData;
|
||||
public uint SizeOfUninitializedData;
|
||||
public uint AddressOfEntryPoint;
|
||||
public uint BaseOfCode;
|
||||
public uint BaseOfData;
|
||||
public uint ImageBase;
|
||||
public uint SectionAlignment;
|
||||
public uint FileAlignment;
|
||||
public ushort MajorOSVersion;
|
||||
public ushort MinorOSVersion;
|
||||
public ushort MajorImageVersion;
|
||||
public ushort MinorImageVersion;
|
||||
public ushort MajorSubsystemVersion;
|
||||
public ushort MinorSubsystemVersion;
|
||||
public uint Win32VersionValue;
|
||||
public uint SizeOfImage;
|
||||
public uint SizeOfHeaders;
|
||||
public uint Checksum;
|
||||
public ushort Subsystem;
|
||||
public ushort DLLCharacteristics;
|
||||
public uint SizeOfStackReserve;
|
||||
public uint SizeOfStackCommit;
|
||||
public uint SizeOfHeapReserve;
|
||||
public uint SizeOfHeapCommit;
|
||||
public uint LoaderFlags;
|
||||
public uint NumberOfRvaAndSizes;
|
||||
[ArrayLength(FieldName = "NumberOfRvaAndSizes")]
|
||||
public RvaEntry[] DataDirectory;
|
||||
}
|
||||
|
||||
internal class RvaEntry
|
||||
{
|
||||
public uint VirtualAddress;
|
||||
public uint Size;
|
||||
}
|
||||
|
||||
internal class PESection
|
||||
{
|
||||
[String(FixedSize=8)]
|
||||
public string Name;
|
||||
public uint SizeMemory;
|
||||
public uint BaseMemory; // RVA
|
||||
public uint SizeImage; // Size in file
|
||||
public uint BaseImage; // Base address in file
|
||||
[ArrayLength(FixedSize=12)]
|
||||
public byte[] Reserved;
|
||||
public uint Flags;
|
||||
}
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
101
Il2CppInspector/PEReader.cs
Normal file
101
Il2CppInspector/PEReader.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright 2017 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
internal class PEReader : FileFormatReader<PEReader>
|
||||
{
|
||||
private COFFHeader coff;
|
||||
private PEOptHeader pe;
|
||||
private PESection[] sections;
|
||||
private uint pFuncTable;
|
||||
|
||||
public PEReader(Stream stream) : base(stream) {}
|
||||
|
||||
public override string Arch {
|
||||
get {
|
||||
switch (coff.Machine) {
|
||||
case 0x14C:
|
||||
return "x86";
|
||||
case 0x1C0: // ARMv7
|
||||
case 0x1C4: // ARMv7 Thumb (T1)
|
||||
return "ARM";
|
||||
default:
|
||||
return "Unsupported";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool Init() {
|
||||
// Check for MZ signature "MZ"
|
||||
if (ReadUInt16() != 0x5A4D)
|
||||
return false;
|
||||
|
||||
// Get offset to PE header from DOS header
|
||||
Position = 0x3C;
|
||||
Position = ReadUInt32();
|
||||
|
||||
// Check PE signature "PE\0\0"
|
||||
if (ReadUInt32() != 0x00004550)
|
||||
return false;
|
||||
|
||||
// Read COFF Header
|
||||
coff = ReadObject<COFFHeader>();
|
||||
|
||||
// Ensure presence of PE Optional header
|
||||
// Size will always be 0x60 + (0x10 ' 0x8) for 16 RVA entries @ 8 bytes each
|
||||
if (coff.SizeOfOptionalHeader != 0xE0)
|
||||
return false;
|
||||
|
||||
// Read PE optional header
|
||||
pe = ReadObject<PEOptHeader>();
|
||||
|
||||
// Ensure IMAGE_NT_OPTIONAL_HDR32_MAGIC (32-bit)
|
||||
if (pe.signature != 0x10B)
|
||||
return false;
|
||||
|
||||
// Get IAT
|
||||
var IATStart = pe.DataDirectory[12].VirtualAddress;
|
||||
var IATSize = pe.DataDirectory[12].Size;
|
||||
|
||||
// Get sections table
|
||||
sections = ReadArray<PESection>(coff.NumberOfSections);
|
||||
|
||||
// Confirm that .rdata section begins at same place as IAT
|
||||
var rData = sections.First(x => x.Name == ".rdata");
|
||||
if (rData.BaseMemory != IATStart)
|
||||
return false;
|
||||
|
||||
// Calculate start of function pointer table
|
||||
pFuncTable = rData.BaseImage + IATSize + 8;
|
||||
GlobalOffset = pe.ImageBase;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override uint[] GetSearchLocations() {
|
||||
Position = pFuncTable;
|
||||
var addrs = new List<uint>();
|
||||
uint addr;
|
||||
while ((addr = ReadUInt32()) != 0)
|
||||
addrs.Add(MapVATR(addr) & 0xfffffffc);
|
||||
return addrs.ToArray();
|
||||
}
|
||||
|
||||
public override uint MapVATR(uint uiAddr) {
|
||||
if (uiAddr == 0)
|
||||
return 0;
|
||||
|
||||
var section = sections.First(x => uiAddr - GlobalOffset >= x.BaseMemory &&
|
||||
uiAddr - GlobalOffset < x.BaseMemory + x.SizeMemory);
|
||||
return uiAddr - section.BaseMemory - GlobalOffset + section.BaseImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
README.md
45
README.md
@@ -1,2 +1,45 @@
|
||||
# Il2CppInspector
|
||||
Extract types, methods, properties and fields from Unity IL2CPP binaries
|
||||
Extract types, methods, properties and fields from Unity IL2CPP binaries.
|
||||
|
||||
* Supports ELF (Android .so) and PE (Windows .exe) file formats
|
||||
* Supports ARM, ARMv7 Thumb (T1) and x86 architectures regardless of file format
|
||||
* Supports metadata versions 21 and 22
|
||||
* No manual reverse-engineering required; all data is calculated automatically
|
||||
* **Il2CppInspector** re-usable class library
|
||||
|
||||
Targets .NET Standard 1.5 / .NET Core 1.1. Built with Visual Studio 2017.
|
||||
|
||||
### Usage
|
||||
|
||||
```
|
||||
dotnet run [<binary-file> [<metadata-file> [<output-file>]]]
|
||||
```
|
||||
|
||||
Defaults if not specified:
|
||||
|
||||
- _binary-file_ - searches for `libil2cpp.so` and `GameAssembly.dll`
|
||||
- _metadata-file_ - `global-metadata.dat`
|
||||
- _output-file_ - `types.cs`
|
||||
|
||||
File format and architecture are automatically detected.
|
||||
|
||||
### Help with iOS support
|
||||
|
||||
Mach-O (iOS) file format is not currently supported. Please contact me via the contact form at http://www.djkaty.com if you have a rooted iOS device and can produce cracked IPA files.
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
Thanks to the following individuals whose code and research helped me develop this tool:
|
||||
|
||||
- Perfare - https://github.com/Perfare/Il2CppDumper
|
||||
- Jumboperson - https://github.com/Jumboperson/Il2CppDumper
|
||||
- nevermoe - https://github.com/nevermoe/unity_metadata_loader
|
||||
- branw - https://github.com/branw/pogo-proto-dumper
|
||||
- fry - https://github.com/fry/d3
|
||||
- ARMConvertor - http://armconverter.com
|
||||
|
||||
This tool uses Perfare's Il2CppDumper code as a base.
|
||||
|
||||
### License
|
||||
|
||||
All rights reserved. Unauthorized use, re-use or the creation of derivative works of this code for commercial purposes whether directly or indirectly is strictly prohibited. Use, re-use or the creation of derivative works for non-commercial purposes is expressly permitted.
|
||||
|
||||
Reference in New Issue
Block a user