diff --git a/Il2CppInspector.Common/FileFormatReaders/Export.cs b/Il2CppInspector.Common/FileFormatReaders/Export.cs new file mode 100644 index 0000000..8cbcc5c --- /dev/null +++ b/Il2CppInspector.Common/FileFormatReaders/Export.cs @@ -0,0 +1,15 @@ +/* + Copyright 2020 Katy Coe - http://www.djkaty.com - https://github.com/djkaty + + All rights reserved. +*/ + +namespace Il2CppInspector +{ + public class Export + { + public int Ordinal; + public string Name; + public ulong VirtualAddress; + } +} diff --git a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs index 5ca0df8..aebb010 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FileFormatReader.cs @@ -28,6 +28,7 @@ namespace Il2CppInspector ulong GlobalOffset { get; } Dictionary GetSymbolTable(); uint[] GetFunctionTable(); + IEnumerable GetExports(); U ReadMappedObject(ulong uiAddr) where U : new(); U[] ReadMappedArray(ulong uiAddr, int count) where U : new(); long[] ReadMappedWordArray(ulong uiAddr, int count); @@ -136,6 +137,9 @@ namespace Il2CppInspector // Find search locations in the machine code for Il2Cpp data public virtual uint[] GetFunctionTable() => throw new NotImplementedException(); + // Find all symbol exports for the image + public virtual IEnumerable GetExports() => null; + // Map an RVA to an offset into the file image // No mapping by default public virtual uint MapVATR(ulong uiAddr) => (uint) uiAddr; diff --git a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/PE.cs b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/PE.cs index 3c01353..dfa40dc 100644 --- a/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/PE.cs +++ b/Il2CppInspector.Common/FileFormatReaders/FormatLayouts/PE.cs @@ -144,5 +144,21 @@ namespace Il2CppInspector public ushort NumberOfLinenumbers; public uint Characteristics; } + + // _IMAGE_EXPORT_DIRECTORY + internal class PEExportDirectory + { + public uint Characteristics; + public uint TimeDateStamp; + public ushort MajorVersion; + public ushort MinorVersion; + public uint Name; + public uint Base; + public uint NumberOfFunctions; + public uint NumberOfNames; + public uint AddressOfFunctions; + public uint AddressOfNames; + public uint AddressOfNameOrdinals; + } #pragma warning restore CS0649 } diff --git a/Il2CppInspector.Common/FileFormatReaders/PEReader.cs b/Il2CppInspector.Common/FileFormatReaders/PEReader.cs index bb0f837..d82fb3d 100644 --- a/Il2CppInspector.Common/FileFormatReaders/PEReader.cs +++ b/Il2CppInspector.Common/FileFormatReaders/PEReader.cs @@ -4,6 +4,7 @@ All rights reserved. */ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -113,6 +114,32 @@ namespace Il2CppInspector return addrs.ToArray(); } + public override IEnumerable GetExports() { + // Get exports table + var ETStart = pe.DataDirectory[0].VirtualAddress + pe.ImageBase; + + // Get export RVAs + var exportDirectoryTable = ReadObject(MapVATR(ETStart)); + var exportCount = (int) exportDirectoryTable.NumberOfFunctions; + var exportAddresses = ReadArray(MapVATR(exportDirectoryTable.AddressOfFunctions + pe.ImageBase), exportCount); + var exports = exportAddresses.Select((a, i) => new Export { + Ordinal = (int) (exportDirectoryTable.Base + i), + VirtualAddress = pe.ImageBase + a + }).ToDictionary(x => x.Ordinal, x => x); + + // Get export names + var nameCount = (int) exportDirectoryTable.NumberOfNames; + var namePointers = ReadArray(MapVATR(exportDirectoryTable.AddressOfNames + pe.ImageBase), nameCount); + var ordinals = ReadArray(MapVATR(exportDirectoryTable.AddressOfNameOrdinals + pe.ImageBase), nameCount); + for (int i = 0; i < nameCount; i++) { + var name = ReadNullTerminatedString(MapVATR(namePointers[i] + pe.ImageBase)); + var ordinal = (int) exportDirectoryTable.Base + ordinals[i]; + exports[ordinal].Name = name; + } + + return exports.Values; + } + public override uint MapVATR(ulong uiAddr) { if (uiAddr == 0) return 0;