Fix PE virtual address for section-aligned RVAs

This commit is contained in:
Matt Nadareski
2022-11-10 22:09:58 -08:00
parent d4a75ed871
commit 69803a999f
2 changed files with 33 additions and 5 deletions

View File

@@ -342,6 +342,15 @@ namespace BurnOutSharp.Builder
/// <returns>Physical address, 0 on error</returns>
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;
}

View File

@@ -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();