IL2CPP: Change metadata and binary to derive from BinaryObjectStream
This commit is contained in:
@@ -13,9 +13,9 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class Il2CppBinaryARM : Il2CppBinary
|
internal class Il2CppBinaryARM : Il2CppBinary
|
||||||
{
|
{
|
||||||
public Il2CppBinaryARM(IFileFormatReader stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
public Il2CppBinaryARM(IFileFormatStream stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
||||||
|
|
||||||
public Il2CppBinaryARM(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
public Il2CppBinaryARM(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
||||||
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
||||||
|
|
||||||
// ARMv7-A Architecture Reference Manual: https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf
|
// ARMv7-A Architecture Reference Manual: https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf
|
||||||
@@ -67,7 +67,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Section 3.1
|
// Section 3.1
|
||||||
private uint getNextThumbInstruction(IFileFormatReader image) {
|
private uint getNextThumbInstruction(IFileFormatStream image) {
|
||||||
// Assume 16-bit
|
// Assume 16-bit
|
||||||
uint inst = image.ReadUInt16();
|
uint inst = image.ReadUInt16();
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ namespace Il2CppInspector
|
|||||||
private bool isBW(uint inst) => inst.Bits(27, 5) == 0b11110 && inst.Bits(14, 2) == 0b10 && inst.Bits(12, 1) == 1;
|
private bool isBW(uint inst) => inst.Bits(27, 5) == 0b11110 && inst.Bits(14, 2) == 0b10 && inst.Bits(12, 1) == 1;
|
||||||
|
|
||||||
// Sweep a Thumb function and return the register values at the end (register number => value)
|
// Sweep a Thumb function and return the register values at the end (register number => value)
|
||||||
private Dictionary<uint, uint> sweepThumbForAddressLoads(List<uint> func, uint baseAddress, IFileFormatReader image) {
|
private Dictionary<uint, uint> sweepThumbForAddressLoads(List<uint> func, uint baseAddress, IFileFormatStream image) {
|
||||||
// List of registers and addresses loaded into them
|
// List of registers and addresses loaded into them
|
||||||
var regs = new Dictionary<uint, uint>();
|
var regs = new Dictionary<uint, uint>();
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get a Thumb function that ends in B.W
|
// Get a Thumb function that ends in B.W
|
||||||
private List<uint> getThumbFunctionAtFileOffset(IFileFormatReader image, uint loc, uint maxLength) {
|
private List<uint> getThumbFunctionAtFileOffset(IFileFormatStream image, uint loc, uint maxLength) {
|
||||||
// Read a function that ends in a hard branch (B.W) or exceeds maxLength instructions
|
// Read a function that ends in a hard branch (B.W) or exceeds maxLength instructions
|
||||||
var func = new List<uint>();
|
var func = new List<uint>();
|
||||||
uint inst;
|
uint inst;
|
||||||
@@ -215,7 +215,7 @@ namespace Il2CppInspector
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) {
|
protected override (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc) {
|
||||||
// Assembly bytes to search for at start of each function
|
// Assembly bytes to search for at start of each function
|
||||||
ulong metadataRegistration, codeRegistration;
|
ulong metadataRegistration, codeRegistration;
|
||||||
|
|
||||||
@@ -264,7 +264,7 @@ namespace Il2CppInspector
|
|||||||
// - B
|
// - B
|
||||||
// R0 = CodeRegistration, R1 = MetadataRegistration, R2 = Il2CppCodeGenOptions
|
// R0 = CodeRegistration, R1 = MetadataRegistration, R2 = Il2CppCodeGenOptions
|
||||||
|
|
||||||
var insts = image.Stream.ReadArray<uint>(pCgr, 10); // 7 instructions + 3 pointers
|
var insts = image.ReadArray<uint>(pCgr, 10); // 7 instructions + 3 pointers
|
||||||
var ldrOffsets = new uint[3];
|
var ldrOffsets = new uint[3];
|
||||||
var pointers = new uint[3];
|
var pointers = new uint[3];
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ namespace Il2CppInspector
|
|||||||
// A64 ISA reference: https://static.docs.arm.com/ddi0596/a/DDI_0596_ARM_a64_instruction_set_architecture.pdf
|
// A64 ISA reference: https://static.docs.arm.com/ddi0596/a/DDI_0596_ARM_a64_instruction_set_architecture.pdf
|
||||||
internal class Il2CppBinaryARM64 : Il2CppBinary
|
internal class Il2CppBinaryARM64 : Il2CppBinary
|
||||||
{
|
{
|
||||||
public Il2CppBinaryARM64(IFileFormatReader stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
public Il2CppBinaryARM64(IFileFormatStream stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
||||||
|
|
||||||
public Il2CppBinaryARM64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
public Il2CppBinaryARM64(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
||||||
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
||||||
|
|
||||||
private (uint reg, ulong page)? getAdrp(uint inst, ulong pc) {
|
private (uint reg, ulong page)? getAdrp(uint inst, ulong pc) {
|
||||||
@@ -70,7 +70,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
private bool isB(uint inst) => inst.Bits(26, 6) == 0b_000101;
|
private bool isB(uint inst) => inst.Bits(26, 6) == 0b_000101;
|
||||||
|
|
||||||
private Dictionary<uint, ulong> sweepForAddressLoads(List<uint> func, ulong baseAddress, IFileFormatReader image) {
|
private Dictionary<uint, ulong> sweepForAddressLoads(List<uint> func, ulong baseAddress, IFileFormatStream image) {
|
||||||
// List of registers and addresses loaded into them
|
// List of registers and addresses loaded into them
|
||||||
var regs = new Dictionary<uint, ulong>();
|
var regs = new Dictionary<uint, ulong>();
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ namespace Il2CppInspector
|
|||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<uint> getFunctionAtFileOffset(IFileFormatReader image, uint loc, uint maxLength) {
|
private List<uint> getFunctionAtFileOffset(IFileFormatStream image, uint loc, uint maxLength) {
|
||||||
// Read a function that ends in a hard branch (B) or exceeds maxLength instructions
|
// Read a function that ends in a hard branch (B) or exceeds maxLength instructions
|
||||||
var func = new List<uint>();
|
var func = new List<uint>();
|
||||||
uint inst;
|
uint inst;
|
||||||
@@ -141,7 +141,7 @@ namespace Il2CppInspector
|
|||||||
// - Loads can be done either with ADRP+ADD (loads the address of the wanted struct) or ADRP+LDR (loads a pointer to the address which must be de-referenced)
|
// - Loads can be done either with ADRP+ADD (loads the address of the wanted struct) or ADRP+LDR (loads a pointer to the address which must be de-referenced)
|
||||||
// - Loads do not need to be pairs of sequential instructions
|
// - Loads do not need to be pairs of sequential instructions
|
||||||
// - We need to sweep the whole function from the ADRP to the next B to find an ADD or LDR with a corresponding register
|
// - We need to sweep the whole function from the ADRP to the next B to find an ADD or LDR with a corresponding register
|
||||||
protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) {
|
protected override (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc) {
|
||||||
// Load function into memory
|
// Load function into memory
|
||||||
// In practice, the longest function length we need is not generally longer than 7 instructions (0x1C bytes)
|
// In practice, the longest function length we need is not generally longer than 7 instructions (0x1C bytes)
|
||||||
var func = getFunctionAtFileOffset(image, loc, 7);
|
var func = getFunctionAtFileOffset(image, loc, 7);
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class Il2CppBinaryX64 : Il2CppBinary
|
internal class Il2CppBinaryX64 : Il2CppBinary
|
||||||
{
|
{
|
||||||
public Il2CppBinaryX64(IFileFormatReader stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
public Il2CppBinaryX64(IFileFormatStream stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
||||||
|
|
||||||
public Il2CppBinaryX64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
public Il2CppBinaryX64(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
||||||
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
||||||
|
|
||||||
// Format of 64-bit LEA:
|
// Format of 64-bit LEA:
|
||||||
@@ -94,7 +94,7 @@ namespace Il2CppInspector
|
|||||||
return ((buff[offset + 1] & 0b0011_1000) >> 3, buff[offset + 1] & 0b0000_0111);
|
return ((buff[offset + 1] & 0b0011_1000) >> 3, buff[offset + 1] & 0b0000_0111);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) {
|
protected override (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc) {
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
var buffSize = 0x76; // minimum number of bytes to process the longest expected function
|
var buffSize = 0x76; // minimum number of bytes to process the longest expected function
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class Il2CppBinaryX86 : Il2CppBinary
|
internal class Il2CppBinaryX86 : Il2CppBinary
|
||||||
{
|
{
|
||||||
public Il2CppBinaryX86(IFileFormatReader stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
public Il2CppBinaryX86(IFileFormatStream stream, EventHandler<string> statusCallback = null) : base(stream, statusCallback) { }
|
||||||
|
|
||||||
public Il2CppBinaryX86(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
public Il2CppBinaryX86(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null)
|
||||||
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
: base(stream, codeRegistration, metadataRegistration, statusCallback) { }
|
||||||
|
|
||||||
protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) {
|
protected override (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc) {
|
||||||
ulong metadata, code;
|
ulong metadata, code;
|
||||||
long pCgr;
|
long pCgr;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ namespace Il2CppInspector.Cpp
|
|||||||
public static class CppCompiler
|
public static class CppCompiler
|
||||||
{
|
{
|
||||||
// Attempt to guess the compiler used to build the binary via its file type
|
// Attempt to guess the compiler used to build the binary via its file type
|
||||||
public static CppCompilerType GuessFromImage(IFileFormatReader image) => (image is PEReader? CppCompilerType.MSVC : CppCompilerType.GCC);
|
public static CppCompilerType GuessFromImage(IFileFormatStream image) => (image is PEReader? CppCompilerType.MSVC : CppCompilerType.GCC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,11 @@ using System.Linq;
|
|||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
// This is a wrapper for multiple binary files of different architectures within a single AAB
|
// This is a wrapper for multiple binary files of different architectures within a single AAB
|
||||||
internal class AABReader : FileFormatReader<AABReader>
|
internal class AABReader : FileFormatStream<AABReader>
|
||||||
{
|
{
|
||||||
private ZipArchive zip;
|
private ZipArchive zip;
|
||||||
private ZipArchiveEntry[] binaryFiles;
|
private ZipArchiveEntry[] binaryFiles;
|
||||||
|
|
||||||
public AABReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "Package.aab";
|
public override string DefaultFilename => "Package.aab";
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
@@ -32,7 +30,7 @@ namespace Il2CppInspector
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
zip = new ZipArchive(BaseStream);
|
zip = new ZipArchive(this);
|
||||||
|
|
||||||
// Get list of binary files
|
// Get list of binary files
|
||||||
binaryFiles = zip.Entries.Where(f => f.FullName.StartsWith("base/lib/") && f.Name == "libil2cpp.so").ToArray();
|
binaryFiles = zip.Entries.Where(f => f.FullName.StartsWith("base/lib/") && f.Name == "libil2cpp.so").ToArray();
|
||||||
@@ -51,10 +49,10 @@ namespace Il2CppInspector
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IFileFormatReader this[uint index] {
|
public override IFileFormatStream this[uint index] {
|
||||||
get {
|
get {
|
||||||
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||||
IFileFormatReader loaded = null;
|
IFileFormatStream loaded = null;
|
||||||
|
|
||||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||||
var binary = binaryFiles[index].Open();
|
var binary = binaryFiles[index].Open();
|
||||||
@@ -13,13 +13,11 @@ using System.Linq;
|
|||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
// This is a wrapper for multiple binary files of different architectures within a single APK
|
// This is a wrapper for multiple binary files of different architectures within a single APK
|
||||||
internal class APKReader : FileFormatReader<APKReader>
|
internal class APKReader : FileFormatStream<APKReader>
|
||||||
{
|
{
|
||||||
private ZipArchive zip;
|
private ZipArchive zip;
|
||||||
private ZipArchiveEntry[] binaryFiles;
|
private ZipArchiveEntry[] binaryFiles;
|
||||||
|
|
||||||
public APKReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "Package.apk";
|
public override string DefaultFilename => "Package.apk";
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
@@ -32,7 +30,7 @@ namespace Il2CppInspector
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
zip = new ZipArchive(BaseStream);
|
zip = new ZipArchive(this);
|
||||||
|
|
||||||
// Get list of binary files
|
// Get list of binary files
|
||||||
binaryFiles = zip.Entries.Where(f => f.FullName.StartsWith("lib/") && f.Name == "libil2cpp.so").ToArray();
|
binaryFiles = zip.Entries.Where(f => f.FullName.StartsWith("lib/") && f.Name == "libil2cpp.so").ToArray();
|
||||||
@@ -51,10 +49,10 @@ namespace Il2CppInspector
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IFileFormatReader this[uint index] {
|
public override IFileFormatStream this[uint index] {
|
||||||
get {
|
get {
|
||||||
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||||
IFileFormatReader loaded = null;
|
IFileFormatStream loaded = null;
|
||||||
|
|
||||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||||
var binary = binaryFiles[index].Open();
|
var binary = binaryFiles[index].Open();
|
||||||
@@ -17,7 +17,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class ElfReader32 : ElfReader<uint, elf_32_phdr, elf_32_sym, ElfReader32, Convert32>
|
internal class ElfReader32 : ElfReader<uint, elf_32_phdr, elf_32_sym, ElfReader32, Convert32>
|
||||||
{
|
{
|
||||||
public ElfReader32(Stream stream) : base(stream) {
|
public ElfReader32() : base() {
|
||||||
ElfReloc.GetRelocType = info => (Elf) (info & 0xff);
|
ElfReloc.GetRelocType = info => (Elf) (info & 0xff);
|
||||||
ElfReloc.GetSymbolIndex = info => info >> 8;
|
ElfReloc.GetSymbolIndex = info => info >> 8;
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,12 @@ namespace Il2CppInspector
|
|||||||
public override int Bits => 32;
|
public override int Bits => 32;
|
||||||
protected override Elf ArchClass => Elf.ELFCLASS32;
|
protected override Elf ArchClass => Elf.ELFCLASS32;
|
||||||
|
|
||||||
protected override void Write(BinaryWriter writer, uint value) => writer.Write(value);
|
protected override void WriteWord(uint value) => Write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ElfReader64 : ElfReader<ulong, elf_64_phdr, elf_64_sym, ElfReader64, Convert64>
|
internal class ElfReader64 : ElfReader<ulong, elf_64_phdr, elf_64_sym, ElfReader64, Convert64>
|
||||||
{
|
{
|
||||||
public ElfReader64(Stream stream) : base(stream) {
|
public ElfReader64() : base() {
|
||||||
ElfReloc.GetRelocType = info => (Elf) (info & 0xffff_ffff);
|
ElfReloc.GetRelocType = info => (Elf) (info & 0xffff_ffff);
|
||||||
ElfReloc.GetSymbolIndex = info => info >> 32;
|
ElfReloc.GetSymbolIndex = info => info >> 32;
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ namespace Il2CppInspector
|
|||||||
public override int Bits => 64;
|
public override int Bits => 64;
|
||||||
protected override Elf ArchClass => Elf.ELFCLASS64;
|
protected override Elf ArchClass => Elf.ELFCLASS64;
|
||||||
|
|
||||||
protected override void Write(BinaryWriter writer, ulong value) => writer.Write(value);
|
protected override void WriteWord(ulong value) => Write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IElfReader
|
interface IElfReader
|
||||||
@@ -46,12 +46,12 @@ namespace Il2CppInspector
|
|||||||
uint GetPLTAddress();
|
uint GetPLTAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class ElfReader<TWord, TPHdr, TSym, TReader, TConvert> : FileFormatReader<TReader>, IElfReader
|
internal abstract class ElfReader<TWord, TPHdr, TSym, TReader, TConvert> : FileFormatStream<TReader>, IElfReader
|
||||||
where TWord : struct
|
where TWord : struct
|
||||||
where TPHdr : Ielf_phdr<TWord>, new()
|
where TPHdr : Ielf_phdr<TWord>, new()
|
||||||
where TSym : Ielf_sym<TWord>, new()
|
where TSym : Ielf_sym<TWord>, new()
|
||||||
where TConvert : IWordConverter<TWord>, new()
|
where TConvert : IWordConverter<TWord>, new()
|
||||||
where TReader : FileFormatReader<TReader>
|
where TReader : FileFormatStream<TReader>
|
||||||
{
|
{
|
||||||
private readonly TConvert conv = new TConvert();
|
private readonly TConvert conv = new TConvert();
|
||||||
|
|
||||||
@@ -115,8 +115,6 @@ namespace Il2CppInspector
|
|||||||
private bool preferPHT = false;
|
private bool preferPHT = false;
|
||||||
private bool isMemoryImage = false;
|
private bool isMemoryImage = false;
|
||||||
|
|
||||||
public ElfReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "libil2cpp.so";
|
public override string DefaultFilename => "libil2cpp.so";
|
||||||
|
|
||||||
public override string Format => Bits == 32 ? "ELF" : "ELF64";
|
public override string Format => Bits == 32 ? "ELF" : "ELF64";
|
||||||
@@ -141,7 +139,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
protected abstract Elf ArchClass { get; }
|
protected abstract Elf ArchClass { get; }
|
||||||
|
|
||||||
protected abstract void Write(BinaryWriter writer, TWord value);
|
protected abstract void WriteWord(TWord value);
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
elf_header = ReadObject<elf_header<TWord>>();
|
elf_header = ReadObject<elf_header<TWord>>();
|
||||||
@@ -154,10 +152,6 @@ namespace Il2CppInspector
|
|||||||
if ((Elf) elf_header.m_arch != ArchClass)
|
if ((Elf) elf_header.m_arch != ArchClass)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Relocations and rebasing will modify the stream - ensure it is non-destructive
|
|
||||||
if (!(BaseStream is MemoryStream))
|
|
||||||
throw new InvalidOperationException("Input stream to ElfReader must be a MemoryStream.");
|
|
||||||
|
|
||||||
// Get PHT and SHT
|
// Get PHT and SHT
|
||||||
program_header_table = ReadArray<TPHdr>(conv.Long(elf_header.e_phoff), elf_header.e_phnum);
|
program_header_table = ReadArray<TPHdr>(conv.Long(elf_header.e_phoff), elf_header.e_phnum);
|
||||||
section_header_table = ReadArray<elf_shdr<TWord>>(conv.Long(elf_header.e_shoff), elf_header.e_shnum);
|
section_header_table = ReadArray<elf_shdr<TWord>>(conv.Long(elf_header.e_shoff), elf_header.e_shnum);
|
||||||
@@ -283,7 +277,6 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process relocations
|
// Process relocations
|
||||||
using var writer = new BinaryWriter(BaseStream, Encoding.Default, true);
|
|
||||||
var relsz = Sizeof(typeof(TSym));
|
var relsz = Sizeof(typeof(TSym));
|
||||||
|
|
||||||
var currentRel = 0;
|
var currentRel = 0;
|
||||||
@@ -334,7 +327,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
if (result.recognized) {
|
if (result.recognized) {
|
||||||
Position = MapVATR(conv.ULong(rel.Offset));
|
Position = MapVATR(conv.ULong(rel.Offset));
|
||||||
Write(writer, result.newValue);
|
WriteWord(result.newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Console.WriteLine($"Processed {rels.Count} relocations");
|
Console.WriteLine($"Processed {rels.Count} relocations");
|
||||||
@@ -525,12 +518,9 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void xorRange(int offset, int length, byte xorValue) {
|
private void xorRange(int offset, int length, byte xorValue) {
|
||||||
using var writer = new BinaryWriter(BaseStream, Encoding.Default, true);
|
|
||||||
|
|
||||||
var bytes = ReadBytes(offset, length);
|
var bytes = ReadBytes(offset, length);
|
||||||
bytes = bytes.Select(b => (byte) (b ^ xorValue)).ToArray();
|
bytes = bytes.Select(b => (byte) (b ^ xorValue)).ToArray();
|
||||||
writer.Seek(offset, SeekOrigin.Begin);
|
Write(offset, bytes);
|
||||||
writer.Write(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void xorSection(string sectionName, byte xorValue, uint stripeSize) {
|
private void xorSection(string sectionName, byte xorValue, uint stripeSize) {
|
||||||
@@ -571,8 +561,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite to stream
|
// Rewrite to stream
|
||||||
using var writer = new BinaryObjectWriter(BaseStream, Endianness, true);
|
WriteArray(conv.Long(elf_header.e_phoff), program_header_table);
|
||||||
writer.WriteArray(conv.Long(elf_header.e_phoff), program_header_table);
|
|
||||||
IsModified = true;
|
IsModified = true;
|
||||||
|
|
||||||
// Rebase dynamic table if it exists
|
// Rebase dynamic table if it exists
|
||||||
@@ -595,7 +584,7 @@ namespace Il2CppInspector
|
|||||||
section.d_un = conv.Add(section.d_un, imageBase);
|
section.d_un = conv.Add(section.d_un, imageBase);
|
||||||
|
|
||||||
// Rewrite to stream
|
// Rewrite to stream
|
||||||
writer.WriteArray(conv.Long(PT_DYNAMIC.p_offset), dt);
|
WriteArray(conv.Long(PT_DYNAMIC.p_offset), dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processSymbols() {
|
private void processSymbols() {
|
||||||
@@ -14,23 +14,22 @@ using NoisyCowStudios.Bin2Object;
|
|||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public interface IFileFormatReader
|
public interface IFileFormatStream
|
||||||
{
|
{
|
||||||
BinaryObjectReader Stream { get; }
|
|
||||||
double Version { get; set; }
|
double Version { get; set; }
|
||||||
long Length { get; }
|
long Length { get; }
|
||||||
uint NumImages { get; }
|
uint NumImages { get; }
|
||||||
string DefaultFilename { get; }
|
string DefaultFilename { get; }
|
||||||
bool IsModified { get; }
|
bool IsModified { get; }
|
||||||
IEnumerable<IFileFormatReader> Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file)
|
IEnumerable<IFileFormatStream> Images { get; } // Each child image of this object (eg. 32/64-bit versions in Fat MachO file)
|
||||||
IFileFormatReader this[uint index] { get; } // With no additional override, one object = one file, this[0] == this
|
IFileFormatStream this[uint index] { get; } // With no additional override, one object = one file, this[0] == this
|
||||||
long Position { get; set; }
|
long Position { get; set; }
|
||||||
string Format { get; }
|
string Format { get; }
|
||||||
string Arch { get; }
|
string Arch { get; }
|
||||||
int Bits { get; }
|
int Bits { get; }
|
||||||
ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory
|
ulong GlobalOffset { get; } // The virtual address where the code section (.text) would be loaded in memory
|
||||||
ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE)
|
ulong ImageBase { get; } // The virtual address of where the image would be loaded in memory (same as GlobalOffset except for PE)
|
||||||
IEnumerable<IFileFormatReader> TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed
|
IEnumerable<IFileFormatStream> TryNextLoadStrategy(); // Some images can be loaded multiple ways, eg. default, packed
|
||||||
Dictionary<string, Symbol> GetSymbolTable();
|
Dictionary<string, Symbol> GetSymbolTable();
|
||||||
uint[] GetFunctionTable();
|
uint[] GetFunctionTable();
|
||||||
IEnumerable<Export> GetExports();
|
IEnumerable<Export> GetExports();
|
||||||
@@ -92,24 +91,52 @@ namespace Il2CppInspector
|
|||||||
long[] ReadMappedWordArray(ulong uiAddr, int count);
|
long[] ReadMappedWordArray(ulong uiAddr, int count);
|
||||||
List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new();
|
List<U> ReadMappedObjectPointerArray<U>(ulong uiAddr, int count) where U : new();
|
||||||
|
|
||||||
|
void WriteEndianBytes(byte[] bytes);
|
||||||
|
void Write(long int64);
|
||||||
|
void Write(ulong uint64);
|
||||||
|
void Write(int int32);
|
||||||
|
void Write(uint uint32);
|
||||||
|
void Write(short int16);
|
||||||
|
void Write(ushort uint16);
|
||||||
|
void Write(long addr, byte[] bytes);
|
||||||
|
void Write(long addr, long int64);
|
||||||
|
void Write(long addr, ulong uint64);
|
||||||
|
void Write(long addr, int int32);
|
||||||
|
void Write(long addr, uint uint32);
|
||||||
|
void Write(long addr, short int16);
|
||||||
|
void Write(long addr, ushort uint16);
|
||||||
|
void Write(long addr, byte value);
|
||||||
|
void Write(long addr, bool value);
|
||||||
|
void WriteObject<T>(long addr, T obj);
|
||||||
|
void WriteObject<T>(T obj);
|
||||||
|
void WriteArray<T>(long addr, T[] array);
|
||||||
|
void WriteArray<T>(T[] array);
|
||||||
|
void WriteNullTerminatedString(long addr, string str, Encoding encoding = null);
|
||||||
|
void WriteNullTerminatedString(string str, Encoding encoding = null);
|
||||||
|
void WriteFixedLengthString(long addr, string str, int size = -1, Encoding encoding = null);
|
||||||
|
void WriteFixedLengthString(string str, int size = -1, Encoding encoding = null);
|
||||||
|
|
||||||
EventHandler<string> OnStatusUpdate { get; set; }
|
EventHandler<string> OnStatusUpdate { get; set; }
|
||||||
|
|
||||||
|
public void AddPrimitiveMapping(Type objType, Type streamType);
|
||||||
|
public void CopyTo(Stream stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FileFormatReader
|
public class FileFormatStream
|
||||||
{
|
{
|
||||||
// Helper method to try all defined file formats when the contents of the binary is unknown
|
// Helper method to try all defined file formats when the contents of the binary is unknown
|
||||||
public static IFileFormatReader Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null)
|
public static IFileFormatStream Load(string filename, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null)
|
||||||
=> Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback);
|
=> Load(new FileStream(filename, FileMode.Open, FileAccess.Read), loadOptions, statusCallback);
|
||||||
|
|
||||||
public static IFileFormatReader Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
public static IFileFormatStream Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
||||||
var types = Assembly.GetExecutingAssembly().DefinedTypes
|
var types = Assembly.GetExecutingAssembly().DefinedTypes
|
||||||
.Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatReader)) && !x.IsGenericTypeDefinition);
|
.Where(x => x.ImplementedInterfaces.Contains(typeof(IFileFormatStream)) && !x.IsGenericTypeDefinition);
|
||||||
|
|
||||||
foreach (var type in types) {
|
foreach (var type in types) {
|
||||||
try {
|
try {
|
||||||
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
|
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
|
||||||
null, new[] {typeof(Stream), typeof(LoadOptions), typeof(EventHandler<string>)}, null)
|
null, new[] {typeof(Stream), typeof(LoadOptions), typeof(EventHandler<string>)}, null)
|
||||||
.Invoke(null, new object[] {stream, loadOptions, statusCallback}) is IFileFormatReader loaded)
|
.Invoke(null, new object[] {stream, loadOptions, statusCallback}) is IFileFormatStream loaded)
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException ex) {
|
catch (TargetInvocationException ex) {
|
||||||
@@ -120,18 +147,12 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class FileFormatReader<T> : BinaryObjectReader, IFileFormatReader where T : FileFormatReader<T>
|
public abstract class FileFormatStream<T> : BinaryObjectStream, IFileFormatStream where T : FileFormatStream<T>
|
||||||
{
|
{
|
||||||
public FileFormatReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public BinaryObjectReader Stream => this;
|
|
||||||
|
|
||||||
public abstract string DefaultFilename { get; }
|
public abstract string DefaultFilename { get; }
|
||||||
|
|
||||||
public bool IsModified { get; protected set; } = false;
|
public bool IsModified { get; protected set; } = false;
|
||||||
|
|
||||||
public long Length => BaseStream.Length;
|
|
||||||
|
|
||||||
public uint NumImages { get; protected set; } = 1;
|
public uint NumImages { get; protected set; } = 1;
|
||||||
|
|
||||||
public ulong GlobalOffset { get; protected set; }
|
public ulong GlobalOffset { get; protected set; }
|
||||||
@@ -151,7 +172,7 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
|
protected void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
|
||||||
|
|
||||||
public IEnumerable<IFileFormatReader> Images {
|
public IEnumerable<IFileFormatStream> Images {
|
||||||
get {
|
get {
|
||||||
for (uint i = 0; i < NumImages; i++)
|
for (uint i = 0; i < NumImages; i++)
|
||||||
yield return this[i];
|
yield return this[i];
|
||||||
@@ -165,15 +186,12 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
public static T Load(Stream stream, LoadOptions loadOptions = null, EventHandler<string> statusCallback = null) {
|
||||||
// Copy the original stream in case we modify it
|
// Copy the original stream in case we modify it
|
||||||
var ms = new MemoryStream();
|
|
||||||
|
|
||||||
if (stream.CanSeek)
|
if (stream.CanSeek)
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
stream.CopyTo(ms);
|
var binary = (T) Activator.CreateInstance(typeof(T));
|
||||||
|
stream.CopyTo(binary);
|
||||||
ms.Position = 0;
|
binary.Position = 0;
|
||||||
var pe = (T) Activator.CreateInstance(typeof(T), ms);
|
return binary.InitImpl(loadOptions, statusCallback) ? binary : null;
|
||||||
return pe.InitImpl(loadOptions, statusCallback) ? pe : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool InitImpl(LoadOptions loadOptions, EventHandler<string> statusCallback) {
|
private bool InitImpl(LoadOptions loadOptions, EventHandler<string> statusCallback) {
|
||||||
@@ -186,10 +204,10 @@ namespace Il2CppInspector
|
|||||||
protected virtual bool Init() => throw new NotImplementedException();
|
protected virtual bool Init() => throw new NotImplementedException();
|
||||||
|
|
||||||
// Choose an image within the file for multi-architecture binaries
|
// Choose an image within the file for multi-architecture binaries
|
||||||
public virtual IFileFormatReader this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds");
|
public virtual IFileFormatStream this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds");
|
||||||
|
|
||||||
// For images that can be loaded and then tested with Il2CppBinary in multiple ways, get the next possible version of the image
|
// For images that can be loaded and then tested with Il2CppBinary in multiple ways, get the next possible version of the image
|
||||||
public virtual IEnumerable<IFileFormatReader> TryNextLoadStrategy() { yield return this; }
|
public virtual IEnumerable<IFileFormatStream> TryNextLoadStrategy() { yield return this; }
|
||||||
|
|
||||||
// Find search locations in the symbol table for Il2Cpp data
|
// Find search locations in the symbol table for Il2Cpp data
|
||||||
public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>();
|
public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>();
|
||||||
@@ -15,8 +15,6 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class MachOReader32 : MachOReader<uint, MachOReader32, Convert32>
|
internal class MachOReader32 : MachOReader<uint, MachOReader32, Convert32>
|
||||||
{
|
{
|
||||||
public MachOReader32(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override int Bits => 32;
|
public override int Bits => 32;
|
||||||
|
|
||||||
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC;
|
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC;
|
||||||
@@ -37,8 +35,6 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
internal class MachOReader64 : MachOReader<ulong, MachOReader64, Convert64>
|
internal class MachOReader64 : MachOReader<ulong, MachOReader64, Convert64>
|
||||||
{
|
{
|
||||||
public MachOReader64(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override int Bits => 64;
|
public override int Bits => 64;
|
||||||
|
|
||||||
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC_64;
|
protected override bool checkMagicLE(MachO magic) => magic == MachO.MH_MAGIC_64;
|
||||||
@@ -59,9 +55,9 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// We need this convoluted generic TReader declaration so that "static T FileFormatReader.Load(Stream)"
|
// We need this convoluted generic TReader declaration so that "static T FileFormatReader.Load(Stream)"
|
||||||
// is inherited to MachOReader32/64 with a correct definition of T
|
// is inherited to MachOReader32/64 with a correct definition of T
|
||||||
internal abstract class MachOReader<TWord, TReader, TConvert> : FileFormatReader<TReader>
|
internal abstract class MachOReader<TWord, TReader, TConvert> : FileFormatStream<TReader>
|
||||||
where TWord : struct
|
where TWord : struct
|
||||||
where TReader : FileFormatReader<TReader>
|
where TReader : FileFormatStream<TReader>
|
||||||
where TConvert : IWordConverter<TWord>, new()
|
where TConvert : IWordConverter<TWord>, new()
|
||||||
{
|
{
|
||||||
private readonly TConvert conv = new TConvert();
|
private readonly TConvert conv = new TConvert();
|
||||||
@@ -75,8 +71,6 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
private List<Export> exports = new List<Export>();
|
private List<Export> exports = new List<Export>();
|
||||||
|
|
||||||
protected MachOReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "app";
|
public override string DefaultFilename => "app";
|
||||||
|
|
||||||
public override string Format => "Mach-O " + (Bits == 32 ? "32-bit" : "64-bit");
|
public override string Format => "Mach-O " + (Bits == 32 ? "32-bit" : "64-bit");
|
||||||
@@ -17,7 +17,7 @@ namespace Il2CppInspector
|
|||||||
// References:
|
// References:
|
||||||
// PE Header file: https://github.com/dotnet/llilc/blob/master/include/clr/ntimage.h
|
// PE Header file: https://github.com/dotnet/llilc/blob/master/include/clr/ntimage.h
|
||||||
// PE format specification: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format?redirectedfrom=MSDN
|
// PE format specification: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format?redirectedfrom=MSDN
|
||||||
internal class PEReader : FileFormatReader<PEReader>
|
internal class PEReader : FileFormatStream<PEReader>
|
||||||
{
|
{
|
||||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
private extern static IntPtr LoadLibrary(string lpLibFileName);
|
private extern static IntPtr LoadLibrary(string lpLibFileName);
|
||||||
@@ -38,8 +38,6 @@ namespace Il2CppInspector
|
|||||||
[PE.IMAGE_SCN_MEM_READ | PE.IMAGE_SCN_MEM_WRITE | PE.IMAGE_SCN_CNT_INITIALIZED_DATA] = ".data"
|
[PE.IMAGE_SCN_MEM_READ | PE.IMAGE_SCN_MEM_WRITE | PE.IMAGE_SCN_CNT_INITIALIZED_DATA] = ".data"
|
||||||
};
|
};
|
||||||
|
|
||||||
public PEReader(Stream stream) : base(stream) {}
|
|
||||||
|
|
||||||
public override string DefaultFilename => "GameAssembly.dll";
|
public override string DefaultFilename => "GameAssembly.dll";
|
||||||
|
|
||||||
|
|
||||||
@@ -187,22 +185,21 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Truncate memory stream at start of COFF header
|
// Truncate memory stream at start of COFF header
|
||||||
var endOfSignature = ReadUInt32(0x3C) + 4; // DOS header + 4-byte PE signature
|
var endOfSignature = ReadUInt32(0x3C) + 4; // DOS header + 4-byte PE signature
|
||||||
BaseStream.SetLength(endOfSignature);
|
SetLength(endOfSignature);
|
||||||
|
|
||||||
// Re-write the stream (the headers are only necessary in case the user wants to save)
|
// Re-write the stream (the headers are only necessary in case the user wants to save)
|
||||||
using var writer = new BinaryObjectWriter(BaseStream, Endianness, true);
|
Position = endOfSignature;
|
||||||
writer.Position = endOfSignature;
|
WriteObject(coff);
|
||||||
writer.WriteObject(coff);
|
if (Bits == 32) WriteObject((PEOptHeader32) pe);
|
||||||
if (Bits == 32) writer.WriteObject((PEOptHeader32) pe);
|
else WriteObject((PEOptHeader64) pe);
|
||||||
else writer.WriteObject((PEOptHeader64) pe);
|
WriteArray(sections);
|
||||||
writer.WriteArray(sections);
|
Write(peBytes, (int) Position, peBytes.Length - (int) Position);
|
||||||
writer.Write(peBytes, (int) Position, peBytes.Length - (int) Position);
|
|
||||||
|
|
||||||
IsModified = true;
|
IsModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw file / unpacked file load strategies
|
// Raw file / unpacked file load strategies
|
||||||
public override IEnumerable<IFileFormatReader> TryNextLoadStrategy() {
|
public override IEnumerable<IFileFormatStream> TryNextLoadStrategy() {
|
||||||
// First load strategy: the regular file
|
// First load strategy: the regular file
|
||||||
yield return this;
|
yield return this;
|
||||||
|
|
||||||
@@ -15,12 +15,10 @@ namespace Il2CppInspector
|
|||||||
// This is a wrapper for a Linux memory dump
|
// This is a wrapper for a Linux memory dump
|
||||||
// The supplied file is a text file containing the output of "cat /proc/["self"|process-id]/maps"
|
// The supplied file is a text file containing the output of "cat /proc/["self"|process-id]/maps"
|
||||||
// We re-construct libil2cpp.so from the *.bin files and return it as the first image
|
// We re-construct libil2cpp.so from the *.bin files and return it as the first image
|
||||||
internal class ProcessMapReader : FileFormatReader<ProcessMapReader>
|
internal class ProcessMapReader : FileFormatStream<ProcessMapReader>
|
||||||
{
|
{
|
||||||
private MemoryStream il2cpp;
|
private MemoryStream il2cpp;
|
||||||
|
|
||||||
public ProcessMapReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "maps.txt";
|
public override string DefaultFilename => "maps.txt";
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
@@ -30,7 +28,7 @@ namespace Il2CppInspector
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get the entire stream as a string
|
// Get the entire stream as a string
|
||||||
var text = System.Text.Encoding.ASCII.GetString((BaseStream as MemoryStream).ToArray());
|
var text = System.Text.Encoding.ASCII.GetString(ToArray());
|
||||||
|
|
||||||
// Line format is: https://stackoverflow.com/questions/1401359/understanding-linux-proc-id-maps
|
// Line format is: https://stackoverflow.com/questions/1401359/understanding-linux-proc-id-maps
|
||||||
// xxxxxxxx-yyyyyyyy ffff zzzzzzzz aa:bb c [whitespace] [image path]
|
// xxxxxxxx-yyyyyyyy ffff zzzzzzzz aa:bb c [whitespace] [image path]
|
||||||
@@ -105,10 +103,10 @@ namespace Il2CppInspector
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IFileFormatReader this[uint index] {
|
public override IFileFormatStream this[uint index] {
|
||||||
get {
|
get {
|
||||||
// Get merged stream as ELF file
|
// Get merged stream as ELF file
|
||||||
return (IFileFormatReader) ElfReader32.Load(il2cpp, LoadOptions, OnStatusUpdate) ?? ElfReader64.Load(il2cpp, LoadOptions, OnStatusUpdate);
|
return (IFileFormatStream) ElfReader32.Load(il2cpp, LoadOptions, OnStatusUpdate) ?? ElfReader64.Load(il2cpp, LoadOptions, OnStatusUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,10 +24,8 @@ namespace Il2CppInspector
|
|||||||
// https://www.psxhax.com/threads/ps4-self-spkg-file-format-documentation-detailed-for-scene-devs.6636/
|
// https://www.psxhax.com/threads/ps4-self-spkg-file-format-documentation-detailed-for-scene-devs.6636/
|
||||||
// https://wiki.henkaku.xyz/vita/images/a/a2/Vita_SDK_specifications.pdf
|
// https://wiki.henkaku.xyz/vita/images/a/a2/Vita_SDK_specifications.pdf
|
||||||
// https://www.psxhax.com/threads/make-fself-gui-for-flat_zs-make_fself-py-script-by-cfwprophet.3494/
|
// https://www.psxhax.com/threads/make-fself-gui-for-flat_zs-make_fself-py-script-by-cfwprophet.3494/
|
||||||
internal class SElfReader : FileFormatReader<SElfReader>
|
internal class SElfReader : FileFormatStream<SElfReader>
|
||||||
{
|
{
|
||||||
public SElfReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "libil2cpp.so";
|
public override string DefaultFilename => "libil2cpp.so";
|
||||||
|
|
||||||
public override string Format => sceData.ProductType == (ulong) SElfExInfoTypes.PTYPE_FAKE? "FSELF" : "SELF";
|
public override string Format => sceData.ProductType == (ulong) SElfExInfoTypes.PTYPE_FAKE? "FSELF" : "SELF";
|
||||||
@@ -9,12 +9,10 @@ using NoisyCowStudios.Bin2Object;
|
|||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
internal class UBReader : FileFormatReader<UBReader>
|
internal class UBReader : FileFormatStream<UBReader>
|
||||||
{
|
{
|
||||||
private FatHeader header;
|
private FatHeader header;
|
||||||
|
|
||||||
public UBReader(Stream stream) : base(stream) { }
|
|
||||||
|
|
||||||
public override string DefaultFilename => "app";
|
public override string DefaultFilename => "app";
|
||||||
|
|
||||||
protected override bool Init() {
|
protected override bool Init() {
|
||||||
@@ -30,7 +28,7 @@ namespace Il2CppInspector
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IFileFormatReader this[uint index] {
|
public override IFileFormatStream this[uint index] {
|
||||||
get {
|
get {
|
||||||
Position = 0x8 + 0x14 * index; // sizeof(FatHeader), sizeof(FatArch)
|
Position = 0x8 + 0x14 * index; // sizeof(FatHeader), sizeof(FatArch)
|
||||||
Endianness = Endianness.Big;
|
Endianness = Endianness.Big;
|
||||||
@@ -41,7 +39,7 @@ namespace Il2CppInspector
|
|||||||
Endianness = Endianness.Little;
|
Endianness = Endianness.Little;
|
||||||
|
|
||||||
using var s = new MemoryStream(ReadBytes((int) arch.Size));
|
using var s = new MemoryStream(ReadBytes((int) arch.Size));
|
||||||
return (IFileFormatReader) MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate);
|
return (IFileFormatStream) MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
public abstract partial class Il2CppBinary
|
public abstract partial class Il2CppBinary
|
||||||
{
|
{
|
||||||
public IFileFormatReader Image { get; }
|
public IFileFormatStream Image { get; }
|
||||||
|
|
||||||
// IL2CPP-only API exports with decrypted names
|
// IL2CPP-only API exports with decrypted names
|
||||||
public Dictionary<string, ulong> APIExports { get; } = new Dictionary<string, ulong>();
|
public Dictionary<string, ulong> APIExports { get; } = new Dictionary<string, ulong>();
|
||||||
@@ -92,7 +92,7 @@ namespace Il2CppInspector
|
|||||||
private bool isModified = false;
|
private bool isModified = false;
|
||||||
public bool IsModified => Image.IsModified || isModified;
|
public bool IsModified => Image.IsModified || isModified;
|
||||||
|
|
||||||
protected Il2CppBinary(IFileFormatReader stream, EventHandler<string> statusCallback = null) {
|
protected Il2CppBinary(IFileFormatStream stream, EventHandler<string> statusCallback = null) {
|
||||||
Image = stream;
|
Image = stream;
|
||||||
OnStatusUpdate = statusCallback;
|
OnStatusUpdate = statusCallback;
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ namespace Il2CppInspector
|
|||||||
DiscoverAPIExports();
|
DiscoverAPIExports();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Il2CppBinary(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) {
|
protected Il2CppBinary(IFileFormatStream stream, uint codeRegistration, uint metadataRegistration, EventHandler<string> statusCallback = null) {
|
||||||
Image = stream;
|
Image = stream;
|
||||||
OnStatusUpdate = statusCallback;
|
OnStatusUpdate = statusCallback;
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load and initialize a binary of any supported architecture
|
// Load and initialize a binary of any supported architecture
|
||||||
private static Il2CppBinary LoadImpl(IFileFormatReader stream, EventHandler<string> statusCallback) {
|
private static Il2CppBinary LoadImpl(IFileFormatStream stream, EventHandler<string> statusCallback) {
|
||||||
// Get type from image architecture
|
// Get type from image architecture
|
||||||
var type = Assembly.GetExecutingAssembly().GetType("Il2CppInspector.Il2CppBinary" + stream.Arch.ToUpper());
|
var type = Assembly.GetExecutingAssembly().GetType("Il2CppInspector.Il2CppBinary" + stream.Arch.ToUpper());
|
||||||
if (type == null)
|
if (type == null)
|
||||||
@@ -118,15 +118,15 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
// Set width of long (convert to sizeof(int) for 32-bit files)
|
// Set width of long (convert to sizeof(int) for 32-bit files)
|
||||||
if (stream[0].Bits == 32) {
|
if (stream[0].Bits == 32) {
|
||||||
stream[0].Stream.PrimitiveMappings.Add(typeof(long), typeof(int));
|
stream[0].AddPrimitiveMapping(typeof(long), typeof(int));
|
||||||
stream[0].Stream.PrimitiveMappings.Add(typeof(ulong), typeof(uint));
|
stream[0].AddPrimitiveMapping(typeof(ulong), typeof(uint));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Il2CppBinary) Activator.CreateInstance(type, stream[0], statusCallback);
|
return (Il2CppBinary) Activator.CreateInstance(type, stream[0], statusCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load binary without a global-metadata.dat available
|
// Load binary without a global-metadata.dat available
|
||||||
public static Il2CppBinary Load(IFileFormatReader stream, double metadataVersion, EventHandler<string> statusCallback = null) {
|
public static Il2CppBinary Load(IFileFormatStream stream, double metadataVersion, EventHandler<string> statusCallback = null) {
|
||||||
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
||||||
var inst = LoadImpl(stream, statusCallback);
|
var inst = LoadImpl(stream, statusCallback);
|
||||||
if (inst.FindRegistrationStructs(metadataVersion))
|
if (inst.FindRegistrationStructs(metadataVersion))
|
||||||
@@ -140,7 +140,7 @@ namespace Il2CppInspector
|
|||||||
// If it is specified and both symbol table and function scanning fail,
|
// If it is specified and both symbol table and function scanning fail,
|
||||||
// Metadata will be used to try to find the required structures with data analysis
|
// Metadata will be used to try to find the required structures with data analysis
|
||||||
// If it is not specified, data analysis will not be performed
|
// If it is not specified, data analysis will not be performed
|
||||||
public static Il2CppBinary Load(IFileFormatReader stream, Metadata metadata, EventHandler<string> statusCallback = null) {
|
public static Il2CppBinary Load(IFileFormatStream stream, Metadata metadata, EventHandler<string> statusCallback = null) {
|
||||||
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
foreach (var loadedImage in stream.TryNextLoadStrategy()) {
|
||||||
var inst = LoadImpl(stream, statusCallback);
|
var inst = LoadImpl(stream, statusCallback);
|
||||||
if (inst.FindRegistrationStructs(metadata))
|
if (inst.FindRegistrationStructs(metadata))
|
||||||
@@ -154,7 +154,7 @@ namespace Il2CppInspector
|
|||||||
public void SaveToFile(string pathname) {
|
public void SaveToFile(string pathname) {
|
||||||
Image.Position = 0;
|
Image.Position = 0;
|
||||||
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
|
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
|
||||||
Image.Stream.BaseStream.CopyTo(outFile);
|
Image.CopyTo(outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize binary without a global-metadata.dat available
|
// Initialize binary without a global-metadata.dat available
|
||||||
@@ -244,7 +244,7 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Architecture-specific search function
|
// Architecture-specific search function
|
||||||
protected abstract (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc);
|
protected abstract (ulong, ulong) ConsiderCode(IFileFormatStream image, uint loc);
|
||||||
|
|
||||||
// Load all of the discovered metadata in the binary
|
// Load all of the discovered metadata in the binary
|
||||||
private void PrepareMetadata(ulong codeRegistration, ulong metadataRegistration, Metadata metadata = null) {
|
private void PrepareMetadata(ulong codeRegistration, ulong metadataRegistration, Metadata metadata = null) {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Il2CppInspector
|
|||||||
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices;
|
public Dictionary<Il2CppMethodSpec, int> GenericMethodInvokerIndices => Binary.GenericMethodInvokerIndices;
|
||||||
|
|
||||||
// TODO: Finish all file access in the constructor and eliminate the need for this
|
// TODO: Finish all file access in the constructor and eliminate the need for this
|
||||||
public IFileFormatReader BinaryImage => Binary.Image;
|
public IFileFormatStream BinaryImage => Binary.Image;
|
||||||
|
|
||||||
private (ulong MetadataAddress, object Value)? getDefaultValue(int typeIndex, int dataIndex) {
|
private (ulong MetadataAddress, object Value)? getDefaultValue(int typeIndex, int dataIndex) {
|
||||||
// No default
|
// No default
|
||||||
@@ -543,7 +543,7 @@ namespace Il2CppInspector
|
|||||||
// Load the metadata file
|
// Load the metadata file
|
||||||
Metadata metadata;
|
Metadata metadata;
|
||||||
try {
|
try {
|
||||||
metadata = new Metadata(metadataStream, statusCallback);
|
metadata = Metadata.FromStream(metadataStream, statusCallback);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
Console.Error.WriteLine(ex.Message);
|
Console.Error.WriteLine(ex.Message);
|
||||||
@@ -554,9 +554,9 @@ namespace Il2CppInspector
|
|||||||
Console.WriteLine("Detected metadata version " + metadata.Version);
|
Console.WriteLine("Detected metadata version " + metadata.Version);
|
||||||
|
|
||||||
// Load the il2cpp code file (try all available file formats)
|
// Load the il2cpp code file (try all available file formats)
|
||||||
IFileFormatReader stream;
|
IFileFormatStream stream;
|
||||||
try {
|
try {
|
||||||
stream = FileFormatReader.Load(binaryStream, loadOptions, statusCallback);
|
stream = FileFormatStream.Load(binaryStream, loadOptions, statusCallback);
|
||||||
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
throw new InvalidOperationException("Unsupported executable file format");
|
throw new InvalidOperationException("Unsupported executable file format");
|
||||||
@@ -571,7 +571,7 @@ namespace Il2CppInspector
|
|||||||
var processors = new List<Il2CppInspector>();
|
var processors = new List<Il2CppInspector>();
|
||||||
foreach (var image in stream.Images) {
|
foreach (var image in stream.Images) {
|
||||||
Console.WriteLine("Container format: " + image.Format);
|
Console.WriteLine("Container format: " + image.Format);
|
||||||
Console.WriteLine("Container endianness: " + ((BinaryObjectReader) image).Endianness);
|
Console.WriteLine("Container endianness: " + ((BinaryObjectStream) image).Endianness);
|
||||||
Console.WriteLine("Architecture word size: {0}-bit", image.Bits);
|
Console.WriteLine("Architecture word size: {0}-bit", image.Bits);
|
||||||
Console.WriteLine("Instruction set: " + image.Arch);
|
Console.WriteLine("Instruction set: " + image.Arch);
|
||||||
Console.WriteLine("Global offset: 0x{0:X16}", image.GlobalOffset);
|
Console.WriteLine("Global offset: 0x{0:X16}", image.GlobalOffset);
|
||||||
|
|||||||
@@ -14,44 +14,60 @@ using NoisyCowStudios.Bin2Object;
|
|||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
{
|
{
|
||||||
public class Metadata : BinaryObjectReader
|
public class Metadata : BinaryObjectStream
|
||||||
{
|
{
|
||||||
public Il2CppGlobalMetadataHeader Header { get; set; }
|
public Il2CppGlobalMetadataHeader Header { get; set; }
|
||||||
|
|
||||||
public Il2CppAssemblyDefinition[] Assemblies { get; }
|
public Il2CppAssemblyDefinition[] Assemblies { get; set; }
|
||||||
public Il2CppImageDefinition[] Images { get; }
|
public Il2CppImageDefinition[] Images { get; set; }
|
||||||
public Il2CppTypeDefinition[] Types { get; }
|
public Il2CppTypeDefinition[] Types { get; set; }
|
||||||
public Il2CppMethodDefinition[] Methods { get; }
|
public Il2CppMethodDefinition[] Methods { get; set; }
|
||||||
public Il2CppParameterDefinition[] Params { get; }
|
public Il2CppParameterDefinition[] Params { get; set; }
|
||||||
public Il2CppFieldDefinition[] Fields { get; }
|
public Il2CppFieldDefinition[] Fields { get; set; }
|
||||||
public Il2CppFieldDefaultValue[] FieldDefaultValues { get; }
|
public Il2CppFieldDefaultValue[] FieldDefaultValues { get; set; }
|
||||||
public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; }
|
public Il2CppParameterDefaultValue[] ParameterDefaultValues { get; set; }
|
||||||
public Il2CppPropertyDefinition[] Properties { get; }
|
public Il2CppPropertyDefinition[] Properties { get; set; }
|
||||||
public Il2CppEventDefinition[] Events { get; }
|
public Il2CppEventDefinition[] Events { get; set; }
|
||||||
public Il2CppGenericContainer[] GenericContainers { get; }
|
public Il2CppGenericContainer[] GenericContainers { get; set; }
|
||||||
public Il2CppGenericParameter[] GenericParameters { get; }
|
public Il2CppGenericParameter[] GenericParameters { get; set; }
|
||||||
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; }
|
public Il2CppCustomAttributeTypeRange[] AttributeTypeRanges { get; set; }
|
||||||
public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; }
|
public Il2CppInterfaceOffsetPair[] InterfaceOffsets { get; set; }
|
||||||
public Il2CppMetadataUsageList[] MetadataUsageLists { get; }
|
public Il2CppMetadataUsageList[] MetadataUsageLists { get; set; }
|
||||||
public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; }
|
public Il2CppMetadataUsagePair[] MetadataUsagePairs { get; set; }
|
||||||
public Il2CppFieldRef[] FieldRefs { get; }
|
public Il2CppFieldRef[] FieldRefs { get; set; }
|
||||||
|
|
||||||
public int[] InterfaceUsageIndices { get; }
|
public int[] InterfaceUsageIndices { get; set; }
|
||||||
public int[] NestedTypeIndices { get; }
|
public int[] NestedTypeIndices { get; set; }
|
||||||
public int[] AttributeTypeIndices { get; }
|
public int[] AttributeTypeIndices { get; set; }
|
||||||
public int[] GenericConstraintIndices { get; }
|
public int[] GenericConstraintIndices { get; set; }
|
||||||
public uint[] VTableMethodIndices { get; }
|
public uint[] VTableMethodIndices { get; set; }
|
||||||
public string[] StringLiterals { get; }
|
public string[] StringLiterals { get; set; }
|
||||||
|
|
||||||
public Dictionary<int, string> Strings { get; } = new Dictionary<int, string>();
|
public Dictionary<int, string> Strings { get; } = new Dictionary<int, string>();
|
||||||
|
|
||||||
// Set if something in the metadata has been modified / decrypted
|
// Set if something in the metadata has been modified / decrypted
|
||||||
public bool IsModified { get; } = false;
|
public bool IsModified { get; private set; } = false;
|
||||||
|
|
||||||
public Metadata(MemoryStream stream, EventHandler<string> statusCallback = null) : base(stream)
|
// Status update callback
|
||||||
|
private EventHandler<string> OnStatusUpdate { get; set; }
|
||||||
|
private void StatusUpdate(string status) => OnStatusUpdate?.Invoke(this, status);
|
||||||
|
|
||||||
|
// Initialize metadata object from a stream
|
||||||
|
public static Metadata FromStream(MemoryStream stream, EventHandler<string> statusCallback = null) {
|
||||||
|
var metadata = new Metadata(statusCallback);
|
||||||
|
stream.Position = 0;
|
||||||
|
stream.CopyTo(metadata);
|
||||||
|
metadata.Position = 0;
|
||||||
|
metadata.Initialize();
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Metadata(EventHandler<string> statusCallback = null) : base() => OnStatusUpdate = statusCallback;
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
{
|
{
|
||||||
// Pre-processing hook
|
// Pre-processing hook
|
||||||
var pluginResult = PluginHooks.PreProcessMetadata(stream);
|
var pluginResult = PluginHooks.PreProcessMetadata(this);
|
||||||
IsModified = pluginResult.IsStreamModified;
|
IsModified = pluginResult.IsStreamModified;
|
||||||
|
|
||||||
// Read metadata header
|
// Read metadata header
|
||||||
@@ -185,7 +201,7 @@ namespace Il2CppInspector
|
|||||||
if (stringOffsets.Except(Strings.Keys).Any()) {
|
if (stringOffsets.Except(Strings.Keys).Any()) {
|
||||||
|
|
||||||
Console.WriteLine("Decrypting strings...");
|
Console.WriteLine("Decrypting strings...");
|
||||||
statusCallback?.Invoke(this, "Decrypting strings");
|
StatusUpdate("Decrypting strings");
|
||||||
|
|
||||||
// There may be zero-padding at the end of the last string since counts seem to be word-aligned
|
// There may be zero-padding at the end of the last string since counts seem to be word-aligned
|
||||||
// Find the true location one byte after the final character of the final string
|
// Find the true location one byte after the final character of the final string
|
||||||
@@ -209,13 +225,10 @@ namespace Il2CppInspector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write changes back in case the user wants to save the metadata file
|
// Write changes back in case the user wants to save the metadata file
|
||||||
using (var sw = new BinaryObjectWriter(BaseStream, Endianness, leaveOpen: true)) {
|
Position = Header.stringOffset;
|
||||||
sw.Version = Version;
|
|
||||||
sw.Position = Header.stringOffset;
|
|
||||||
foreach (var str in Strings.OrderBy(s => s.Key))
|
foreach (var str in Strings.OrderBy(s => s.Key))
|
||||||
sw.WriteNullTerminatedString(str.Value);
|
WriteNullTerminatedString(str.Value);
|
||||||
sw.Flush();
|
Flush();
|
||||||
}
|
|
||||||
|
|
||||||
IsModified = true;
|
IsModified = true;
|
||||||
}
|
}
|
||||||
@@ -235,7 +248,7 @@ namespace Il2CppInspector
|
|||||||
public void SaveToFile(string pathname) {
|
public void SaveToFile(string pathname) {
|
||||||
Position = 0;
|
Position = 0;
|
||||||
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
|
using (var outFile = new FileStream(pathname, FileMode.Create, FileAccess.Write))
|
||||||
BaseStream.CopyTo(outFile);
|
CopyTo(outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int Sizeof(Type type) => Sizeof(type, Version);
|
internal int Sizeof(Type type) => Sizeof(type, Version);
|
||||||
|
|||||||
@@ -801,17 +801,9 @@ namespace Il2CppInspector
|
|||||||
MetadataRegistration.methodReferences = 0;
|
MetadataRegistration.methodReferences = 0;
|
||||||
|
|
||||||
// Write changes to stream
|
// Write changes to stream
|
||||||
using var sw = new BinaryObjectWriter(Image.Stream.BaseStream, Image.Stream.Endianness, true);
|
|
||||||
sw.Version = Image.Version;
|
|
||||||
|
|
||||||
// Set width of long (convert to sizeof(int) for 32-bit files)
|
Image.WriteObject(Image.MapVATR(CodeRegistrationPointer), CodeRegistration);
|
||||||
if (Image.Bits == 32) {
|
Image.WriteObject(Image.MapVATR(MetadataRegistrationPointer), MetadataRegistration);
|
||||||
sw.PrimitiveMappings.Add(typeof(long), typeof(int));
|
|
||||||
sw.PrimitiveMappings.Add(typeof(ulong), typeof(uint));
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.WriteObject(Image.MapVATR(CodeRegistrationPointer), CodeRegistration);
|
|
||||||
sw.WriteObject(Image.MapVATR(MetadataRegistrationPointer), MetadataRegistration);
|
|
||||||
isModified = true;
|
isModified = true;
|
||||||
|
|
||||||
StatusUpdate("Analyzing IL2CPP image");
|
StatusUpdate("Analyzing IL2CPP image");
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace Il2CppInspector.Model
|
|||||||
public int WordSizeBytes => WordSizeBits / 8;
|
public int WordSizeBytes => WordSizeBits / 8;
|
||||||
|
|
||||||
// The binary image
|
// The binary image
|
||||||
public IFileFormatReader Image => Package.BinaryImage;
|
public IFileFormatStream Image => Package.BinaryImage;
|
||||||
|
|
||||||
// The IL2CPP package for this application
|
// The IL2CPP package for this application
|
||||||
public Il2CppInspector Package => TypeModel.Package;
|
public Il2CppInspector Package => TypeModel.Package;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace Il2CppInspector
|
|||||||
{
|
{
|
||||||
internal class ULEB128
|
internal class ULEB128
|
||||||
{
|
{
|
||||||
public static ulong Decode(IFileFormatReader next) {
|
public static ulong Decode(IFileFormatStream next) {
|
||||||
ulong uleb = 0;
|
ulong uleb = 0;
|
||||||
byte b = 0x80;
|
byte b = 0x80;
|
||||||
for (var shift = 0; b >> 7 == 1; shift += 7) {
|
for (var shift = 0; b >> 7 == 1; shift += 7) {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ namespace Il2CppInspectorGUI
|
|||||||
try {
|
try {
|
||||||
OnStatusUpdate?.Invoke(this, "Processing metadata");
|
OnStatusUpdate?.Invoke(this, "Processing metadata");
|
||||||
|
|
||||||
metadata = new Metadata(metadataStream, StatusUpdate);
|
metadata = Metadata.FromStream(metadataStream, StatusUpdate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
@@ -150,7 +150,7 @@ namespace Il2CppInspectorGUI
|
|||||||
OnStatusUpdate?.Invoke(this, "Processing binary");
|
OnStatusUpdate?.Invoke(this, "Processing binary");
|
||||||
|
|
||||||
// This may throw other exceptions from the individual loaders as well
|
// This may throw other exceptions from the individual loaders as well
|
||||||
IFileFormatReader stream = FileFormatReader.Load(binaryStream, LoadOptions, StatusUpdate);
|
IFileFormatStream stream = FileFormatStream.Load(binaryStream, LoadOptions, StatusUpdate);
|
||||||
if (stream == null) {
|
if (stream == null) {
|
||||||
throw new InvalidOperationException("Could not determine the binary file format");
|
throw new InvalidOperationException("Could not determine the binary file format");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user