From 69803a999ff0966eeff157c9d7938cd1b5e7d7c9 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 10 Nov 2022 22:09:58 -0800 Subject: [PATCH] Fix PE virtual address for section-aligned RVAs --- BurnOutSharp.Builder/Extensions.cs | 15 +++++++++++--- BurnOutSharp.Builder/PortableExecutable.cs | 23 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/BurnOutSharp.Builder/Extensions.cs b/BurnOutSharp.Builder/Extensions.cs index feae44c9..3cd7824a 100644 --- a/BurnOutSharp.Builder/Extensions.cs +++ b/BurnOutSharp.Builder/Extensions.cs @@ -342,6 +342,15 @@ namespace BurnOutSharp.Builder /// Physical address, 0 on error public static uint ConvertVirtualAddress(this uint rva, Models.PortableExecutable.SectionHeader[] sections) { + // If we have an invalid section table, we can't do anything + if (sections == null || sections.Length == 0) + return 0; + + // If the RVA matches a section start exactly, use that + var matchingSection = sections.FirstOrDefault(s => s.VirtualAddress == rva); + if (matchingSection != null) + return rva - matchingSection.VirtualAddress + matchingSection.PointerToRawData; + // Loop through all of the sections for (int i = 0; i < sections.Length; i++) { @@ -355,9 +364,9 @@ namespace BurnOutSharp.Builder // Attempt to derive the physical address from the current section var section = sections[i]; - if (rva >= section.VirtualAddress - && (rva <= section.VirtualAddress + section.SizeOfRawData - || rva <= section.VirtualAddress + section.VirtualSize)) + if (rva >= section.VirtualAddress && section.VirtualSize != 0 && rva <= section.VirtualAddress + section.VirtualSize) + return rva - section.VirtualAddress + section.PointerToRawData; + else if (rva >= section.VirtualAddress && section.SizeOfRawData != 0 && rva <= section.VirtualAddress + section.SizeOfRawData) return rva - section.VirtualAddress + section.PointerToRawData; } diff --git a/BurnOutSharp.Builder/PortableExecutable.cs b/BurnOutSharp.Builder/PortableExecutable.cs index 6903fd0d..cc39c9d5 100644 --- a/BurnOutSharp.Builder/PortableExecutable.cs +++ b/BurnOutSharp.Builder/PortableExecutable.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using BurnOutSharp.Models.PortableExecutable; namespace BurnOutSharp.Builder @@ -246,9 +247,15 @@ namespace BurnOutSharp.Builder // Should also be in the '.rsrc' section if (optionalHeader.ResourceTable != null && optionalHeader.ResourceTable.VirtualAddress != 0) { + // If the optional header and `.rsrc` section disagree, use the `.rsrc` section + var resourceSection = sectionTable.FirstOrDefault(sh => Encoding.ASCII.GetString(sh.Name).TrimEnd('\0') == ".rsrc"); + uint resourceTableRVA = optionalHeader.ResourceTable.VirtualAddress; + if (resourceSection != null) + resourceTableRVA = resourceSection.VirtualAddress; + // If the offset for the resource directory table doesn't exist int tableAddress = initialOffset - + (int)optionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable); + + (int)resourceTableRVA.ConvertVirtualAddress(executable.SectionTable); if (tableAddress >= data.Length) return executable; @@ -1072,6 +1079,9 @@ namespace BurnOutSharp.Builder var resourceDirectoryTable = new ResourceDirectoryTable(); resourceDirectoryTable.Characteristics = data.ReadUInt32(ref offset); + if (resourceDirectoryTable.Characteristics != 0) + return null; + resourceDirectoryTable.TimeDateStamp = data.ReadUInt32(ref offset); resourceDirectoryTable.MajorVersion = data.ReadUInt16(ref offset); resourceDirectoryTable.MinorVersion = data.ReadUInt16(ref offset); @@ -1435,9 +1445,15 @@ namespace BurnOutSharp.Builder // Should also be in the '.rsrc' section if (optionalHeader.ResourceTable != null && optionalHeader.ResourceTable.VirtualAddress != 0) { + // If the optional header and `.rsrc` section disagree, use the `.rsrc` section + var resourceSection = sectionTable.FirstOrDefault(sh => Encoding.ASCII.GetString(sh.Name).TrimEnd('\0') == ".rsrc"); + uint resourceTableRVA = optionalHeader.ResourceTable.VirtualAddress; + if (resourceSection != null) + resourceTableRVA = resourceSection.VirtualAddress; + // If the offset for the resource directory table doesn't exist int resourceTableAddress = initialOffset - + (int)optionalHeader.ResourceTable.VirtualAddress.ConvertVirtualAddress(executable.SectionTable); + + (int)resourceTableRVA.ConvertVirtualAddress(executable.SectionTable); if (resourceTableAddress >= data.Length) return executable; @@ -2269,6 +2285,9 @@ namespace BurnOutSharp.Builder var resourceDirectoryTable = new ResourceDirectoryTable(); resourceDirectoryTable.Characteristics = data.ReadUInt32(); + if (resourceDirectoryTable.Characteristics != 0) + return null; + resourceDirectoryTable.TimeDateStamp = data.ReadUInt32(); resourceDirectoryTable.MajorVersion = data.ReadUInt16(); resourceDirectoryTable.MinorVersion = data.ReadUInt16();