Additional refactoring

This commit is contained in:
Katy Coe
2017-10-23 16:12:40 +02:00
parent 474faa009c
commit 0ab1b75ef4
12 changed files with 117 additions and 190 deletions

View File

@@ -8,9 +8,9 @@ namespace Il2CppInspector
{
public class Il2CppDumper
{
private readonly Il2CppProcessor il2cpp;
private readonly Il2CppInspector il2cpp;
public Il2CppDumper(Il2CppProcessor proc) {
public Il2CppDumper(Il2CppInspector proc) {
il2cpp = proc;
}
@@ -100,7 +100,7 @@ namespace Il2CppInspector
}
if (methodDef.methodIndex >= 0)
writer.Write("); // {0:x} - {1}\n",
il2cpp.Code.PtrCodeRegistration.methodPointers[methodDef.methodIndex],
il2cpp.Binary.MethodPointers[methodDef.methodIndex],
methodDef.methodIndex);
else
writer.Write("); // 0 - -1\n");

View File

@@ -40,13 +40,13 @@ namespace Il2CppInspector
}
// Analyze data
var il2cppProcessors = Il2CppProcessor.LoadFromFile(imageFile, metaFile);
if (il2cppProcessors == null)
var il2cppInspectors = Il2CppInspector.LoadFromFile(imageFile, metaFile);
if (il2cppInspectors == null)
Environment.Exit(1);
// Write output file
int i = 0;
foreach (var il2cpp in il2cppProcessors)
foreach (var il2cpp in il2cppInspectors)
new Il2CppDumper(il2cpp).WriteFile(outFile + (i++ > 0 ? "-" + (i-1) : ""));
}
}

View File

@@ -21,11 +21,11 @@ namespace Il2CppInspector
long Position { get; set; }
string Arch { get; }
uint GlobalOffset { get; }
uint[] GetSearchLocations();
uint[] GetFunctionTable();
U ReadMappedObject<U>(uint uiAddr) where U : new();
U[] ReadMappedArray<U>(uint uiAddr, int count) where U : new();
uint MapVATR(uint uiAddr);
void FinalizeInit(Il2CppReader il2cpp);
void FinalizeInit(Il2CppBinary il2cpp);
byte[] ReadBytes(int count);
ulong ReadUInt64();
@@ -77,7 +77,7 @@ namespace Il2CppInspector
}
// Find search locations in the machine code for Il2Cpp data
public virtual uint[] GetSearchLocations() => throw new NotImplementedException();
public virtual uint[] GetFunctionTable() => throw new NotImplementedException();
// Map an RVA to an offset into the file image
// No mapping by default
@@ -93,6 +93,6 @@ namespace Il2CppInspector
}
// Perform file format-based post-load manipulations to the IL2Cpp data
public virtual void FinalizeInit(Il2CppReader il2cpp) { }
public virtual void FinalizeInit(Il2CppBinary il2cpp) { }
}
}

View File

