Unify symbol table format and implement for Elf and Mach-O
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -131,7 +132,7 @@ namespace Il2CppInspector
|
|||||||
private TPHdr getProgramHeader(Elf programIndex) => program_header_table.FirstOrDefault(x => x.p_type == (uint) programIndex);
|
private TPHdr getProgramHeader(Elf programIndex) => program_header_table.FirstOrDefault(x => x.p_type == (uint) programIndex);
|
||||||
private elf_dynamic<TWord> getDynamic(Elf dynamicIndex) => dynamic_table?.FirstOrDefault(x => (Elf) conv.ULong(x.d_tag) == dynamicIndex);
|
private elf_dynamic<TWord> getDynamic(Elf dynamicIndex) => dynamic_table?.FirstOrDefault(x => (Elf) conv.ULong(x.d_tag) == dynamicIndex);
|
||||||
|
|
||||||
private Dictionary<string, ulong> symbolTable = new Dictionary<string, ulong>();
|
private Dictionary<string, Symbol> symbolTable = new Dictionary<string, Symbol>();
|
||||||
private List<Export> exports = new List<Export>();
|
private List<Export> exports = new List<Export>();
|
||||||
|
|
||||||
protected abstract Elf ArchClass { get; }
|
protected abstract Elf ArchClass { get; }
|
||||||
@@ -318,7 +319,7 @@ namespace Il2CppInspector
|
|||||||
xorRange(conv.Int(section.sh_offset), conv.Int(section.sh_size), xorValue);
|
xorRange(conv.Int(section.sh_offset), conv.Int(section.sh_size), xorValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Dictionary<string, ulong> GetSymbolTable() => symbolTable;
|
public override Dictionary<string, Symbol> GetSymbolTable() => symbolTable;
|
||||||
public override IEnumerable<Export> GetExports() => exports;
|
public override IEnumerable<Export> GetExports() => exports;
|
||||||
|
|
||||||
private void processSymbols() {
|
private void processSymbols() {
|
||||||
@@ -366,10 +367,18 @@ namespace Il2CppInspector
|
|||||||
foreach (var symbol in symbol_table) {
|
foreach (var symbol in symbol_table) {
|
||||||
var name = ReadNullTerminatedString(conv.Long(pTab.strings) + symbol.st_name);
|
var name = ReadNullTerminatedString(conv.Long(pTab.strings) + symbol.st_name);
|
||||||
|
|
||||||
|
var type = symbol.type == Elf.STT_FUNC? SymbolType.Function
|
||||||
|
: symbol.type == Elf.STT_OBJECT || symbol.type == Elf.STT_COMMON? SymbolType.Name
|
||||||
|
: SymbolType.Unknown;
|
||||||
|
|
||||||
|
if (symbol.st_shndx == (ushort) Elf.SHN_UNDEF)
|
||||||
|
type = SymbolType.Import;
|
||||||
|
|
||||||
// Avoid duplicates
|
// Avoid duplicates
|
||||||
symbolTable.TryAdd(name, conv.ULong(symbol.st_value));
|
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)
|
if (symbol.st_shndx != (ushort) Elf.SHN_UNDEF)
|
||||||
exportTable.TryAdd(name, new Export {Name = name, VirtualAddress = conv.ULong(symbol.st_value)});
|
exportTable.TryAdd(name, new Export {Name = symbolItem.DemangledName, VirtualAddress = conv.ULong(symbol.st_value)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Il2CppInspector
|
|||||||
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)
|
||||||
Dictionary<string, ulong> GetSymbolTable();
|
Dictionary<string, Symbol> GetSymbolTable();
|
||||||
uint[] GetFunctionTable();
|
uint[] GetFunctionTable();
|
||||||
IEnumerable<Export> GetExports();
|
IEnumerable<Export> GetExports();
|
||||||
U ReadMappedObject<U>(ulong uiAddr) where U : new();
|
U ReadMappedObject<U>(ulong uiAddr) where U : new();
|
||||||
@@ -140,7 +140,7 @@ namespace Il2CppInspector
|
|||||||
public virtual IFileFormatReader this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds");
|
public virtual IFileFormatReader this[uint index] => (index == 0)? this : throw new IndexOutOfRangeException("Binary image index out of bounds");
|
||||||
|
|
||||||
// Find search locations in the symbol table for Il2Cpp data
|
// Find search locations in the symbol table for Il2Cpp data
|
||||||
public virtual Dictionary<string, ulong> GetSymbolTable() => null;
|
public virtual Dictionary<string, Symbol> GetSymbolTable() => new Dictionary<string, Symbol>();
|
||||||
|
|
||||||
// Find search locations in the machine code for Il2Cpp data
|
// Find search locations in the machine code for Il2Cpp data
|
||||||
public virtual uint[] GetFunctionTable() => throw new NotImplementedException();
|
public virtual uint[] GetFunctionTable() => throw new NotImplementedException();
|
||||||
|
|||||||
@@ -46,6 +46,19 @@ namespace Il2CppInspector
|
|||||||
// SHNs
|
// SHNs
|
||||||
SHN_UNDEF = 0,
|
SHN_UNDEF = 0,
|
||||||
|
|
||||||
|
// STTs
|
||||||
|
STT_NOTYPE = 0,
|
||||||
|
STT_OBJECT = 1,
|
||||||
|
STT_FUNC = 2,
|
||||||
|
STT_SECTION = 3,
|
||||||
|
STT_FILE = 4,
|
||||||
|
STT_COMMON = 5,
|
||||||
|
STT_LOOS = 10,
|
||||||
|
STT_HIOS = 12,
|
||||||
|
STT_LOPROC = 13,
|
||||||
|
STT_SPARC_REGISTER = 13,
|
||||||
|
STT_HIPROC = 15,
|
||||||
|
|
||||||
// dynamic sections
|
// dynamic sections
|
||||||
DT_STRTAB = 5,
|
DT_STRTAB = 5,
|
||||||
DT_SYMTAB = 6,
|
DT_SYMTAB = 6,
|
||||||
@@ -192,6 +205,8 @@ namespace Il2CppInspector
|
|||||||
uint st_name { get; }
|
uint st_name { get; }
|
||||||
TWord st_value { get; }
|
TWord st_value { get; }
|
||||||
ushort st_shndx { get; }
|
ushort st_shndx { get; }
|
||||||
|
Elf st_info { get; }
|
||||||
|
Elf type { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class elf_32_sym : Ielf_sym<uint>
|
internal class elf_32_sym : Ielf_sym<uint>
|
||||||
@@ -199,11 +214,13 @@ namespace Il2CppInspector
|
|||||||
public uint st_name => f_st_name;
|
public uint st_name => f_st_name;
|
||||||
public uint st_value => f_st_value;
|
public uint st_value => f_st_value;
|
||||||
public ushort st_shndx => f_st_shndx;
|
public ushort st_shndx => f_st_shndx;
|
||||||
|
public Elf st_info => (Elf) f_st_info;
|
||||||
|
public Elf type => (Elf) (f_st_info & 0xf);
|
||||||
|
|
||||||
public uint f_st_name;
|
public uint f_st_name;
|
||||||
public uint f_st_value;
|
public uint f_st_value;
|
||||||
public uint st_size;
|
public uint st_size;
|
||||||
public byte st_info;
|
public byte f_st_info;
|
||||||
public byte st_other;
|
public byte st_other;
|
||||||
public ushort f_st_shndx;
|
public ushort f_st_shndx;
|
||||||
}
|
}
|
||||||
@@ -213,9 +230,11 @@ namespace Il2CppInspector
|
|||||||
public uint st_name => f_st_name;
|
public uint st_name => f_st_name;
|
||||||
public ulong st_value => f_st_value;
|
public ulong st_value => f_st_value;
|
||||||
public ushort st_shndx => f_st_shndx;
|
public ushort st_shndx => f_st_shndx;
|
||||||
|
public Elf st_info => (Elf) f_st_info;
|
||||||
|
public Elf type => (Elf) (f_st_info & 0xf);
|
||||||
|
|
||||||
public uint f_st_name;
|
public uint f_st_name;
|
||||||
public byte st_info;
|
public byte f_st_info;
|
||||||
public byte st_other;
|
public byte st_other;
|
||||||
public ushort f_st_shndx;
|
public ushort f_st_shndx;
|
||||||
public ulong f_st_value;
|
public ulong f_st_value;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
|
|
||||||
namespace Il2CppInspector
|
namespace Il2CppInspector
|
||||||
@@ -33,7 +34,34 @@ namespace Il2CppInspector
|
|||||||
CPU_TYPE_X86 = 7,
|
CPU_TYPE_X86 = 7,
|
||||||
CPU_TYPE_X86_64 = 0x01000000 + CPU_TYPE_X86,
|
CPU_TYPE_X86_64 = 0x01000000 + CPU_TYPE_X86,
|
||||||
CPU_TYPE_ARM = 12,
|
CPU_TYPE_ARM = 12,
|
||||||
CPU_TYPE_ARM64 = 0x01000000 + CPU_TYPE_ARM
|
CPU_TYPE_ARM64 = 0x01000000 + CPU_TYPE_ARM,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum MachO_NType : byte
|
||||||
|
{
|
||||||
|
// n_type masks
|
||||||
|
N_STAB = 0xe0,
|
||||||
|
N_PEXT = 0x10,
|
||||||
|
N_TYPE = 0x0e,
|
||||||
|
N_EXT = 0x01,
|
||||||
|
|
||||||
|
// n_stab bits
|
||||||
|
N_UNDF = 0x00,
|
||||||
|
N_ABS = 0x02,
|
||||||
|
N_SECT = 0x0e,
|
||||||
|
N_PBUD = 0x0c,
|
||||||
|
N_INDR = 0x0a,
|
||||||
|
|
||||||
|
// n_type bits when N_STAB has some bits set
|
||||||
|
N_GSYM = 0x20,
|
||||||
|
N_FNAME = 0x22,
|
||||||
|
N_FUN = 0x24,
|
||||||
|
N_STSYM = 0x26,
|
||||||
|
N_BNSYM = 0x2E,
|
||||||
|
N_ENSYM = 0x4E,
|
||||||
|
N_SO = 0x64,
|
||||||
|
N_OSO = 0x66,
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MachOHeader<TWord> where TWord : struct
|
internal class MachOHeader<TWord> where TWord : struct
|
||||||
@@ -124,8 +152,9 @@ namespace Il2CppInspector
|
|||||||
|
|
||||||
internal class MachO_nlist<TWord> where TWord : struct
|
internal class MachO_nlist<TWord> where TWord : struct
|
||||||
{
|
{
|
||||||
|
public MachO_NType n_type => (MachO_NType) f_n_type;
|
||||||
public uint n_strx;
|
public uint n_strx;
|
||||||
public byte n_type;
|
public byte f_n_type;
|
||||||
public byte n_sect;
|
public byte n_sect;
|
||||||
public ushort n_desc;
|
public ushort n_desc;
|
||||||
public TWord n_value;
|
public TWord n_value;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NoisyCowStudios.Bin2Object;
|
using NoisyCowStudios.Bin2Object;
|
||||||
@@ -228,8 +229,8 @@ 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();
|
public override uint[] GetFunctionTable() => ReadArray<TWord>(funcTab.ImageOffset, conv.Int(funcTab.Size) / (Bits / 8)).Select(x => MapVATR(conv.ULong(x)) & 0xffff_fffe).ToArray();
|
||||||
|
|
||||||
public override Dictionary<string, ulong> GetSymbolTable() {
|
public override Dictionary<string, Symbol> GetSymbolTable() {
|
||||||
var symbols = new Dictionary<string, ulong>();
|
var symbols = new Dictionary<string, Symbol>();
|
||||||
|
|
||||||
// https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/nlist.h
|
// https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/nlist.h
|
||||||
// n_sect: https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/stab.h
|
// n_sect: https://opensource.apple.com/source/cctools/cctools-795/include/mach-o/stab.h
|
||||||
@@ -243,11 +244,33 @@ namespace Il2CppInspector
|
|||||||
var name = (symbol.n_strx != 0) ? ReadNullTerminatedString() : "";
|
var name = (symbol.n_strx != 0) ? ReadNullTerminatedString() : "";
|
||||||
var value = (ulong) Convert.ChangeType(symbol.n_value, typeof(ulong));
|
var value = (ulong) Convert.ChangeType(symbol.n_value, typeof(ulong));
|
||||||
|
|
||||||
// Ignore duplicates for now, also ignore symbols with no address
|
// Ignore symbols with no address or name
|
||||||
if (value != 0)
|
if (value == 0 || name.Length == 0)
|
||||||
symbols.TryAdd(name, value);
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
|
// Mask out the N_EXT and N_PEXT bits because we don't care about it
|
||||||
|
var ntype = (MachO_NType) ((byte)symbol.n_type & ~(byte)MachO_NType.N_EXT & ~(byte)MachO_NType.N_PEXT);
|
||||||
|
|
||||||
|
// For non-debugging symbols (no bits of N_STAB set), just leave the N_TYPE
|
||||||
|
// Otherwise leave the whole n_type field (with N_EXT and N_PEXT removed)
|
||||||
|
var dbg = (symbol.n_type & MachO_NType.N_STAB) != 0;
|
||||||
|
|
||||||
|
if (dbg)
|
||||||
|
if (ntype == MachO_NType.N_BNSYM || ntype == MachO_NType.N_ENSYM
|
||||||
|
|| ntype == MachO_NType.N_SO || ntype == MachO_NType.N_OSO)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var type = ntype == MachO_NType.N_FUN? SymbolType.Function
|
||||||
|
: ntype == MachO_NType.N_STSYM || ntype == MachO_NType.N_GSYM || ntype == MachO_NType.N_SECT? SymbolType.Name
|
||||||
|
: SymbolType.Unknown;
|
||||||
|
|
||||||
|
if (type == SymbolType.Unknown) {
|
||||||
|
Console.WriteLine($"Unknown symbol type: {((int) ntype):x2} {value:x16} " + CxxDemangler.CxxDemangler.Demangle(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore duplicates
|
||||||
|
symbols.TryAdd(name, new Symbol { Name = name, VirtualAddress = value, Type = type });
|
||||||
|
}
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
Il2CppInspector.Common/FileFormatReaders/Symbol.cs
Normal file
26
Il2CppInspector.Common/FileFormatReaders/Symbol.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Il2CppInspector
|
||||||
|
{
|
||||||
|
public enum SymbolType
|
||||||
|
{
|
||||||
|
Function,
|
||||||
|
Name,
|
||||||
|
Import,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// A code file function export
|
||||||
|
public class Symbol
|
||||||
|
{
|
||||||
|
public ulong VirtualAddress { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public SymbolType Type { get; set; }
|
||||||
|
|
||||||
|
public string DemangledName => CxxDemangler.CxxDemangler.Demangle(Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -148,20 +148,20 @@ namespace Il2CppInspector
|
|||||||
// Try searching the symbol table
|
// Try searching the symbol table
|
||||||
var symbols = Image.GetSymbolTable();
|
var symbols = Image.GetSymbolTable();
|
||||||
|
|
||||||
if (symbols?.Any() ?? false) {
|
if (symbols.Any()) {
|
||||||
Console.WriteLine($"Symbol table(s) found with {symbols.Count} entries");
|
Console.WriteLine($"Symbol table(s) found with {symbols.Count} entries");
|
||||||
|
|
||||||
symbols.TryGetValue("g_CodeRegistration", out var code);
|
symbols.TryGetValue("g_CodeRegistration", out var code);
|
||||||
symbols.TryGetValue("g_MetadataRegistration", out var metadata);
|
symbols.TryGetValue("g_MetadataRegistration", out var metadata);
|
||||||
|
|
||||||
if (code == 0)
|
if (code == null)
|
||||||
symbols.TryGetValue("_g_CodeRegistration", out code);
|
symbols.TryGetValue("_g_CodeRegistration", out code);
|
||||||
if (metadata == 0)
|
if (metadata == null)
|
||||||
symbols.TryGetValue("_g_MetadataRegistration", out metadata);
|
symbols.TryGetValue("_g_MetadataRegistration", out metadata);
|
||||||
|
|
||||||
if (code != 0 && metadata != 0) {
|
if (code != null && metadata != null) {
|
||||||
Console.WriteLine("Required structures acquired from symbol lookup");
|
Console.WriteLine("Required structures acquired from symbol lookup");
|
||||||
Configure(code, metadata);
|
Configure(code.VirtualAddress, metadata.VirtualAddress);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
Reference in New Issue
Block a user