Implement new GUI and CLI, fix misc. smaller issues (#22)
* Initial commit of new UI c# component * Initial commit of new UI frontend component * target WinExe to hide console window in release mode, move ui exe into resources * force single file publishing and add initial gh workflow for publishing ui * fix workflow errors * update dependencies and remove cxxdemangler, as it was outdated * fix c# single file output due to invalid output path * smaller tweaks, hack around loops in cpp type layouting * process other queued exports even if one fails and show error message * add basic support for processing LC_DYLD_CHAINED_FIXUPS * ELF loading should not use the file offset for loading the dynamic section * fix symbol table loading in some modified elfs * add "start export" button on format selection screen, clear all toasts after selecting an export format * embed ui executable directly into c# assembly * only build tauri component in c# release builds * add il2cpp file (binary, metadata) export to advanced tab * fix and enable binary ninja fake string segment support * add support for metadata * unify logic for getting element type index * fix new ui not allowing script exports other than ida * new ui: clear out loaded binary if no IL2CPP images could be loaded * fix toAddr calls in ghidra script target * remove dependency on a section being named .text in loaded pe files * tweak symbol reading a bit and remove sht relocation reading * add initial support for required forward references in il2cpp types, also fix issues with type names clashing with il2cpp api types * reduce clang errors for header file, fix better array size struct, emit required forward definitions in header * expose forward definitions in AppModel, fix issue with method-only used types not being emitted * remove debug log line * fix spelling mistakes in gui outputs * fix il2cpp_array_size_t not being an actual type for later method definitions * change the default port for new ui dev to 5000 * show current version and hash in new ui footer * seperate redux ui impl into FrontendCore project * make inspector version a server api, split up output subtypes and tweak some option names * add redux CLI based on redux GUI output formats * replace all Console.WriteLine calls in core inspector with AnsiConsole calls * add workflow for new cli and add back old gui workflow * disable aot publish and enable single file for redux cli
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -51,7 +52,7 @@ namespace Il2CppInspector
|
||||
|
||||
public override IFileFormatStream this[uint index] {
|
||||
get {
|
||||
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||
AnsiConsole.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||
IFileFormatStream loaded = null;
|
||||
|
||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -51,7 +52,7 @@ namespace Il2CppInspector
|
||||
|
||||
public override IFileFormatStream this[uint index] {
|
||||
get {
|
||||
Console.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||
AnsiConsole.WriteLine($"Extracting binary from {binaryFiles[index].FullName}");
|
||||
IFileFormatStream loaded = null;
|
||||
|
||||
// ZipArchiveEntry does not support seeking so we have to close and re-open for each possible load format
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -160,7 +161,7 @@ namespace Il2CppInspector
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Got exception {ex} while parsing SHT - reverting to PHT");
|
||||
AnsiConsole.WriteLine($"Got exception {ex} while parsing SHT - reverting to PHT");
|
||||
preferPHT = true;
|
||||
SHT = [];
|
||||
}
|
||||
@@ -170,12 +171,12 @@ namespace Il2CppInspector
|
||||
// These can happen as a result of conversions from other formats to ELF,
|
||||
// or if the SHT has been deliberately stripped
|
||||
if (!SHT.Any()) {
|
||||
Console.WriteLine("ELF binary has no SHT - reverting to PHT");
|
||||
AnsiConsole.WriteLine("ELF binary has no SHT - reverting to PHT");
|
||||
preferPHT = true;
|
||||
}
|
||||
|
||||
else if (SHT.All(s => conv.ULong(s.sh_addr) == 0ul)) {
|
||||
Console.WriteLine("ELF binary SHT is all-zero - reverting to PHT");
|
||||
AnsiConsole.WriteLine("ELF binary SHT is all-zero - reverting to PHT");
|
||||
preferPHT = true;
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ namespace Il2CppInspector
|
||||
|
||||
// If the first file offset of the first PHT is zero, assume a dumped image
|
||||
if (PHT.Any(t => conv.ULong(t.p_vaddr) == 0ul)) {
|
||||
Console.WriteLine("ELF binary appears to be a dumped memory image");
|
||||
AnsiConsole.WriteLine("ELF binary appears to be a dumped memory image");
|
||||
isMemoryImage = true;
|
||||
}
|
||||
preferPHT = true;
|
||||
@@ -202,7 +203,7 @@ namespace Il2CppInspector
|
||||
else {
|
||||
var shtOverlap = shtShouldBeOrdered.Aggregate((x, y) => x <= y? y : ulong.MaxValue) == ulong.MaxValue;
|
||||
if (shtOverlap) {
|
||||
Console.WriteLine("ELF binary SHT contains invalid ranges - reverting to PHT");
|
||||
AnsiConsole.WriteLine("ELF binary SHT contains invalid ranges - reverting to PHT");
|
||||
preferPHT = true;
|
||||
}
|
||||
}
|
||||
@@ -223,7 +224,20 @@ namespace Il2CppInspector
|
||||
|
||||
// Get dynamic table if it exists (must be done after rebasing)
|
||||
if (GetProgramHeader(Elf.PT_DYNAMIC) is TPHdr PT_DYNAMIC)
|
||||
DynamicTable = ReadArray<elf_dynamic<TWord>>(conv.Long(PT_DYNAMIC.p_offset), (int) (conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic<TWord>))));
|
||||
{
|
||||
// Important: do not use p_offset here!
|
||||
// Only load sections should be loaded, which should also include the memory region that contains the dynamic section.
|
||||
// This just provides the virtual address of the section.
|
||||
// Some binaries may use the offset here to point to a fake version of the dynamic section,
|
||||
// making relocation resolution and subsequent analysis fail.
|
||||
// Reference for Android:
|
||||
// phdr_table_get_dynamic_section, https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker_phdr.cpp
|
||||
|
||||
var dynamicAddr = conv.ULong(PT_DYNAMIC.p_vaddr);
|
||||
var dynamicSize = (int)(conv.Long(PT_DYNAMIC.p_filesz) / Sizeof(typeof(elf_dynamic<TWord>)));
|
||||
|
||||
DynamicTable = ReadMappedArray<elf_dynamic<TWord>>(dynamicAddr, dynamicSize);
|
||||
}
|
||||
|
||||
// Get offset of code section
|
||||
var codeSegment = PHT.First(x => ((Elf) x.p_flags & Elf.PF_X) == Elf.PF_X);
|
||||
@@ -254,21 +268,6 @@ namespace Il2CppInspector
|
||||
|
||||
StatusUpdate("Finding relocations");
|
||||
|
||||
// Two types: add value from offset in image, and add value from specified addend
|
||||
foreach (var relSection in GetSections(Elf.SHT_REL)) {
|
||||
reverseMapExclusions.Add(((uint) conv.Int(relSection.sh_offset), (uint) (conv.Int(relSection.sh_offset) + conv.Int(relSection.sh_size) - 1)));
|
||||
rels.UnionWith(
|
||||
from rel in ReadArray<elf_rel<TWord>>(conv.Long(relSection.sh_offset), conv.Int(conv.Div(relSection.sh_size, relSection.sh_entsize)))
|
||||
select new ElfReloc(rel, SHT[relSection.sh_link].sh_offset));
|
||||
}
|
||||
|
||||
foreach (var relaSection in GetSections(Elf.SHT_RELA)) {
|
||||
reverseMapExclusions.Add(((uint) conv.Int(relaSection.sh_offset), (uint) (conv.Int(relaSection.sh_offset) + conv.Int(relaSection.sh_size) - 1)));
|
||||
rels.UnionWith(
|
||||
from rela in ReadArray<elf_rela<TWord>>(conv.Long(relaSection.sh_offset), conv.Int(conv.Div(relaSection.sh_size, relaSection.sh_entsize)))
|
||||
select new ElfReloc(rela, SHT[relaSection.sh_link].sh_offset));
|
||||
}
|
||||
|
||||
// Relocations in dynamic section
|
||||
if (GetDynamicEntry(Elf.DT_REL) is elf_dynamic<TWord> dt_rel) {
|
||||
var dt_rel_count = conv.Int(conv.Div(GetDynamicEntry(Elf.DT_RELSZ).d_un, GetDynamicEntry(Elf.DT_RELENT).d_un));
|
||||
@@ -291,7 +290,7 @@ namespace Il2CppInspector
|
||||
}
|
||||
|
||||
// Process relocations
|
||||
var relsz = Sizeof(typeof(TSym));
|
||||
var relsz = (uint)Sizeof(typeof(TSym));
|
||||
|
||||
var currentRel = 0;
|
||||
var totalRel = rels.Count();
|
||||
@@ -301,7 +300,26 @@ namespace Il2CppInspector
|
||||
if (currentRel % 1000 == 0)
|
||||
StatusUpdate($"Processing relocations ({currentRel * 100 / totalRel:F0}%)");
|
||||
|
||||
var symValue = ReadObject<TSym>(conv.Long(rel.SymbolTable) + conv.Long(rel.SymbolIndex) * relsz).st_value; // S
|
||||
TWord symValue;
|
||||
|
||||
try
|
||||
{
|
||||
// man this really needs a full overhaul
|
||||
symValue = ReadMappedObject<TSym>(conv.ULong(rel.SymbolTable) + conv.ULong(rel.SymbolIndex) * relsz)
|
||||
.st_value; // S
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
try
|
||||
{
|
||||
symValue = ReadObject<TSym>(conv.Long(rel.SymbolTable) + conv.Long(rel.SymbolIndex) * relsz)
|
||||
.st_value; // S
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore relocations into memory addresses not mapped from the image
|
||||
try {
|
||||
@@ -344,7 +362,7 @@ namespace Il2CppInspector
|
||||
WriteWord(result.newValue);
|
||||
}
|
||||
}
|
||||
Console.WriteLine($"Processed {rels.Count} relocations");
|
||||
AnsiConsole.WriteLine($"Processed {rels.Count} relocations");
|
||||
|
||||
// Build symbol and export tables
|
||||
processSymbols();
|
||||
@@ -388,7 +406,8 @@ namespace Il2CppInspector
|
||||
WriteArray(conv.Long(PT_DYNAMIC.p_offset), dt);
|
||||
}
|
||||
|
||||
private void processSymbols() {
|
||||
private void processSymbols()
|
||||
{
|
||||
StatusUpdate("Processing symbols");
|
||||
|
||||
// Three possible symbol tables in ELF files
|
||||
@@ -436,7 +455,15 @@ namespace Il2CppInspector
|
||||
symbolTable.Clear();
|
||||
var exportTable = new Dictionary<string, Export>();
|
||||
|
||||
foreach (var pTab in pTables) {
|
||||
var alreadyProcessed = new List<(TWord offset, TWord count)>();
|
||||
|
||||
foreach (var pTab in pTables)
|
||||
{
|
||||
if (alreadyProcessed.Any(x =>
|
||||
conv.ULong(x.offset) == conv.ULong(pTab.offset)))
|
||||
continue;
|
||||
|
||||
alreadyProcessed.Add((pTab.offset, pTab.count));
|
||||
var symbol_table = ReadArray<TSym>(conv.Long(pTab.offset), conv.Int(pTab.count));
|
||||
|
||||
foreach (var symbol in symbol_table)
|
||||
@@ -463,7 +490,7 @@ namespace Il2CppInspector
|
||||
var symbolItem = new Symbol {Name = name, Type = type, VirtualAddress = conv.ULong(symbol.st_value) };
|
||||
symbolTable.TryAdd(name, symbolItem);
|
||||
if (symbol.st_shndx != (ushort) Elf.SHN_UNDEF)
|
||||
exportTable.TryAdd(name, new Export {Name = symbolItem.DemangledName, VirtualAddress = conv.ULong(symbol.st_value)});
|
||||
exportTable.TryAdd(name, new Export {Name = symbolItem.Name, VirtualAddress = conv.ULong(symbol.st_value)});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace Il2CppInspector
|
||||
try {
|
||||
if (type.GetMethod("Load", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public,
|
||||
null, new[] { typeof(BinaryObjectStream), typeof(LoadOptions), typeof(EventHandler<string>) }, null)
|
||||
.Invoke(null, new object[] { binaryObjectStream, loadOptions, statusCallback }) is IFileFormatStream loaded) {
|
||||
.Invoke(null, [binaryObjectStream, loadOptions, statusCallback]) is IFileFormatStream loaded) {
|
||||
|
||||
loaded.IsModified |= preProcessResult.IsStreamModified;
|
||||
return loaded;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
using System;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
using VersionedSerialization.Attributes;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
@@ -31,6 +32,7 @@ namespace Il2CppInspector
|
||||
LC_DYLD_INFO_ONLY = 0x80000022,
|
||||
LC_FUNCTION_STARTS = 0x26,
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C,
|
||||
LC_DYLD_CHAINED_FIXUPS = 0x80000034,
|
||||
|
||||
CPU_TYPE_X86 = 7,
|
||||
CPU_TYPE_X86_64 = 0x01000000 + CPU_TYPE_X86,
|
||||
@@ -172,4 +174,47 @@ namespace Il2CppInspector
|
||||
public bool r_extern => ((r_data >> 27) & 1) == 1;
|
||||
public uint r_type => r_data >> 28;
|
||||
}
|
||||
|
||||
[VersionedStruct]
|
||||
public partial struct MachODyldChainedFixupsHeader
|
||||
{
|
||||
public uint FixupsVersion;
|
||||
public uint StartsOffset;
|
||||
public uint ImportsOffset;
|
||||
public uint SymbolsOffset;
|
||||
public uint ImportsCount;
|
||||
public uint ImportsFormat;
|
||||
public uint SymbolsFormat;
|
||||
}
|
||||
|
||||
[VersionedStruct]
|
||||
public partial struct MachODyldChainedStartsInSegment
|
||||
{
|
||||
public const ushort DYLD_CHAINED_PTR_START_NONE = 0xffff;
|
||||
|
||||
public uint StructSize;
|
||||
public ushort PageSize;
|
||||
public ushort PointerFormat;
|
||||
public ulong SegmentOffset;
|
||||
public uint MaxValidPointer;
|
||||
public ushort PageCount;
|
||||
}
|
||||
|
||||
public enum MachODyldChainedPtr
|
||||
{
|
||||
DYLD_CHAINED_PTR_64 = 2,
|
||||
DYLD_CHAINED_PTR_64_OFFSET = 6,
|
||||
}
|
||||
|
||||
[VersionedStruct]
|
||||
public partial struct MachODyldChainedPtr64Rebase
|
||||
{
|
||||
private ulong _value;
|
||||
|
||||
public ulong Target => _value & 0xfffffffff;
|
||||
public ulong High8 => (_value >> 36) & 0xff;
|
||||
public ulong Reserved => (_value >> (36 + 8)) & 0x7f;
|
||||
public ulong Next => (_value >> (36 + 8 + 7)) & 0xfff;
|
||||
public bool Bind => ((_value >> (36 + 8 + 7 + 12)) & 0x1) == 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
@@ -172,15 +173,21 @@ namespace Il2CppInspector
|
||||
if (encryptionInfo.CryptID != 0)
|
||||
throw new NotImplementedException("This Mach-O executable is encrypted with FairPlay DRM and cannot be processed. Please provide a decrypted version of the executable.");
|
||||
break;
|
||||
|
||||
case MachO.LC_DYLD_CHAINED_FIXUPS:
|
||||
var chainedFixupsInfo = ReadObject<MachOLinkEditDataCommand>();
|
||||
ApplyChainedFixups(chainedFixupsInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
// There might be other data after the load command so always use the specified total size to step forwards
|
||||
Position = startPos + loadCommand.Size;
|
||||
}
|
||||
|
||||
// Note: Some binaries do not have __mod_init_func, but instead just __init_offset with offsets to the init functions. This check is disabled.
|
||||
// Must find __mod_init_func
|
||||
if (funcTab == null)
|
||||
return false;
|
||||
//if (funcTab == null)
|
||||
// return false;
|
||||
|
||||
// Process relocations
|
||||
foreach (var section in machoSections) {
|
||||
@@ -188,7 +195,7 @@ namespace Il2CppInspector
|
||||
|
||||
// TODO: Implement Mach-O relocations
|
||||
if (rels.Any()) {
|
||||
Console.WriteLine("Mach-O file contains relocations (feature not yet implemented)");
|
||||
AnsiConsole.WriteLine("Mach-O file contains relocations (feature not yet implemented)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -282,7 +289,7 @@ namespace Il2CppInspector
|
||||
: SymbolType.Unknown;
|
||||
|
||||
if (type == SymbolType.Unknown) {
|
||||
Console.WriteLine($"Unknown symbol type: {((int) ntype):x2} {value:x16} " + CxxDemangler.CxxDemangler.Demangle(name));
|
||||
AnsiConsole.WriteLine($"Unknown symbol type: {((int) ntype):x2} {value:x16} {name}");
|
||||
}
|
||||
|
||||
// Ignore duplicates
|
||||
@@ -290,7 +297,82 @@ namespace Il2CppInspector
|
||||
}
|
||||
}
|
||||
|
||||
public override uint[] GetFunctionTable() => ReadArray<TWord>(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray();
|
||||
private void ApplyChainedFixups(in MachOLinkEditDataCommand info)
|
||||
{
|
||||
var chainedFixupsHeader = ReadVersionedObject<MachODyldChainedFixupsHeader>(info.Offset);
|
||||
if (chainedFixupsHeader.FixupsVersion != 0)
|
||||
{
|
||||
AnsiConsole.WriteLine($"Unsupported chained fixups version: {chainedFixupsHeader.FixupsVersion}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (chainedFixupsHeader.ImportsFormat != 1 /* DYLD_CHAINED_IMPORT */)
|
||||
{
|
||||
AnsiConsole.WriteLine($"Unsupported chained fixups import format: {chainedFixupsHeader.ImportsFormat}");
|
||||
return;
|
||||
}
|
||||
|
||||
//var importsBase = info.Offset + chainedFixupsHeader.ImportsOffset;
|
||||
//var imports = ReadPrimitiveArray<uint>(importsBase,
|
||||
// chainedFixupsHeader.ImportsCount);
|
||||
|
||||
//var symbolsBase = info.Offset + chainedFixupsHeader.SymbolsOffset; // todo: apparently this supports zlib
|
||||
|
||||
var startsBase = info.Offset + chainedFixupsHeader.StartsOffset;
|
||||
var segmentCount = ReadPrimitive<uint>(startsBase);
|
||||
var segmentStartOffsets = ReadPrimitiveArray<uint>(startsBase + 4, segmentCount);
|
||||
|
||||
foreach (var startOffset in segmentStartOffsets)
|
||||
{
|
||||
if (startOffset == 0)
|
||||
continue;
|
||||
|
||||
var startsInfo = ReadVersionedObject<MachODyldChainedStartsInSegment>(startsBase + startOffset);
|
||||
if (startsInfo.SegmentOffset == 0)
|
||||
continue;
|
||||
|
||||
var pointerFormat = (MachODyldChainedPtr)startsInfo.PointerFormat;
|
||||
|
||||
var pages = ReadPrimitiveArray<ushort>(
|
||||
startsBase + startOffset + MachODyldChainedStartsInSegment.Size(), startsInfo.PageCount);
|
||||
|
||||
for (var i = 0; i < pages.Length; i++)
|
||||
{
|
||||
var page = pages[i];
|
||||
if (page == MachODyldChainedStartsInSegment.DYLD_CHAINED_PTR_START_NONE)
|
||||
continue;
|
||||
|
||||
var chainOffset = startsInfo.SegmentOffset + (ulong)(i * startsInfo.PageSize) + page;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var currentEntry = ReadVersionedObject<MachODyldChainedPtr64Rebase>((long)chainOffset);
|
||||
|
||||
var fixedValue = 0ul;
|
||||
|
||||
if (!currentEntry.Bind) // todo: bind
|
||||
{
|
||||
fixedValue = pointerFormat switch
|
||||
{
|
||||
MachODyldChainedPtr.DYLD_CHAINED_PTR_64
|
||||
or MachODyldChainedPtr.DYLD_CHAINED_PTR_64_OFFSET
|
||||
=> currentEntry.High8 << 56 | currentEntry.Target,
|
||||
_ => fixedValue
|
||||
};
|
||||
|
||||
Write((long)chainOffset, fixedValue);
|
||||
}
|
||||
|
||||
if (currentEntry.Next == 0)
|
||||
break;
|
||||
|
||||
chainOffset += currentEntry.Next * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override uint[] GetFunctionTable() => funcTab == null ? [] : ReadArray<TWord>(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray();
|
||||
|
||||
public override Dictionary<string, Symbol> GetSymbolTable() => symbolTable;
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
@@ -102,7 +103,7 @@ namespace Il2CppInspector
|
||||
// Unpacking must be done starting here, one byte after the end of the headers
|
||||
// Packed or previously packed with Themida? This is purely for information
|
||||
if (sections.FirstOrDefault(x => x.Name == ".themida") is PESection _)
|
||||
Console.WriteLine("Themida protection detected");
|
||||
AnsiConsole.WriteLine("Themida protection detected");
|
||||
|
||||
// Packed with anything (including Themida)?
|
||||
mightBePacked = sections.FirstOrDefault(x => x.Name == ".rdata") is null;
|
||||
@@ -114,26 +115,31 @@ namespace Il2CppInspector
|
||||
section.Name = wantedSectionTypes[section.Characteristics];
|
||||
|
||||
// Get base of code
|
||||
GlobalOffset = pe.ImageBase + pe.BaseOfCode - sections.First(x => x.Name == ".text").PointerToRawData;
|
||||
GlobalOffset = pe.ImageBase + pe.BaseOfCode - sections
|
||||
.FirstOrDefault(x => x.Characteristics.HasFlag(PE.IMAGE_SCN_MEM_EXECUTE))?.PointerToRawData ?? 0;
|
||||
|
||||
// Confirm that .rdata section begins at same place as IAT
|
||||
var rData = sections.First(x => x.Name == ".rdata");
|
||||
mightBePacked |= rData.VirtualAddress != IATStart;
|
||||
var rData = sections.FirstOrDefault(x => x.Name == ".rdata");
|
||||
mightBePacked |= rData == null || rData.VirtualAddress != IATStart;
|
||||
if (rData != null)
|
||||
{
|
||||
// Calculate start of function pointer table
|
||||
pFuncTable = rData.PointerToRawData + IATSize;
|
||||
|
||||
// Calculate start of function pointer table
|
||||
pFuncTable = rData.PointerToRawData + IATSize;
|
||||
|
||||
// Skip over __guard_check_icall_fptr and __guard_dispatch_icall_fptr if present, then the following zero offset
|
||||
Position = pFuncTable;
|
||||
if (pe is PEOptHeader32) {
|
||||
while (ReadUInt32() != 0)
|
||||
// Skip over __guard_check_icall_fptr and __guard_dispatch_icall_fptr if present, then the following zero offset
|
||||
Position = pFuncTable;
|
||||
if (pe is PEOptHeader32)
|
||||
{
|
||||
while (ReadUInt32() != 0)
|
||||
pFuncTable += 4;
|
||||
pFuncTable += 4;
|
||||
pFuncTable += 4;
|
||||
}
|
||||
else {
|
||||
while (ReadUInt64() != 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ReadUInt64() != 0)
|
||||
pFuncTable += 8;
|
||||
pFuncTable += 8;
|
||||
pFuncTable += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// In the fist go round, we signal that this is at least a valid PE file; we don't try to unpack yet
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
using Spectre.Console;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NoisyCowStudios.Bin2Object;
|
||||
|
||||
namespace Il2CppInspector
|
||||
{
|
||||
@@ -100,7 +101,7 @@ namespace Il2CppInspector
|
||||
// Get the entire remaining chunk, or to the end of the file if it doesn't contain the end of the chunk
|
||||
var length = (uint) Math.Min(chunk.Memory.End - memoryNext, source.Length);
|
||||
|
||||
Console.WriteLine($"Writing {length:x8} bytes from {Path.GetFileName(file.Name)} +{fileStart:x8} ({memoryNext:x8}) to target {il2cpp.Position:x8}");
|
||||
AnsiConsole.WriteLine($"Writing {length:x8} bytes from {Path.GetFileName(file.Name)} +{fileStart:x8} ({memoryNext:x8}) to target {il2cpp.Position:x8}");
|
||||
|
||||
// Can't use Stream.CopyTo as it doesn't support length parameter
|
||||
var buffer = new byte[length];
|
||||
|
||||
@@ -20,7 +20,5 @@ namespace Il2CppInspector
|
||||
public ulong VirtualAddress { get; set; }
|
||||
public string Name { get; set; }
|
||||
public SymbolType Type { get; set; }
|
||||
|
||||
public string DemangledName => CxxDemangler.CxxDemangler.Demangle(Name);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user