2023-09-08 22:55:47 -04:00
|
|
|
using System;
|
2025-09-26 13:06:18 -04:00
|
|
|
using SabreTools.Data.Models.COFF;
|
2023-09-08 22:55:47 -04:00
|
|
|
|
2025-09-26 13:15:55 -04:00
|
|
|
namespace SabreTools.Data.Extensions
|
2023-09-08 22:55:47 -04:00
|
|
|
{
|
2026-03-21 20:09:10 -04:00
|
|
|
// TODO: Add tests
|
2026-03-18 17:15:03 -04:00
|
|
|
public static class PortableExecutableExtensions
|
2023-09-08 22:55:47 -04:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Convert a relative virtual address to a physical one
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="rva">Relative virtual address to convert</param>
|
|
|
|
|
/// <param name="sections">Array of sections to check against</param>
|
|
|
|
|
/// <returns>Physical address, 0 on error</returns>
|
2025-11-14 14:06:43 -05:00
|
|
|
public static uint ConvertVirtualAddress(this uint rva, SectionHeader[] sections)
|
2023-09-08 22:55:47 -04:00
|
|
|
{
|
|
|
|
|
// If we have an invalid section table, we can't do anything
|
2025-11-14 14:06:43 -05:00
|
|
|
if (sections.Length == 0)
|
2023-09-08 22:55:47 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// If the RVA is 0, we just return 0 because it's invalid
|
|
|
|
|
if (rva == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// If the RVA matches a section start exactly, use that
|
2024-11-30 02:49:10 -05:00
|
|
|
var matchingSection = Array.Find(sections, s => s.VirtualAddress == rva);
|
2026-01-25 14:32:49 -05:00
|
|
|
if (matchingSection is not null)
|
2023-09-08 22:55:47 -04:00
|
|
|
return rva - matchingSection.VirtualAddress + matchingSection.PointerToRawData;
|
|
|
|
|
|
|
|
|
|
// Loop through all of the sections
|
2025-09-11 10:11:05 -04:00
|
|
|
uint maxVirtualAddress = 0, maxRawPointer = 0;
|
2023-09-08 22:55:47 -04:00
|
|
|
for (int i = 0; i < sections.Length; i++)
|
|
|
|
|
{
|
2024-11-30 02:49:10 -05:00
|
|
|
// If the section "starts" at 0, just skip it
|
|
|
|
|
var section = sections[i];
|
|
|
|
|
if (section.PointerToRawData == 0)
|
2023-09-08 22:55:47 -04:00
|
|
|
continue;
|
|
|
|
|
|
2024-11-30 02:49:10 -05:00
|
|
|
// If the virtual address is greater than the RVA
|
|
|
|
|
if (rva < section.VirtualAddress)
|
2023-09-08 22:55:47 -04:00
|
|
|
continue;
|
|
|
|
|
|
2025-09-11 10:11:05 -04:00
|
|
|
// Cache the maximum matching section data, in case of a miss
|
|
|
|
|
if (rva >= section.VirtualAddress)
|
|
|
|
|
{
|
|
|
|
|
maxVirtualAddress = section.VirtualAddress;
|
|
|
|
|
maxRawPointer = section.PointerToRawData;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-08 22:55:47 -04:00
|
|
|
// Attempt to derive the physical address from the current section
|
2024-11-30 02:49:10 -05:00
|
|
|
if (section.VirtualSize != 0 && rva <= section.VirtualAddress + section.VirtualSize)
|
2023-09-08 22:55:47 -04:00
|
|
|
return rva - section.VirtualAddress + section.PointerToRawData;
|
2024-11-30 02:49:10 -05:00
|
|
|
else if (section.SizeOfRawData != 0 && rva <= section.VirtualAddress + section.SizeOfRawData)
|
2023-09-08 22:55:47 -04:00
|
|
|
return rva - section.VirtualAddress + section.PointerToRawData;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 10:11:05 -04:00
|
|
|
return maxRawPointer != 0 ? rva - maxVirtualAddress + maxRawPointer : 0;
|
2023-09-08 22:55:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Find the section a revlative virtual address lives in
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="rva">Relative virtual address to convert</param>
|
|
|
|
|
/// <param name="sections">Array of sections to check against</param>
|
|
|
|
|
/// <returns>Section index, null on error</returns>
|
2025-11-14 14:06:43 -05:00
|
|
|
public static int ContainingSectionIndex(this uint rva, SectionHeader[] sections)
|
2023-09-08 22:55:47 -04:00
|
|
|
{
|
|
|
|
|
// If we have an invalid section table, we can't do anything
|
2026-01-25 14:30:18 -05:00
|
|
|
if (sections is null || sections.Length == 0)
|
2023-09-08 22:55:47 -04:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// If the RVA is 0, we just return -1 because it's invalid
|
|
|
|
|
if (rva == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// Loop through all of the sections
|
|
|
|
|
for (int i = 0; i < sections.Length; i++)
|
|
|
|
|
{
|
2024-11-30 02:49:10 -05:00
|
|
|
// If the section "starts" at 0, just skip it
|
2023-09-15 22:48:37 -04:00
|
|
|
var section = sections[i];
|
2024-11-30 02:49:10 -05:00
|
|
|
if (section.PointerToRawData == 0)
|
2023-09-08 22:55:47 -04:00
|
|
|
continue;
|
|
|
|
|
|
2024-11-30 02:49:10 -05:00
|
|
|
// If the virtual address is greater than the RVA
|
|
|
|
|
if (rva < section.VirtualAddress)
|
2023-09-08 22:55:47 -04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Attempt to derive the physical address from the current section
|
2024-11-30 02:49:10 -05:00
|
|
|
if (section.VirtualSize != 0 && rva <= section.VirtualAddress + section.VirtualSize)
|
2023-09-08 22:55:47 -04:00
|
|
|
return i;
|
2024-11-30 02:49:10 -05:00
|
|
|
else if (section.SizeOfRawData != 0 && rva <= section.VirtualAddress + section.SizeOfRawData)
|
2023-09-08 22:55:47 -04:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-24 09:31:28 -04:00
|
|
|
}
|