From 1496bbb623bab7e885a0767376dad961ae9e6596 Mon Sep 17 00:00:00 2001 From: Katy Coe Date: Mon, 28 Oct 2019 22:13:20 +0100 Subject: [PATCH] PE32+: Initial support --- .../FileFormatReaders/FormatLayouts/PE.cs | 42 +++++++++++++++---- Il2CppInspector/FileFormatReaders/PEReader.cs | 21 ++++++---- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs b/Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs index 3992bd3..ccfe469 100644 --- a/Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs +++ b/Il2CppInspector/FileFormatReaders/FormatLayouts/PE.cs @@ -9,8 +9,14 @@ using NoisyCowStudios.Bin2Object; namespace Il2CppInspector { // Source: https://github.com/dotnet/llilc/blob/master/include/clr/ntimage.h -#pragma warning disable CS0649 + public enum PE : uint + { + IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b, + IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b + } + +#pragma warning disable CS0649 // _IMAGE_FILE_HEADER internal class COFFHeader { @@ -24,9 +30,22 @@ namespace Il2CppInspector } // _IMAGE_OPTIONAL_HEADER - internal class PEOptHeader32 + internal interface IPEOptHeader { - public ushort Magic; + PE ExpectedMagic { get; } + ushort Magic { get; } + ulong ImageBase { get; } + RvaEntry[] DataDirectory { get; } + } + + internal class PEOptHeader32 : IPEOptHeader + { + public PE ExpectedMagic => PE.IMAGE_NT_OPTIONAL_HDR32_MAGIC; + public ushort Magic => f_Magic; + public ulong ImageBase => f_ImageBase; + public RvaEntry[] DataDirectory => f_DataDirectory; + + public ushort f_Magic; public byte MajorLinkerVersion; public byte MinorLinkerVersion; public uint SizeOfCode; @@ -35,7 +54,7 @@ namespace Il2CppInspector public uint AddressOfEntryPoint; public uint BaseOfCode; public uint BaseOfData; - public uint ImageBase; + public uint f_ImageBase; public uint SectionAlignment; public uint FileAlignment; public ushort MajorOSVersion; @@ -57,13 +76,18 @@ namespace Il2CppInspector public uint LoaderFlags; public uint NumberOfRvaAndSizes; [ArrayLength(FieldName = "NumberOfRvaAndSizes")] - public RvaEntry[] DataDirectory; + public RvaEntry[] f_DataDirectory; } // _IMAGE_OPTIONAL_HEADER64 - internal class PEOptHeader64 + internal class PEOptHeader64 : IPEOptHeader { - public ushort Magic; + public PE ExpectedMagic => PE.IMAGE_NT_OPTIONAL_HDR64_MAGIC; + public ushort Magic => f_Magic; + public ulong ImageBase => f_ImageBase; + public RvaEntry[] DataDirectory => f_DataDirectory; + + public ushort f_Magic; public byte MajorLinkerVersion; public byte MinorLinkerVersion; public uint SizeOfCode; @@ -71,7 +95,7 @@ namespace Il2CppInspector public uint SizeOfUninitializedData; public uint AddressOfEntryPoint; public uint BaseOfCode; - public ulong ImageBase; + public ulong f_ImageBase; public uint SectionAlignment; public uint FileAlignment; public ushort MajorOSVersion; @@ -93,7 +117,7 @@ namespace Il2CppInspector public uint LoaderFlags; public uint NumberOfRvaAndSizes; [ArrayLength(FieldName = "NumberOfRvaAndSizes")] - public RvaEntry[] DataDirectory; + public RvaEntry[] f_DataDirectory; } internal class RvaEntry diff --git a/Il2CppInspector/FileFormatReaders/PEReader.cs b/Il2CppInspector/FileFormatReaders/PEReader.cs index d886e32..9109444 100644 --- a/Il2CppInspector/FileFormatReaders/PEReader.cs +++ b/Il2CppInspector/FileFormatReaders/PEReader.cs @@ -13,13 +13,13 @@ namespace Il2CppInspector internal class PEReader : FileFormatReader { private COFFHeader coff; - private PEOptHeader32 pe; + private IPEOptHeader pe; private PESection[] sections; private uint pFuncTable; public PEReader(Stream stream) : base(stream) {} - public override string Format => "PE"; + public override string Format => pe is PEOptHeader32 ? "PE32" : "PE32+"; public override string Arch => coff.Machine switch { 0x8664 => "x64", // IMAGE_FILE_MACHINE_AMD64 @@ -34,7 +34,7 @@ namespace Il2CppInspector // IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20B // IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10B // Could also use coff.Characteristics (IMAGE_FILE_32BIT_MACHINE) or coff.Machine - public override int Bits => pe.Magic == 0x20B ? 64 : 32; + public override int Bits => (PE) pe.Magic == PE.IMAGE_NT_OPTIONAL_HDR64_MAGIC ? 64 : 32; protected override bool Init() { // Check for MZ signature "MZ" @@ -52,15 +52,20 @@ namespace Il2CppInspector coff = ReadObject(); // Ensure presence of PE Optional header - // Size will always be 0x60 + (0x10 ' 0x8) for 16 RVA entries @ 8 bytes each - if (coff.SizeOfOptionalHeader != 0xE0) + // Size will always be 0x60 (32-bit) or 0x70 (64-bit) + (0x10 ' 0x8) for 16 RVA entries @ 8 bytes each + if (!((coff.SizeOfOptionalHeader == 0xE0 ? 32 : + coff.SizeOfOptionalHeader == 0xF0 ? (int?) 64 : null) is var likelyWordSize)) return false; // Read PE optional header - pe = ReadObject(); + pe = likelyWordSize switch { + 32 => ReadObject(), + 64 => ReadObject(), + _ => null + }; - // Ensure IMAGE_NT_OPTIONAL_HDR32_MAGIC (32-bit) - if (pe.Magic != 0x10B) + // Confirm architecture magic number matches expected word size + if ((PE) pe.Magic != pe.ExpectedMagic) return false; // Get IAT