mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-13 13:45:57 +00:00
Add PE partial debug table parsing
This commit is contained in:
@@ -174,6 +174,29 @@ namespace BurnOutSharp.Builder
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Table
|
||||
|
||||
// Should also be in the '.debug' section
|
||||
if (optionalHeader.Debug != null && optionalHeader.Debug.VirtualAddress != 0)
|
||||
{
|
||||
// If the offset for the debug table doesn't exist
|
||||
int debugTableAddress = initialOffset
|
||||
+ (int)optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
|
||||
if (debugTableAddress >= data.Length)
|
||||
return executable;
|
||||
|
||||
// Try to parse the debug table
|
||||
int endOffset = (int)(debugTableAddress + optionalHeader.CertificateTable.Size);
|
||||
var debugTable = ParseDebugTable(data, debugTableAddress, endOffset, executable.SectionTable);
|
||||
if (debugTable == null)
|
||||
return null;
|
||||
|
||||
// Set the debug table
|
||||
executable.DebugTable = debugTable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Export Table
|
||||
|
||||
// Should also be in the '.rsrc' section
|
||||
@@ -714,6 +737,45 @@ namespace BurnOutSharp.Builder
|
||||
return delayLoadDirectoryTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a debug table
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array to parse</param>
|
||||
/// <param name="offset">Offset into the byte array</param>
|
||||
/// <param name="endOffset">First address not part of the debug table</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled debug table on success, null on error</returns>
|
||||
private static DebugTable ParseDebugTable(byte[] data, int offset, int endOffset, SectionHeader[] sections)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var debugTable = new DebugTable();
|
||||
|
||||
var debugDirectoryTable = new List<DebugDirectoryEntry>();
|
||||
|
||||
while (offset < endOffset)
|
||||
{
|
||||
var debugDirectoryEntry = new DebugDirectoryEntry();
|
||||
|
||||
debugDirectoryEntry.Characteristics = data.ReadUInt32(ref offset);
|
||||
debugDirectoryEntry.TimeDateStamp = data.ReadUInt32(ref offset);
|
||||
debugDirectoryEntry.MajorVersion = data.ReadUInt16(ref offset);
|
||||
debugDirectoryEntry.MinorVersion = data.ReadUInt16(ref offset);
|
||||
debugDirectoryEntry.DebugType = (DebugType)data.ReadUInt32(ref offset);
|
||||
debugDirectoryEntry.SizeOfData = data.ReadUInt32(ref offset);
|
||||
debugDirectoryEntry.AddressOfRawData = data.ReadUInt32(ref offset);
|
||||
debugDirectoryEntry.PointerToRawData = data.ReadUInt32(ref offset);
|
||||
|
||||
debugDirectoryTable.Add(debugDirectoryEntry);
|
||||
}
|
||||
|
||||
debugTable.DebugDirectoryTable = debugDirectoryTable.ToArray();
|
||||
|
||||
// TODO: Should we read the debug data in? Most of it is unformatted or undocumented
|
||||
// TODO: Implement .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
|
||||
|
||||
return debugTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a byte array into a export table
|
||||
/// </summary>
|
||||
@@ -1298,6 +1360,30 @@ namespace BurnOutSharp.Builder
|
||||
|
||||
#endregion
|
||||
|
||||
#region Debug Table
|
||||
|
||||
// Should also be in the '.debug' section
|
||||
if (optionalHeader.Debug != null && optionalHeader.Debug.VirtualAddress != 0)
|
||||
{
|
||||
// If the offset for the debug table doesn't exist
|
||||
int debugTableAddress = initialOffset
|
||||
+ (int)optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
|
||||
if (debugTableAddress >= data.Length)
|
||||
return executable;
|
||||
|
||||
// Try to parse the debug table
|
||||
data.Seek(debugTableAddress, SeekOrigin.Begin);
|
||||
int endOffset = (int)(debugTableAddress + optionalHeader.CertificateTable.Size);
|
||||
var debugTable = ParseDebugTable(data, endOffset, executable.SectionTable);
|
||||
if (debugTable == null)
|
||||
return null;
|
||||
|
||||
// Set the debug table
|
||||
executable.DebugTable = debugTable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Export Table
|
||||
|
||||
// Should also be in the '.edata' section
|
||||
@@ -1834,6 +1920,44 @@ namespace BurnOutSharp.Builder
|
||||
return delayLoadDirectoryTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a debug table
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <param name="endOffset">First address not part of the debug table</param>
|
||||
/// <param name="sections">Section table to use for virtual address translation</param>
|
||||
/// <returns>Filled debug table on success, null on error</returns>
|
||||
private static DebugTable ParseDebugTable(Stream data, int endOffset, SectionHeader[] sections)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
var debugTable = new DebugTable();
|
||||
|
||||
var debugDirectoryTable = new List<DebugDirectoryEntry>();
|
||||
|
||||
while (data.Position < endOffset)
|
||||
{
|
||||
var debugDirectoryEntry = new DebugDirectoryEntry();
|
||||
|
||||
debugDirectoryEntry.Characteristics = data.ReadUInt32();
|
||||
debugDirectoryEntry.TimeDateStamp = data.ReadUInt32();
|
||||
debugDirectoryEntry.MajorVersion = data.ReadUInt16();
|
||||
debugDirectoryEntry.MinorVersion = data.ReadUInt16();
|
||||
debugDirectoryEntry.DebugType = (DebugType)data.ReadUInt32();
|
||||
debugDirectoryEntry.SizeOfData = data.ReadUInt32();
|
||||
debugDirectoryEntry.AddressOfRawData = data.ReadUInt32();
|
||||
debugDirectoryEntry.PointerToRawData = data.ReadUInt32();
|
||||
|
||||
debugDirectoryTable.Add(debugDirectoryEntry);
|
||||
}
|
||||
|
||||
debugTable.DebugDirectoryTable = debugDirectoryTable.ToArray();
|
||||
|
||||
// TODO: Should we read the debug data in? Most of it is unformatted or undocumented
|
||||
// TODO: Implement .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
|
||||
|
||||
return debugTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a export table
|
||||
/// </summary>
|
||||
|
||||
38
BurnOutSharp.Models/PortableExecutable/DebugTable.cs
Normal file
38
BurnOutSharp.Models/PortableExecutable/DebugTable.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace BurnOutSharp.Models.PortableExecutable
|
||||
{
|
||||
/// <summary>
|
||||
/// The .debug section is used in object files to contain compiler-generated debug
|
||||
/// information and in image files to contain all of the debug information that is
|
||||
/// generated. This section describes the packaging of debug information in object
|
||||
/// and image files.
|
||||
///
|
||||
/// The next section describes the format of the debug directory, which can be
|
||||
/// anywhere in the image. Subsequent sections describe the "groups" in object
|
||||
/// files that contain debug information.
|
||||
///
|
||||
/// The default for the linker is that debug information is not mapped into the
|
||||
/// address space of the image. A .debug section exists only when debug information
|
||||
/// is mapped in the address space.
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/debug/pe-format"/>
|
||||
public class DebugTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Image files contain an optional debug directory that indicates what form
|
||||
/// of debug information is present and where it is. This directory consists
|
||||
/// of an array of debug directory entries whose location and size are
|
||||
/// indicated in the image optional header.
|
||||
///
|
||||
/// The debug directory can be in a discardable .debug section (if one exists),
|
||||
/// or it can be included in any other section in the image file, or not be
|
||||
/// in a section at all.
|
||||
///
|
||||
/// Each debug directory entry identifies the location and size of a block of
|
||||
/// debug information. The specified RVA can be zero if the debug information
|
||||
/// is not covered by a section header (that is, it resides in the image
|
||||
/// file and is not mapped into the run-time address space). If it is mapped,
|
||||
/// the RVA is its address.
|
||||
/// </summary>
|
||||
public DebugDirectoryEntry[] DebugDirectoryTable;
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,11 @@ namespace BurnOutSharp.Models.PortableExecutable
|
||||
// the object file contains managed code. The format of the metadata is not
|
||||
// documented, but can be handed to the CLR interfaces for handling metadata.
|
||||
|
||||
/// <summary>
|
||||
/// Debug table (.debug*)
|
||||
/// </summary>
|
||||
public DebugTable DebugTable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Export table (.edata)
|
||||
/// </summary>
|
||||
@@ -101,9 +106,6 @@ namespace BurnOutSharp.Models.PortableExecutable
|
||||
// - Delay Import Name Table
|
||||
// - Delay Bound Import Address Table
|
||||
// - Delay Unload Import Address Table
|
||||
// - The .debug Section
|
||||
// - [Debug Directory Entry]
|
||||
// - .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
|
||||
// - The .drectve Section (Object Only)
|
||||
// - The .pdata Section [Multiple formats per entry]
|
||||
// - TLS Callback Functions
|
||||
|
||||
Reference in New Issue
Block a user