@@ -47,7 +47,7 @@ namespace Il2CppInspector
return true;
}
public override uint[] GetSearchLocations() {
public override uint[] GetFunctionTable() {
// Find dynamic section
var dynamic = new elf_32_shdr();
var PT_DYNAMIC = program_table_element.First(x => x.p_type == 2u);

View File

@@ -113,7 +113,7 @@ namespace Il2CppInspector
return true;
}
public override uint[] GetSearchLocations() {
public override uint[] GetFunctionTable() {
Position = pFuncTable;
var functionPointers = new List<uint>();
@@ -139,10 +139,9 @@ namespace Il2CppInspector
return functionPointers.ToArray();
}
public override void FinalizeInit(Il2CppReader il2cpp) {
public override void FinalizeInit(Il2CppBinary il2cpp) {
// Mach-O function pointers have an annoying habit of being 1-off
il2cpp.PtrCodeRegistration.methodPointers =
il2cpp.PtrCodeRegistration.methodPointers.Select(x => x - 1).ToArray();
il2cpp.MethodPointers = il2cpp.MethodPointers.Select(x => x - 1).ToArray();
}
public override uint MapVATR(uint uiAddr) {

View File

@@ -80,7 +80,7 @@ namespace Il2CppInspector
return true;
}
public override uint[] GetSearchLocations() {
public override uint[] GetFunctionTable() {
Position = pFuncTable;
var addrs = new List<uint>();
uint addr;

View File

@@ -0,0 +1,62 @@
/*
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.Collections.Generic;
namespace Il2CppInspector
{
public abstract class Il2CppBinary
{
public IFileFormatReader Image { get; }
public Il2CppCodeRegistration CodeRegistration { get; protected set; }
public Il2CppMetadataRegistration MetadataRegistration { get; protected set; }
public uint[] MethodPointers { get; set; }
public int[] FieldOffsets { get; private set; }
public List<Il2CppType> Types { get; } = new List<Il2CppType>();
protected Il2CppBinary(IFileFormatReader stream) {
Image = stream;
}
protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) {
Image = stream;
Configure(Image, codeRegistration, metadataRegistration);
}
// Architecture-specific search function
protected abstract (uint, uint) ConsiderCode(uint loc, uint globalOffset);
// Check all search locations
public bool Initialize(int version, uint imageIndex = 0) {
var subImage = Image[imageIndex];
Image.Stream.Version = version;
var addrs = subImage.GetFunctionTable();
foreach (var loc in addrs)
if (loc != 0) {
var (code, metadata) = ConsiderCode(loc, Image.GlobalOffset);
if (code != 0) {
Configure(subImage, code, metadata);
subImage.FinalizeInit(this);
return true;
}
}
return false;
}
private void Configure(IFileFormatReader image, uint codeRegistration, uint metadataRegistration) {
CodeRegistration = image.ReadMappedObject<Il2CppCodeRegistration>(codeRegistration);
MetadataRegistration = image.ReadMappedObject<Il2CppMetadataRegistration>(metadataRegistration);
MethodPointers = image.ReadMappedArray<uint>(CodeRegistration.pmethodPointers, (int) CodeRegistration.methodPointersCount);
FieldOffsets = image.ReadMappedArray<int>(MetadataRegistration.pfieldOffsets, MetadataRegistration.fieldOffsetsCount);
var types = image.ReadMappedArray<uint>(MetadataRegistration.ptypes, MetadataRegistration.typesCount);
for (int i = 0; i < MetadataRegistration.typesCount; i++)
Types.Add(image.ReadMappedObject<Il2CppType>(types[i]));
}
}
}

View File

@@ -9,13 +9,13 @@ using System.Linq;
namespace Il2CppInspector
{
internal class Il2CppReaderARM : Il2CppReader
internal class Il2CppBinaryARM : Il2CppBinary
{
public Il2CppReaderARM(IFileFormatReader stream) : base(stream) { }
public Il2CppBinaryARM(IFileFormatReader stream) : base(stream) { }
public Il2CppReaderARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { }
public Il2CppBinaryARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { }
protected override (uint, uint) Search(uint loc, uint globalOffset) {
protected override (uint, uint) ConsiderCode(uint loc, uint globalOffset) {
// Assembly bytes to search for at start of each function
uint metadataRegistration, codeRegistration;

View File

@@ -49,12 +49,6 @@ namespace Il2CppInspector
public uint interopDataCount;
[Version(Min = 23)]
public uint interopData;
// Properties
public uint[] methodPointers
{
get; set;
}
}
#pragma warning disable CS0649
@@ -78,16 +72,6 @@ namespace Il2CppInspector
public uint typeDefinitionsSizes;
public uint metadataUsagesCount;
public uint metadataUsages;
public int[] fieldOffsets
{
get; set;
}
public Il2CppType[] types
{
get; set;
}
}
#pragma warning restore CS0649
@@ -136,68 +120,13 @@ namespace Il2CppInspector
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 uint attrs => bits & 0xffff;
public Il2CppTypeEnum type => (Il2CppTypeEnum)((bits >> 16) & 0xff);
public uint num_mods => (bits >> 24) & 0x3f;
public bool byref => ((bits >> 30) & 1) == 1;
public bool pinned => (bits >> 31) == 1;
}
public class Il2CppGenericClass

View File

@@ -8,11 +8,11 @@ using System.Linq;
namespace Il2CppInspector
{
internal class Il2CppReaderX86 : Il2CppReader
internal class Il2CppBinaryX86 : Il2CppBinary
{
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) {
public Il2CppBinaryX86(IFileFormatReader stream) : base(stream) { }
public Il2CppBinaryX86(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { }
protected override (uint, uint) ConsiderCode(uint loc, uint globalOffset) {
uint funcPtr, metadata, code;
ushort opcode;

View File

@@ -12,17 +12,17 @@ using System.Text;
namespace Il2CppInspector
{
public class Il2CppProcessor
public class Il2CppInspector
{
public Il2CppReader Code { get; }
public Il2CppBinary Binary { get; }
public Metadata Metadata { get; }
public Il2CppProcessor(Il2CppReader code, Metadata metadata) {
Code = code;
public Il2CppInspector(Il2CppBinary binary, Metadata metadata) {
Binary = binary;
Metadata = metadata;
}
public static List<Il2CppProcessor> LoadFromFile(string codeFile, string metadataFile) {
public static List<Il2CppInspector> LoadFromFile(string codeFile, string metadataFile) {
// Load the metadata file
Metadata metadata;
try {
@@ -33,7 +33,7 @@ namespace Il2CppInspector
return null;
}
// Load the il2cpp code file (try ELF and PE)
// Load the il2cpp code file (try ELF, PE, Mach-O and Universal Binary)
var memoryStream = new MemoryStream(File.ReadAllBytes(codeFile));
IFileFormatReader stream =
(((IFileFormatReader) ElfReader.Load(memoryStream) ??
@@ -45,17 +45,18 @@ namespace Il2CppInspector
return null;
}
var processors = new List<Il2CppProcessor>();
// Multi-image binaries may contain more than one Il2Cpp image
var processors = new List<Il2CppInspector>();
foreach (var image in stream.Images) {
Il2CppReader il2cpp;
Il2CppBinary binary;
// We are currently supporting x86 and ARM architectures
switch (image.Arch) {
case "x86":
il2cpp = new Il2CppReaderX86(image);
binary = new Il2CppBinaryX86(image);
break;
case "ARM":
il2cpp = new Il2CppReaderARM(image);
binary = new Il2CppBinaryARM(image);
break;
default:
Console.Error.WriteLine("Unsupported architecture");
@@ -63,11 +64,11 @@ namespace Il2CppInspector
}
// Find code and metadata regions
if (!il2cpp.Load(metadata.Version)) {
if (!binary.Initialize(metadata.Version)) {
Console.Error.WriteLine("Could not process IL2CPP image");
}
else {
processors.Add(new Il2CppProcessor(il2cpp, metadata));
processors.Add(new Il2CppInspector(binary, metadata));
}
}
return processors;
@@ -76,32 +77,29 @@ namespace Il2CppInspector
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];
Il2CppTypeDefinition klass = Metadata.Types[pType.datapoint];
ret = Metadata.Strings[klass.nameIndex];
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) {
Il2CppGenericClass generic_class = Code.Image.ReadMappedObject<Il2CppGenericClass>(pType.data.generic_class);
Il2CppGenericClass generic_class = Binary.Image.ReadMappedObject<Il2CppGenericClass>(pType.datapoint);
Il2CppTypeDefinition pMainDef = Metadata.Types[generic_class.typeDefinitionIndex];
ret = Metadata.Strings[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);
Il2CppGenericInst pInst = Binary.Image.ReadMappedObject<Il2CppGenericInst>(generic_class.context.class_inst);
var pointers = Binary.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();
var pOriType = Binary.Image.ReadMappedObject<Il2CppType>(pointers[i]);
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();
Il2CppArrayType arrayType = Binary.Image.ReadMappedObject<Il2CppArrayType>(pType.datapoint);
var type = Binary.Image.ReadMappedObject<Il2CppType>(arrayType.etype);
ret = $"{GetTypeName(type)}[]";
}
else if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY) {
var type = Code.Image.ReadMappedObject<Il2CppType>(pType.data.type);
type.Init();
var type = Binary.Image.ReadMappedObject<Il2CppType>(pType.datapoint);
ret = $"{GetTypeName(type)}[]";
}
else {
@@ -114,7 +112,7 @@ namespace Il2CppInspector
}
public Il2CppType GetTypeFromTypeIndex(int idx) {
return Code.PtrMetadataRegistration.types[idx];
return Binary.Types[idx];
}
public int GetFieldOffsetFromIndex(int typeIndex, int fieldIndexInType) {
@@ -123,19 +121,19 @@ namespace Il2CppInspector
// Some variants of 21 also use an array of pointers
if (Metadata.Version == 21) {
var f = Code.PtrMetadataRegistration.fieldOffsets;
var f = Binary.FieldOffsets;
fieldOffsetsArePointers = (f[0] == 0 && f[1] == 0 && f[2] == 0 && f[3] == 0 && f[4] == 0 && f[5] > 0);
}
// All older versions use values directly in the array
if (!fieldOffsetsArePointers) {
var typeDef = Metadata.Types[typeIndex];
return Code.PtrMetadataRegistration.fieldOffsets[typeDef.fieldStart + fieldIndexInType];
return Binary.FieldOffsets[typeDef.fieldStart + fieldIndexInType];
}
var ptr = Code.PtrMetadataRegistration.fieldOffsets[typeIndex];
Code.Image.Stream.Position = Code.Image.MapVATR((uint)ptr) + 4 * fieldIndexInType;
return Code.Image.Stream.ReadInt32();
var ptr = Binary.FieldOffsets[typeIndex];
Binary.Image.Stream.Position = Binary.Image.MapVATR((uint)ptr) + 4 * fieldIndexInType;
return Binary.Image.Stream.ReadInt32();
}

View File

@@ -1,61 +0,0 @@
/*
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(Image, 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(int version, uint imageIndex = 0) {
var subImage = Image[imageIndex];
Image.Stream.Version = version;
var addrs = subImage.GetSearchLocations();
foreach (var loc in addrs)
if (loc != 0) {
var (code, metadata) = Search(loc, Image.GlobalOffset);
if (code != 0) {
Configure(subImage, code, metadata);
subImage.FinalizeInit(this);
return true;
}
}
return false;
}
private void Configure(IFileFormatReader image, 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();
}
}
}
}