diff --git a/X86Disassembler/PE/DOSHeader.cs b/X86Disassembler/PE/DOSHeader.cs
index ea30ee4..9e321bb 100644
--- a/X86Disassembler/PE/DOSHeader.cs
+++ b/X86Disassembler/PE/DOSHeader.cs
@@ -1,40 +1,37 @@
-using System;
+namespace X86Disassembler.PE;
-namespace X86Disassembler.PE
+///
+/// Represents the DOS header of a PE file
+///
+public class DOSHeader
{
- ///
- /// Represents the DOS header of a PE file
- ///
- public class DOSHeader
- {
- public ushort e_magic; // Magic number (MZ)
- public ushort e_cblp; // Bytes on last page of file
- public ushort e_cp; // Pages in file
- public ushort e_crlc; // Relocations
- public ushort e_cparhdr; // Size of header in paragraphs
- public ushort e_minalloc; // Minimum extra paragraphs needed
- public ushort e_maxalloc; // Maximum extra paragraphs needed
- public ushort e_ss; // Initial (relative) SS value
- public ushort e_sp; // Initial SP value
- public ushort e_csum; // Checksum
- public ushort e_ip; // Initial IP value
- public ushort e_cs; // Initial (relative) CS value
- public ushort e_lfarlc; // File address of relocation table
- public ushort e_ovno; // Overlay number
- public ushort[] e_res; // Reserved words
- public ushort e_oemid; // OEM identifier (for e_oeminfo)
- public ushort e_oeminfo; // OEM information; e_oemid specific
- public ushort[] e_res2; // Reserved words
- public uint e_lfanew; // File address of new exe header
+ public ushort e_magic; // Magic number (MZ)
+ public ushort e_cblp; // Bytes on last page of file
+ public ushort e_cp; // Pages in file
+ public ushort e_crlc; // Relocations
+ public ushort e_cparhdr; // Size of header in paragraphs
+ public ushort e_minalloc; // Minimum extra paragraphs needed
+ public ushort e_maxalloc; // Maximum extra paragraphs needed
+ public ushort e_ss; // Initial (relative) SS value
+ public ushort e_sp; // Initial SP value
+ public ushort e_csum; // Checksum
+ public ushort e_ip; // Initial IP value
+ public ushort e_cs; // Initial (relative) CS value
+ public ushort e_lfarlc; // File address of relocation table
+ public ushort e_ovno; // Overlay number
+ public ushort[] e_res; // Reserved words
+ public ushort e_oemid; // OEM identifier (for e_oeminfo)
+ public ushort e_oeminfo; // OEM information; e_oemid specific
+ public ushort[] e_res2; // Reserved words
+ public uint e_lfanew; // File address of new exe header
- ///
- /// Initializes a new instance of the DOSHeader class
- ///
- public DOSHeader()
- {
- // Initialize arrays to avoid nullability warnings
- e_res = new ushort[4];
- e_res2 = new ushort[10];
- }
+ ///
+ /// Initializes a new instance of the DOSHeader class
+ ///
+ public DOSHeader()
+ {
+ // Initialize arrays to avoid nullability warnings
+ e_res = new ushort[4];
+ e_res2 = new ushort[10];
}
-}
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/ExportDirectory.cs b/X86Disassembler/PE/ExportDirectory.cs
index c29086c..4a02d95 100644
--- a/X86Disassembler/PE/ExportDirectory.cs
+++ b/X86Disassembler/PE/ExportDirectory.cs
@@ -1,30 +1,29 @@
-namespace X86Disassembler.PE
+namespace X86Disassembler.PE;
+
+///
+/// Represents the Export Directory of a PE file
+///
+public class ExportDirectory
{
- ///
- /// Represents the Export Directory of a PE file
- ///
- public class ExportDirectory
- {
- public uint Characteristics; // Reserved, must be 0
- public uint TimeDateStamp; // Time and date stamp
- public ushort MajorVersion; // Major version
- public ushort MinorVersion; // Minor version
- public uint Name; // RVA of the name of the DLL
- public string DllName; // The actual name of the DLL
- public uint Base; // Ordinal base
- public uint NumberOfFunctions; // Number of functions
- public uint NumberOfNames; // Number of names
- public uint AddressOfFunctions; // RVA of the export address table
- public uint AddressOfNames; // RVA of the export names table
- public uint AddressOfNameOrdinals; // RVA of the ordinal table
+ public uint Characteristics; // Reserved, must be 0
+ public uint TimeDateStamp; // Time and date stamp
+ public ushort MajorVersion; // Major version
+ public ushort MinorVersion; // Minor version
+ public uint Name; // RVA of the name of the DLL
+ public string DllName; // The actual name of the DLL
+ public uint Base; // Ordinal base
+ public uint NumberOfFunctions; // Number of functions
+ public uint NumberOfNames; // Number of names
+ public uint AddressOfFunctions; // RVA of the export address table
+ public uint AddressOfNames; // RVA of the export names table
+ public uint AddressOfNameOrdinals; // RVA of the ordinal table
- ///
- /// Initializes a new instance of the ExportDirectory class
- ///
- public ExportDirectory()
- {
- // Initialize string field to avoid nullability warning
- DllName = string.Empty;
- }
+ ///
+ /// Initializes a new instance of the ExportDirectory class
+ ///
+ public ExportDirectory()
+ {
+ // Initialize string field to avoid nullability warning
+ DllName = string.Empty;
}
-}
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/FileHeader.cs b/X86Disassembler/PE/FileHeader.cs
index 00a8538..24364f8 100644
--- a/X86Disassembler/PE/FileHeader.cs
+++ b/X86Disassembler/PE/FileHeader.cs
@@ -1,16 +1,15 @@
-namespace X86Disassembler.PE
+namespace X86Disassembler.PE;
+
+///
+/// Represents the File header of a PE file
+///
+public class FileHeader
{
- ///
- /// Represents the File header of a PE file
- ///
- public class FileHeader
- {
- public ushort Machine; // Target machine type
- public ushort NumberOfSections; // Number of sections
- public uint TimeDateStamp; // Time and date stamp
- public uint PointerToSymbolTable; // File pointer to COFF symbol table
- public uint NumberOfSymbols; // Number of symbols
- public ushort SizeOfOptionalHeader; // Size of optional header
- public ushort Characteristics; // Characteristics
- }
-}
+ public ushort Machine; // Target machine type
+ public ushort NumberOfSections; // Number of sections
+ public uint TimeDateStamp; // Time and date stamp
+ public uint PointerToSymbolTable; // File pointer to COFF symbol table
+ public uint NumberOfSymbols; // Number of symbols
+ public ushort SizeOfOptionalHeader; // Size of optional header
+ public ushort Characteristics; // Characteristics
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/ImportDescriptor.cs b/X86Disassembler/PE/ImportDescriptor.cs
index 0b5acdf..56bbf4d 100644
--- a/X86Disassembler/PE/ImportDescriptor.cs
+++ b/X86Disassembler/PE/ImportDescriptor.cs
@@ -1,28 +1,25 @@
-using System.Collections.Generic;
+namespace X86Disassembler.PE;
-namespace X86Disassembler.PE
+///
+/// Represents an Import Descriptor in a PE file
+///
+public class ImportDescriptor
{
+ public uint OriginalFirstThunk; // RVA to original first thunk
+ public uint TimeDateStamp; // Time and date stamp
+ public uint ForwarderChain; // Forwarder chain
+ public uint Name; // RVA to the name of the DLL
+ public string DllName; // The actual name of the DLL
+ public uint FirstThunk; // RVA to first thunk
+
+ public List Functions { get; } = new List();
+
///
- /// Represents an Import Descriptor in a PE file
+ /// Initializes a new instance of the ImportDescriptor class
///
- public class ImportDescriptor
+ public ImportDescriptor()
{
- public uint OriginalFirstThunk; // RVA to original first thunk
- public uint TimeDateStamp; // Time and date stamp
- public uint ForwarderChain; // Forwarder chain
- public uint Name; // RVA to the name of the DLL
- public string DllName; // The actual name of the DLL
- public uint FirstThunk; // RVA to first thunk
-
- public List Functions { get; } = new List();
-
- ///
- /// Initializes a new instance of the ImportDescriptor class
- ///
- public ImportDescriptor()
- {
- // Initialize string field to avoid nullability warning
- DllName = string.Empty;
- }
+ // Initialize string field to avoid nullability warning
+ DllName = string.Empty;
}
-}
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/OptionalHeader.cs b/X86Disassembler/PE/OptionalHeader.cs
index a4e4b83..ff335a1 100644
--- a/X86Disassembler/PE/OptionalHeader.cs
+++ b/X86Disassembler/PE/OptionalHeader.cs
@@ -1,73 +1,72 @@
-namespace X86Disassembler.PE
+namespace X86Disassembler.PE;
+
+///
+/// Represents the Optional header of a PE file
+///
+public class OptionalHeader
{
+ // Optional Header Magic values
+ private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
+ private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
+
+ // Standard fields
+ public ushort Magic; // Magic number (PE32 or PE32+)
+ public byte MajorLinkerVersion; // Major linker version
+ public byte MinorLinkerVersion; // Minor linker version
+ public uint SizeOfCode; // Size of code section
+ public uint SizeOfInitializedData; // Size of initialized data section
+ public uint SizeOfUninitializedData; // Size of uninitialized data section
+ public uint AddressOfEntryPoint; // Address of entry point
+ public uint BaseOfCode; // Base of code section
+ public uint BaseOfData; // Base of data section (PE32 only)
+
+ // Windows-specific fields
+ public object ImageBase; // Image base address (uint for PE32, ulong for PE32+)
+ public uint SectionAlignment; // Section alignment
+ public uint FileAlignment; // File alignment
+ public ushort MajorOperatingSystemVersion; // Major OS version
+ public ushort MinorOperatingSystemVersion; // Minor OS version
+ public ushort MajorImageVersion; // Major image version
+ public ushort MinorImageVersion; // Minor image version
+ public ushort MajorSubsystemVersion; // Major subsystem version
+ public ushort MinorSubsystemVersion; // Minor subsystem version
+ public uint Win32VersionValue; // Win32 version value
+ public uint SizeOfImage; // Size of image
+ public uint SizeOfHeaders; // Size of headers
+ public uint CheckSum; // Checksum
+ public ushort Subsystem; // Subsystem
+ public ushort DllCharacteristics; // DLL characteristics
+ public object SizeOfStackReserve; // Size of stack reserve (uint for PE32, ulong for PE32+)
+ public object SizeOfStackCommit; // Size of stack commit (uint for PE32, ulong for PE32+)
+ public object SizeOfHeapReserve; // Size of heap reserve (uint for PE32, ulong for PE32+)
+ public object SizeOfHeapCommit; // Size of heap commit (uint for PE32, ulong for PE32+)
+ public uint LoaderFlags; // Loader flags
+ public uint NumberOfRvaAndSizes; // Number of RVA and sizes
+
+ public DataDirectory[] DataDirectories; // Data directories
+
///
- /// Represents the Optional header of a PE file
+ /// Initializes a new instance of the OptionalHeader class
///
- public class OptionalHeader
+ public OptionalHeader()
{
- // Optional Header Magic values
- private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
- private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
-
- // Standard fields
- public ushort Magic; // Magic number (PE32 or PE32+)
- public byte MajorLinkerVersion; // Major linker version
- public byte MinorLinkerVersion; // Minor linker version
- public uint SizeOfCode; // Size of code section
- public uint SizeOfInitializedData; // Size of initialized data section
- public uint SizeOfUninitializedData; // Size of uninitialized data section
- public uint AddressOfEntryPoint; // Address of entry point
- public uint BaseOfCode; // Base of code section
- public uint BaseOfData; // Base of data section (PE32 only)
-
- // Windows-specific fields
- public object ImageBase; // Image base address (uint for PE32, ulong for PE32+)
- public uint SectionAlignment; // Section alignment
- public uint FileAlignment; // File alignment
- public ushort MajorOperatingSystemVersion; // Major OS version
- public ushort MinorOperatingSystemVersion; // Minor OS version
- public ushort MajorImageVersion; // Major image version
- public ushort MinorImageVersion; // Minor image version
- public ushort MajorSubsystemVersion; // Major subsystem version
- public ushort MinorSubsystemVersion; // Minor subsystem version
- public uint Win32VersionValue; // Win32 version value
- public uint SizeOfImage; // Size of image
- public uint SizeOfHeaders; // Size of headers
- public uint CheckSum; // Checksum
- public ushort Subsystem; // Subsystem
- public ushort DllCharacteristics; // DLL characteristics
- public object SizeOfStackReserve; // Size of stack reserve (uint for PE32, ulong for PE32+)
- public object SizeOfStackCommit; // Size of stack commit (uint for PE32, ulong for PE32+)
- public object SizeOfHeapReserve; // Size of heap reserve (uint for PE32, ulong for PE32+)
- public object SizeOfHeapCommit; // Size of heap commit (uint for PE32, ulong for PE32+)
- public uint LoaderFlags; // Loader flags
- public uint NumberOfRvaAndSizes; // Number of RVA and sizes
-
- public DataDirectory[] DataDirectories; // Data directories
-
- ///
- /// Initializes a new instance of the OptionalHeader class
- ///
- public OptionalHeader()
- {
- // Initialize object fields to avoid nullability warnings
- ImageBase = 0u; // Default to 32-bit value
- SizeOfStackReserve = 0u;
- SizeOfStackCommit = 0u;
- SizeOfHeapReserve = 0u;
- SizeOfHeapCommit = 0u;
+ // Initialize object fields to avoid nullability warnings
+ ImageBase = 0u; // Default to 32-bit value
+ SizeOfStackReserve = 0u;
+ SizeOfStackCommit = 0u;
+ SizeOfHeapReserve = 0u;
+ SizeOfHeapCommit = 0u;
- // Initialize array to avoid nullability warning
- DataDirectories = new DataDirectory[0];
- }
-
- ///
- /// Determines if the PE file is 64-bit based on the Magic value
- ///
- /// True if the PE file is 64-bit, false otherwise
- public bool Is64Bit()
- {
- return Magic == PE32PLUS_MAGIC;
- }
+ // Initialize array to avoid nullability warning
+ DataDirectories = new DataDirectory[0];
}
-}
+
+ ///
+ /// Determines if the PE file is 64-bit based on the Magic value
+ ///
+ /// True if the PE file is 64-bit, false otherwise
+ public bool Is64Bit()
+ {
+ return Magic == PE32PLUS_MAGIC;
+ }
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/PEFormat.cs b/X86Disassembler/PE/PEFormat.cs
index dbb8c62..130a0f8 100644
--- a/X86Disassembler/PE/PEFormat.cs
+++ b/X86Disassembler/PE/PEFormat.cs
@@ -1,236 +1,231 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
using X86Disassembler.PE.Parsers;
-namespace X86Disassembler.PE
+namespace X86Disassembler.PE;
+
+///
+/// Represents a Portable Executable (PE) file format parser
+///
+public class PEFormat
{
+ // DOS Header constants
+ private const ushort DOS_SIGNATURE = 0x5A4D; // 'MZ'
+ private const uint PE_SIGNATURE = 0x00004550; // 'PE\0\0'
+
+ // Optional Header Magic values
+ private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
+ private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
+
+ // Section characteristics flags
+ private const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code
+ private const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable
+ private const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable
+ private const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writable
+
+ // Data directories
+ private const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export Directory
+ private const int IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import Directory
+ private const int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource Directory
+ private const int IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception Directory
+ private const int IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security Directory
+ private const int IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table
+ private const int IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug Directory
+ private const int IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; // Architecture Specific Data
+ private const int IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // RVA of GP
+ private const int IMAGE_DIRECTORY_ENTRY_TLS = 9; // TLS Directory
+ private const int IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load Configuration Directory
+ private const int IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound Import Directory
+ private const int IMAGE_DIRECTORY_ENTRY_IAT = 12; // Import Address Table
+ private const int IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay Load Import Descriptors
+ private const int IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; // COM Runtime descriptor
+
+ // PE file data
+ private byte[] _fileData;
+
+ // Parser instances
+ private readonly DOSHeaderParser _dosHeaderParser;
+ private readonly FileHeaderParser _fileHeaderParser;
+ private readonly OptionalHeaderParser _optionalHeaderParser;
+ private readonly SectionHeaderParser _sectionHeaderParser;
+ private PEUtility _peUtility;
+ private ExportDirectoryParser _exportDirectoryParser;
+ private ImportDescriptorParser _importDescriptorParser;
+
+ // Parsed headers
+ public DOSHeader DosHeader { get; private set; }
+ public FileHeader FileHeader { get; private set; }
+ public OptionalHeader OptionalHeader { get; private set; }
+ public List SectionHeaders { get; private set; }
+ public bool Is64Bit { get; private set; }
+
+ // Export and Import information
+ public ExportDirectory ExportDirectory { get; private set; }
+ public List ExportedFunctions { get; private set; }
+ public List ImportDescriptors { get; private set; }
+
///
- /// Represents a Portable Executable (PE) file format parser
+ /// Initializes a new instance of the PEFormat class
///
- public class PEFormat
+ /// The raw file data
+ public PEFormat(byte[] fileData)
{
- // DOS Header constants
- private const ushort DOS_SIGNATURE = 0x5A4D; // 'MZ'
- private const uint PE_SIGNATURE = 0x00004550; // 'PE\0\0'
+ _fileData = fileData;
+ SectionHeaders = new List();
+ ExportedFunctions = new List();
+ ImportDescriptors = new List();
+
+ // Initialize parsers
+ _dosHeaderParser = new DOSHeaderParser();
+ _fileHeaderParser = new FileHeaderParser();
+ _optionalHeaderParser = new OptionalHeaderParser();
+ _sectionHeaderParser = new SectionHeaderParser();
+
+ // Initialize properties to avoid nullability warnings
+ DosHeader = new DOSHeader();
+ FileHeader = new FileHeader();
+ OptionalHeader = new OptionalHeader();
+ ExportDirectory = new ExportDirectory();
+
+ // These will be initialized during Parse()
+ _peUtility = null!;
+ _exportDirectoryParser = null!;
+ _importDescriptorParser = null!;
+ }
- // Optional Header Magic values
- private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
- private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
-
- // Section characteristics flags
- private const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code
- private const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable
- private const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable
- private const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writable
-
- // Data directories
- private const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export Directory
- private const int IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import Directory
- private const int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource Directory
- private const int IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception Directory
- private const int IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security Directory
- private const int IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table
- private const int IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug Directory
- private const int IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; // Architecture Specific Data
- private const int IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // RVA of GP
- private const int IMAGE_DIRECTORY_ENTRY_TLS = 9; // TLS Directory
- private const int IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load Configuration Directory
- private const int IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound Import Directory
- private const int IMAGE_DIRECTORY_ENTRY_IAT = 12; // Import Address Table
- private const int IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay Load Import Descriptors
- private const int IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; // COM Runtime descriptor
-
- // PE file data
- private byte[] _fileData;
-
- // Parser instances
- private readonly DOSHeaderParser _dosHeaderParser;
- private readonly FileHeaderParser _fileHeaderParser;
- private readonly OptionalHeaderParser _optionalHeaderParser;
- private readonly SectionHeaderParser _sectionHeaderParser;
- private PEUtility _peUtility;
- private ExportDirectoryParser _exportDirectoryParser;
- private ImportDescriptorParser _importDescriptorParser;
-
- // Parsed headers
- public DOSHeader DosHeader { get; private set; }
- public FileHeader FileHeader { get; private set; }
- public OptionalHeader OptionalHeader { get; private set; }
- public List SectionHeaders { get; private set; }
- public bool Is64Bit { get; private set; }
-
- // Export and Import information
- public ExportDirectory ExportDirectory { get; private set; }
- public List ExportedFunctions { get; private set; }
- public List ImportDescriptors { get; private set; }
-
- ///
- /// Initializes a new instance of the PEFormat class
- ///
- /// The raw file data
- public PEFormat(byte[] fileData)
+ ///
+ /// Parses the PE file structure
+ ///
+ /// True if parsing was successful, false otherwise
+ public bool Parse()
+ {
+ try
{
- _fileData = fileData;
- SectionHeaders = new List();
- ExportedFunctions = new List();
- ImportDescriptors = new List();
-
- // Initialize parsers
- _dosHeaderParser = new DOSHeaderParser();
- _fileHeaderParser = new FileHeaderParser();
- _optionalHeaderParser = new OptionalHeaderParser();
- _sectionHeaderParser = new SectionHeaderParser();
-
- // Initialize properties to avoid nullability warnings
- DosHeader = new DOSHeader();
- FileHeader = new FileHeader();
- OptionalHeader = new OptionalHeader();
- ExportDirectory = new ExportDirectory();
-
- // These will be initialized during Parse()
- _peUtility = null!;
- _exportDirectoryParser = null!;
- _importDescriptorParser = null!;
- }
-
- ///
- /// Parses the PE file structure
- ///
- /// True if parsing was successful, false otherwise
- public bool Parse()
- {
- try
+ using (MemoryStream stream = new MemoryStream(_fileData))
+ using (BinaryReader reader = new BinaryReader(stream))
{
- using (MemoryStream stream = new MemoryStream(_fileData))
- using (BinaryReader reader = new BinaryReader(stream))
+ // Parse DOS header
+ DosHeader = _dosHeaderParser.Parse(reader);
+
+ // Move to PE header
+ reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
+
+ // Verify PE signature
+ uint peSignature = reader.ReadUInt32();
+ if (peSignature != PE_SIGNATURE)
{
- // Parse DOS header
- DosHeader = _dosHeaderParser.Parse(reader);
+ throw new InvalidDataException("Invalid PE signature");
+ }
- // Move to PE header
- reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
+ // Parse File Header
+ FileHeader = _fileHeaderParser.Parse(reader);
- // Verify PE signature
- uint peSignature = reader.ReadUInt32();
- if (peSignature != PE_SIGNATURE)
- {
- throw new InvalidDataException("Invalid PE signature");
- }
+ // Parse Optional Header
+ OptionalHeader = _optionalHeaderParser.Parse(reader);
+ Is64Bit = OptionalHeader.Is64Bit();
- // Parse File Header
- FileHeader = _fileHeaderParser.Parse(reader);
+ // Parse Section Headers
+ for (int i = 0; i < FileHeader.NumberOfSections; i++)
+ {
+ SectionHeaders.Add(_sectionHeaderParser.Parse(reader));
+ }
- // Parse Optional Header
- OptionalHeader = _optionalHeaderParser.Parse(reader);
- Is64Bit = OptionalHeader.Is64Bit();
+ // Initialize utility after section headers are parsed
+ _peUtility = new PEUtility(SectionHeaders, OptionalHeader.SizeOfHeaders);
+ _exportDirectoryParser = new ExportDirectoryParser(_peUtility);
+ _importDescriptorParser = new ImportDescriptorParser(_peUtility);
- // Parse Section Headers
- for (int i = 0; i < FileHeader.NumberOfSections; i++)
- {
- SectionHeaders.Add(_sectionHeaderParser.Parse(reader));
- }
-
- // Initialize utility after section headers are parsed
- _peUtility = new PEUtility(SectionHeaders, OptionalHeader.SizeOfHeaders);
- _exportDirectoryParser = new ExportDirectoryParser(_peUtility);
- _importDescriptorParser = new ImportDescriptorParser(_peUtility);
-
- // Parse Export Directory
- if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT &&
- OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
- {
- uint exportDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
- uint exportDirSize = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+ // Parse Export Directory
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
+ {
+ uint exportDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ uint exportDirSize = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
- ExportDirectory = _exportDirectoryParser.Parse(reader, exportDirRva);
- ExportedFunctions = _exportDirectoryParser.ParseExportedFunctions(reader, ExportDirectory, exportDirRva, exportDirSize);
- }
+ ExportDirectory = _exportDirectoryParser.Parse(reader, exportDirRva);
+ ExportedFunctions = _exportDirectoryParser.ParseExportedFunctions(reader, ExportDirectory, exportDirRva, exportDirSize);
+ }
- // Parse Import Descriptors
- if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT &&
- OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
- {
- uint importDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
- ImportDescriptors = _importDescriptorParser.Parse(reader, importDirRva);
- }
+ // Parse Import Descriptors
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
+ {
+ uint importDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ ImportDescriptors = _importDescriptorParser.Parse(reader, importDirRva);
}
+ }
- return true;
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Error parsing PE file: {ex.Message}");
- return false;
- }
+ return true;
}
-
- ///
- /// Gets the raw data for a specific section
- ///
- /// Index of the section
- /// Byte array containing the section data
- public byte[] GetSectionData(int sectionIndex)
+ catch (Exception ex)
{
- if (sectionIndex < 0 || sectionIndex >= SectionHeaders.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(sectionIndex));
- }
-
- SectionHeader section = SectionHeaders[sectionIndex];
- byte[] sectionData = new byte[section.SizeOfRawData];
-
- Array.Copy(_fileData, section.PointerToRawData, sectionData, 0, section.SizeOfRawData);
-
- return sectionData;
- }
-
- ///
- /// Gets the raw data for a section by name
- ///
- /// Name of the section
- /// Byte array containing the section data
- public byte[] GetSectionData(string sectionName)
- {
- for (int i = 0; i < SectionHeaders.Count; i++)
- {
- if (SectionHeaders[i].Name == sectionName)
- {
- return GetSectionData(i);
- }
- }
-
- throw new ArgumentException($"Section '{sectionName}' not found");
- }
-
- ///
- /// Gets all code sections
- ///
- /// List of section indices that contain code
- public List GetCodeSections()
- {
- List codeSections = new List();
-
- for (int i = 0; i < SectionHeaders.Count; i++)
- {
- if (SectionHeaders[i].ContainsCode())
- {
- codeSections.Add(i);
- }
- }
-
- return codeSections;
- }
-
- ///
- /// Checks if a section contains code
- ///
- /// The section to check
- /// True if the section contains code, false otherwise
- public bool IsSectionContainsCode(SectionHeader section)
- {
- return section.ContainsCode();
+ Console.WriteLine($"Error parsing PE file: {ex.Message}");
+ return false;
}
}
-}
+
+ ///
+ /// Gets the raw data for a specific section
+ ///
+ /// Index of the section
+ /// Byte array containing the section data
+ public byte[] GetSectionData(int sectionIndex)
+ {
+ if (sectionIndex < 0 || sectionIndex >= SectionHeaders.Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(sectionIndex));
+ }
+
+ SectionHeader section = SectionHeaders[sectionIndex];
+ byte[] sectionData = new byte[section.SizeOfRawData];
+
+ Array.Copy(_fileData, section.PointerToRawData, sectionData, 0, section.SizeOfRawData);
+
+ return sectionData;
+ }
+
+ ///
+ /// Gets the raw data for a section by name
+ ///
+ /// Name of the section
+ /// Byte array containing the section data
+ public byte[] GetSectionData(string sectionName)
+ {
+ for (int i = 0; i < SectionHeaders.Count; i++)
+ {
+ if (SectionHeaders[i].Name == sectionName)
+ {
+ return GetSectionData(i);
+ }
+ }
+
+ throw new ArgumentException($"Section '{sectionName}' not found");
+ }
+
+ ///
+ /// Gets all code sections
+ ///
+ /// List of section indices that contain code
+ public List GetCodeSections()
+ {
+ List codeSections = new List();
+
+ for (int i = 0; i < SectionHeaders.Count; i++)
+ {
+ if (SectionHeaders[i].ContainsCode())
+ {
+ codeSections.Add(i);
+ }
+ }
+
+ return codeSections;
+ }
+
+ ///
+ /// Checks if a section contains code
+ ///
+ /// The section to check
+ /// True if the section contains code, false otherwise
+ public bool IsSectionContainsCode(SectionHeader section)
+ {
+ return section.ContainsCode();
+ }
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/PEUtility.cs b/X86Disassembler/PE/PEUtility.cs
index eea571a..8f9de86 100644
--- a/X86Disassembler/PE/PEUtility.cs
+++ b/X86Disassembler/PE/PEUtility.cs
@@ -1,62 +1,58 @@
-using System;
-using System.Collections.Generic;
+namespace X86Disassembler.PE;
-namespace X86Disassembler.PE
+///
+/// Utility class for PE format operations
+///
+public class PEUtility
{
+ private readonly List _sectionHeaders;
+ private readonly uint _sizeOfHeaders;
+
///
- /// Utility class for PE format operations
+ /// Initialize a new instance of the PEUtility class
///
- public class PEUtility
+ /// The section headers
+ /// The size of the headers
+ public PEUtility(List sectionHeaders, uint sizeOfHeaders)
{
- private readonly List _sectionHeaders;
- private readonly uint _sizeOfHeaders;
+ _sectionHeaders = sectionHeaders;
+ _sizeOfHeaders = sizeOfHeaders;
+ }
- ///
- /// Initialize a new instance of the PEUtility class
- ///
- /// The section headers
- /// The size of the headers
- public PEUtility(List sectionHeaders, uint sizeOfHeaders)
+ ///
+ /// Converts a Relative Virtual Address (RVA) to a file offset
+ ///
+ /// The RVA to convert
+ /// The corresponding file offset
+ public uint RvaToOffset(uint rva)
+ {
+ if (rva == 0)
{
- _sectionHeaders = sectionHeaders;
- _sizeOfHeaders = sizeOfHeaders;
+ return 0;
}
-
- ///
- /// Converts a Relative Virtual Address (RVA) to a file offset
- ///
- /// The RVA to convert
- /// The corresponding file offset
- public uint RvaToOffset(uint rva)
- {
- if (rva == 0)
- {
- return 0;
- }
- foreach (var section in _sectionHeaders)
+ foreach (var section in _sectionHeaders)
+ {
+ // Check if the RVA is within this section
+ if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize)
{
- // Check if the RVA is within this section
- if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize)
- {
- // Calculate the offset within the section
- uint offsetInSection = rva - section.VirtualAddress;
+ // Calculate the offset within the section
+ uint offsetInSection = rva - section.VirtualAddress;
- // Make sure we don't exceed the raw data size
- if (offsetInSection < section.SizeOfRawData)
- {
- return section.PointerToRawData + offsetInSection;
- }
+ // Make sure we don't exceed the raw data size
+ if (offsetInSection < section.SizeOfRawData)
+ {
+ return section.PointerToRawData + offsetInSection;
}
}
-
- // If the RVA is not within any section, it might be in the headers
- if (rva < _sizeOfHeaders)
- {
- return rva;
- }
-
- throw new ArgumentException($"RVA {rva:X8} is not within any section");
}
+
+ // If the RVA is not within any section, it might be in the headers
+ if (rva < _sizeOfHeaders)
+ {
+ return rva;
+ }
+
+ throw new ArgumentException($"RVA {rva:X8} is not within any section");
}
-}
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/Parsers/DOSHeaderParser.cs b/X86Disassembler/PE/Parsers/DOSHeaderParser.cs
index 3cc5427..9699920 100644
--- a/X86Disassembler/PE/Parsers/DOSHeaderParser.cs
+++ b/X86Disassembler/PE/Parsers/DOSHeaderParser.cs
@@ -1,63 +1,59 @@
-using System;
-using System.IO;
+namespace X86Disassembler.PE.Parsers;
-namespace X86Disassembler.PE.Parsers
+///
+/// Parser for the DOS header of a PE file
+///
+public class DOSHeaderParser : IParser
{
+ // DOS Header constants
+ private const ushort DOS_SIGNATURE = 0x5A4D; // 'MZ'
+
///
- /// Parser for the DOS header of a PE file
+ /// Parse the DOS header from the binary reader
///
- public class DOSHeaderParser : IParser
+ /// The binary reader positioned at the start of the DOS header
+ /// The parsed DOS header
+ public DOSHeader Parse(BinaryReader reader)
{
- // DOS Header constants
- private const ushort DOS_SIGNATURE = 0x5A4D; // 'MZ'
+ DOSHeader header = new DOSHeader();
- ///
- /// Parse the DOS header from the binary reader
- ///
- /// The binary reader positioned at the start of the DOS header
- /// The parsed DOS header
- public DOSHeader Parse(BinaryReader reader)
+ header.e_magic = reader.ReadUInt16();
+ if (header.e_magic != DOS_SIGNATURE)
{
- DOSHeader header = new DOSHeader();
-
- header.e_magic = reader.ReadUInt16();
- if (header.e_magic != DOS_SIGNATURE)
- {
- throw new InvalidDataException("Invalid DOS signature (MZ)");
- }
-
- header.e_cblp = reader.ReadUInt16();
- header.e_cp = reader.ReadUInt16();
- header.e_crlc = reader.ReadUInt16();
- header.e_cparhdr = reader.ReadUInt16();
- header.e_minalloc = reader.ReadUInt16();
- header.e_maxalloc = reader.ReadUInt16();
- header.e_ss = reader.ReadUInt16();
- header.e_sp = reader.ReadUInt16();
- header.e_csum = reader.ReadUInt16();
- header.e_ip = reader.ReadUInt16();
- header.e_cs = reader.ReadUInt16();
- header.e_lfarlc = reader.ReadUInt16();
- header.e_ovno = reader.ReadUInt16();
-
- header.e_res = new ushort[4];
- for (int i = 0; i < 4; i++)
- {
- header.e_res[i] = reader.ReadUInt16();
- }
-
- header.e_oemid = reader.ReadUInt16();
- header.e_oeminfo = reader.ReadUInt16();
-
- header.e_res2 = new ushort[10];
- for (int i = 0; i < 10; i++)
- {
- header.e_res2[i] = reader.ReadUInt16();
- }
-
- header.e_lfanew = reader.ReadUInt32();
-
- return header;
+ throw new InvalidDataException("Invalid DOS signature (MZ)");
}
+
+ header.e_cblp = reader.ReadUInt16();
+ header.e_cp = reader.ReadUInt16();
+ header.e_crlc = reader.ReadUInt16();
+ header.e_cparhdr = reader.ReadUInt16();
+ header.e_minalloc = reader.ReadUInt16();
+ header.e_maxalloc = reader.ReadUInt16();
+ header.e_ss = reader.ReadUInt16();
+ header.e_sp = reader.ReadUInt16();
+ header.e_csum = reader.ReadUInt16();
+ header.e_ip = reader.ReadUInt16();
+ header.e_cs = reader.ReadUInt16();
+ header.e_lfarlc = reader.ReadUInt16();
+ header.e_ovno = reader.ReadUInt16();
+
+ header.e_res = new ushort[4];
+ for (int i = 0; i < 4; i++)
+ {
+ header.e_res[i] = reader.ReadUInt16();
+ }
+
+ header.e_oemid = reader.ReadUInt16();
+ header.e_oeminfo = reader.ReadUInt16();
+
+ header.e_res2 = new ushort[10];
+ for (int i = 0; i < 10; i++)
+ {
+ header.e_res2[i] = reader.ReadUInt16();
+ }
+
+ header.e_lfanew = reader.ReadUInt32();
+
+ return header;
}
}
diff --git a/X86Disassembler/PE/Parsers/ExportDirectoryParser.cs b/X86Disassembler/PE/Parsers/ExportDirectoryParser.cs
index 2e71f8b..666947e 100644
--- a/X86Disassembler/PE/Parsers/ExportDirectoryParser.cs
+++ b/X86Disassembler/PE/Parsers/ExportDirectoryParser.cs
@@ -1,176 +1,172 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
using System.Text;
-namespace X86Disassembler.PE.Parsers
+namespace X86Disassembler.PE.Parsers;
+
+///
+/// Parser for the Export Directory of a PE file
+///
+public class ExportDirectoryParser
{
- ///
- /// Parser for the Export Directory of a PE file
- ///
- public class ExportDirectoryParser
+ private readonly PEUtility _utility;
+
+ public ExportDirectoryParser(PEUtility utility)
{
- private readonly PEUtility _utility;
+ _utility = utility;
+ }
+
+ ///
+ /// Parse the Export Directory from the binary reader
+ ///
+ /// The binary reader
+ /// The RVA of the Export Directory
+ /// The parsed Export Directory
+ public ExportDirectory Parse(BinaryReader reader, uint rva)
+ {
+ ExportDirectory directory = new ExportDirectory();
- public ExportDirectoryParser(PEUtility utility)
+ reader.BaseStream.Seek(_utility.RvaToOffset(rva), SeekOrigin.Begin);
+
+ directory.Characteristics = reader.ReadUInt32();
+ directory.TimeDateStamp = reader.ReadUInt32();
+ directory.MajorVersion = reader.ReadUInt16();
+ directory.MinorVersion = reader.ReadUInt16();
+ directory.Name = reader.ReadUInt32();
+ directory.Base = reader.ReadUInt32();
+ directory.NumberOfFunctions = reader.ReadUInt32();
+ directory.NumberOfNames = reader.ReadUInt32();
+ directory.AddressOfFunctions = reader.ReadUInt32();
+ directory.AddressOfNames = reader.ReadUInt32();
+ directory.AddressOfNameOrdinals = reader.ReadUInt32();
+
+ // Read the DLL name
+ try
{
- _utility = utility;
+ uint dllNameRVA = directory.Name;
+ uint dllNameOffset = _utility.RvaToOffset(dllNameRVA);
+ reader.BaseStream.Seek(dllNameOffset, SeekOrigin.Begin);
+
+ // Read the null-terminated ASCII string
+ StringBuilder nameBuilder = new StringBuilder();
+ byte b;
+
+ while ((b = reader.ReadByte()) != 0)
+ {
+ nameBuilder.Append((char)b);
+ }
+
+ directory.DllName = nameBuilder.ToString();
+ }
+ catch (Exception)
+ {
+ directory.DllName = "Unknown";
}
- ///
- /// Parse the Export Directory from the binary reader
- ///
- /// The binary reader
- /// The RVA of the Export Directory
- /// The parsed Export Directory
- public ExportDirectory Parse(BinaryReader reader, uint rva)
- {
- ExportDirectory directory = new ExportDirectory();
-
- reader.BaseStream.Seek(_utility.RvaToOffset(rva), SeekOrigin.Begin);
-
- directory.Characteristics = reader.ReadUInt32();
- directory.TimeDateStamp = reader.ReadUInt32();
- directory.MajorVersion = reader.ReadUInt16();
- directory.MinorVersion = reader.ReadUInt16();
- directory.Name = reader.ReadUInt32();
- directory.Base = reader.ReadUInt32();
- directory.NumberOfFunctions = reader.ReadUInt32();
- directory.NumberOfNames = reader.ReadUInt32();
- directory.AddressOfFunctions = reader.ReadUInt32();
- directory.AddressOfNames = reader.ReadUInt32();
- directory.AddressOfNameOrdinals = reader.ReadUInt32();
-
- // Read the DLL name
- try
- {
- uint dllNameRVA = directory.Name;
- uint dllNameOffset = _utility.RvaToOffset(dllNameRVA);
- reader.BaseStream.Seek(dllNameOffset, SeekOrigin.Begin);
-
- // Read the null-terminated ASCII string
- StringBuilder nameBuilder = new StringBuilder();
- byte b;
-
- while ((b = reader.ReadByte()) != 0)
- {
- nameBuilder.Append((char)b);
- }
-
- directory.DllName = nameBuilder.ToString();
- }
- catch (Exception)
- {
- directory.DllName = "Unknown";
- }
-
- return directory;
- }
+ return directory;
+ }
+
+ ///
+ /// Parse the exported functions using the export directory information
+ ///
+ /// The binary reader
+ /// The Export Directory
+ /// The RVA of the Export Directory
+ /// The size of the Export Directory
+ /// List of exported functions
+ public List ParseExportedFunctions(BinaryReader reader, ExportDirectory directory, uint exportDirRva, uint exportDirSize)
+ {
+ List exportedFunctions = new List();
- ///
- /// Parse the exported functions using the export directory information
- ///
- /// The binary reader
- /// The Export Directory
- /// The RVA of the Export Directory
- /// The size of the Export Directory
- /// List of exported functions
- public List ParseExportedFunctions(BinaryReader reader, ExportDirectory directory, uint exportDirRva, uint exportDirSize)
+ if (directory == null)
{
- List exportedFunctions = new List();
-
- if (directory == null)
- {
- return exportedFunctions;
- }
-
- // Read the array of function addresses (RVAs)
- uint[] functionRVAs = new uint[directory.NumberOfFunctions];
- reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfFunctions), SeekOrigin.Begin);
- for (int i = 0; i < directory.NumberOfFunctions; i++)
- {
- functionRVAs[i] = reader.ReadUInt32();
- }
-
- // Read the array of name RVAs
- uint[] nameRVAs = new uint[directory.NumberOfNames];
- reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNames), SeekOrigin.Begin);
- for (int i = 0; i < directory.NumberOfNames; i++)
- {
- nameRVAs[i] = reader.ReadUInt32();
- }
-
- // Read the array of name ordinals
- ushort[] nameOrdinals = new ushort[directory.NumberOfNames];
- reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNameOrdinals), SeekOrigin.Begin);
- for (int i = 0; i < directory.NumberOfNames; i++)
- {
- nameOrdinals[i] = reader.ReadUInt16();
- }
-
- // Create a dictionary to map ordinals to names
- Dictionary ordinalToName = new Dictionary();
- for (int i = 0; i < directory.NumberOfNames; i++)
- {
- // Read the function name
- reader.BaseStream.Seek(_utility.RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
- List nameBytes = new List();
- byte b;
- while ((b = reader.ReadByte()) != 0)
- {
- nameBytes.Add(b);
- }
- string name = Encoding.ASCII.GetString(nameBytes.ToArray());
-
- // Map the ordinal to the name
- ordinalToName[nameOrdinals[i]] = name;
- }
-
- // Create the exported functions
- for (ushort i = 0; i < directory.NumberOfFunctions; i++)
- {
- uint functionRVA = functionRVAs[i];
- if (functionRVA == 0)
- {
- continue; // Skip empty entries
- }
-
- ExportedFunction function = new ExportedFunction();
- function.Ordinal = (ushort)(i + directory.Base);
- function.Address = functionRVA;
-
- // Check if this function has a name
- if (ordinalToName.TryGetValue(i, out string? name))
- {
- function.Name = name ?? $"Ordinal_{function.Ordinal}";
- }
- else
- {
- function.Name = $"Ordinal_{function.Ordinal}";
- }
-
- // Check if this is a forwarder
- uint exportDirEnd = exportDirRva + exportDirSize;
-
- if (functionRVA >= exportDirRva && functionRVA < exportDirEnd)
- {
- function.IsForwarder = true;
-
- // Read the forwarder string
- reader.BaseStream.Seek(_utility.RvaToOffset(functionRVA), SeekOrigin.Begin);
- List forwarderBytes = new List();
- byte b;
- while ((b = reader.ReadByte()) != 0)
- {
- forwarderBytes.Add(b);
- }
- function.ForwarderName = Encoding.ASCII.GetString(forwarderBytes.ToArray());
- }
-
- exportedFunctions.Add(function);
- }
-
return exportedFunctions;
}
+
+ // Read the array of function addresses (RVAs)
+ uint[] functionRVAs = new uint[directory.NumberOfFunctions];
+ reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfFunctions), SeekOrigin.Begin);
+ for (int i = 0; i < directory.NumberOfFunctions; i++)
+ {
+ functionRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name RVAs
+ uint[] nameRVAs = new uint[directory.NumberOfNames];
+ reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNames), SeekOrigin.Begin);
+ for (int i = 0; i < directory.NumberOfNames; i++)
+ {
+ nameRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name ordinals
+ ushort[] nameOrdinals = new ushort[directory.NumberOfNames];
+ reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNameOrdinals), SeekOrigin.Begin);
+ for (int i = 0; i < directory.NumberOfNames; i++)
+ {
+ nameOrdinals[i] = reader.ReadUInt16();
+ }
+
+ // Create a dictionary to map ordinals to names
+ Dictionary ordinalToName = new Dictionary();
+ for (int i = 0; i < directory.NumberOfNames; i++)
+ {
+ // Read the function name
+ reader.BaseStream.Seek(_utility.RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
+ List nameBytes = new List();
+ byte b;
+ while ((b = reader.ReadByte()) != 0)
+ {
+ nameBytes.Add(b);
+ }
+ string name = Encoding.ASCII.GetString(nameBytes.ToArray());
+
+ // Map the ordinal to the name
+ ordinalToName[nameOrdinals[i]] = name;
+ }
+
+ // Create the exported functions
+ for (ushort i = 0; i < directory.NumberOfFunctions; i++)
+ {
+ uint functionRVA = functionRVAs[i];
+ if (functionRVA == 0)
+ {
+ continue; // Skip empty entries
+ }
+
+ ExportedFunction function = new ExportedFunction();
+ function.Ordinal = (ushort)(i + directory.Base);
+ function.Address = functionRVA;
+
+ // Check if this function has a name
+ if (ordinalToName.TryGetValue(i, out string? name))
+ {
+ function.Name = name ?? $"Ordinal_{function.Ordinal}";
+ }
+ else
+ {
+ function.Name = $"Ordinal_{function.Ordinal}";
+ }
+
+ // Check if this is a forwarder
+ uint exportDirEnd = exportDirRva + exportDirSize;
+
+ if (functionRVA >= exportDirRva && functionRVA < exportDirEnd)
+ {
+ function.IsForwarder = true;
+
+ // Read the forwarder string
+ reader.BaseStream.Seek(_utility.RvaToOffset(functionRVA), SeekOrigin.Begin);
+ List forwarderBytes = new List();
+ byte b;
+ while ((b = reader.ReadByte()) != 0)
+ {
+ forwarderBytes.Add(b);
+ }
+ function.ForwarderName = Encoding.ASCII.GetString(forwarderBytes.ToArray());
+ }
+
+ exportedFunctions.Add(function);
+ }
+
+ return exportedFunctions;
}
}
diff --git a/X86Disassembler/PE/Parsers/FileHeaderParser.cs b/X86Disassembler/PE/Parsers/FileHeaderParser.cs
index 6e4602a..4358815 100644
--- a/X86Disassembler/PE/Parsers/FileHeaderParser.cs
+++ b/X86Disassembler/PE/Parsers/FileHeaderParser.cs
@@ -1,30 +1,27 @@
-using System.IO;
+namespace X86Disassembler.PE.Parsers;
-namespace X86Disassembler.PE.Parsers
+///
+/// Parser for the File header of a PE file
+///
+public class FileHeaderParser : IParser
{
///
- /// Parser for the File header of a PE file
+ /// Parse the File header from the binary reader
///
- public class FileHeaderParser : IParser
+ /// The binary reader positioned at the start of the File header
+ /// The parsed File header
+ public FileHeader Parse(BinaryReader reader)
{
- ///
- /// Parse the File header from the binary reader
- ///
- /// The binary reader positioned at the start of the File header
- /// The parsed File header
- public FileHeader Parse(BinaryReader reader)
- {
- FileHeader header = new FileHeader();
-
- header.Machine = reader.ReadUInt16();
- header.NumberOfSections = reader.ReadUInt16();
- header.TimeDateStamp = reader.ReadUInt32();
- header.PointerToSymbolTable = reader.ReadUInt32();
- header.NumberOfSymbols = reader.ReadUInt32();
- header.SizeOfOptionalHeader = reader.ReadUInt16();
- header.Characteristics = reader.ReadUInt16();
-
- return header;
- }
+ FileHeader header = new FileHeader();
+
+ header.Machine = reader.ReadUInt16();
+ header.NumberOfSections = reader.ReadUInt16();
+ header.TimeDateStamp = reader.ReadUInt32();
+ header.PointerToSymbolTable = reader.ReadUInt32();
+ header.NumberOfSymbols = reader.ReadUInt32();
+ header.SizeOfOptionalHeader = reader.ReadUInt16();
+ header.Characteristics = reader.ReadUInt16();
+
+ return header;
}
}
diff --git a/X86Disassembler/PE/Parsers/IParser.cs b/X86Disassembler/PE/Parsers/IParser.cs
index 72e3b39..cb817e9 100644
--- a/X86Disassembler/PE/Parsers/IParser.cs
+++ b/X86Disassembler/PE/Parsers/IParser.cs
@@ -1,18 +1,15 @@
-using System.IO;
+namespace X86Disassembler.PE.Parsers;
-namespace X86Disassembler.PE.Parsers
+///
+/// Interface for PE format component parsers
+///
+/// The type of component to parse
+public interface IParser
{
///
- /// Interface for PE format component parsers
+ /// Parse a component from the binary reader
///
- /// The type of component to parse
- public interface IParser
- {
- ///
- /// Parse a component from the binary reader
- ///
- /// The binary reader positioned at the start of the component
- /// The parsed component
- T Parse(BinaryReader reader);
- }
+ /// The binary reader positioned at the start of the component
+ /// The parsed component
+ T Parse(BinaryReader reader);
}
diff --git a/X86Disassembler/PE/Parsers/ImportDescriptorParser.cs b/X86Disassembler/PE/Parsers/ImportDescriptorParser.cs
index ed7f741..b6f2f11 100644
--- a/X86Disassembler/PE/Parsers/ImportDescriptorParser.cs
+++ b/X86Disassembler/PE/Parsers/ImportDescriptorParser.cs
@@ -1,192 +1,188 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
using System.Text;
-namespace X86Disassembler.PE.Parsers
+namespace X86Disassembler.PE.Parsers;
+
+///
+/// Parser for Import Descriptors in a PE file
+///
+public class ImportDescriptorParser
{
- ///
- /// Parser for Import Descriptors in a PE file
- ///
- public class ImportDescriptorParser
+ private readonly PEUtility _utility;
+
+ public ImportDescriptorParser(PEUtility utility)
{
- private readonly PEUtility _utility;
+ _utility = utility;
+ }
+
+ ///
+ /// Parse the Import Descriptors from the binary reader
+ ///
+ /// The binary reader
+ /// The RVA of the Import Directory
+ /// List of Import Descriptors
+ public List Parse(BinaryReader reader, uint rva)
+ {
+ List descriptors = new List();
- public ImportDescriptorParser(PEUtility utility)
+ try
{
- _utility = utility;
+ uint importTableOffset = _utility.RvaToOffset(rva);
+ reader.BaseStream.Seek(importTableOffset, SeekOrigin.Begin);
+
+ int descriptorCount = 0;
+
+ while (true)
+ {
+ descriptorCount++;
+
+ // Read the import descriptor
+ uint originalFirstThunk = reader.ReadUInt32();
+ uint timeDateStamp = reader.ReadUInt32();
+ uint forwarderChain = reader.ReadUInt32();
+ uint nameRva = reader.ReadUInt32();
+ uint firstThunk = reader.ReadUInt32();
+
+ // Check if we've reached the end of the import descriptors
+ if (originalFirstThunk == 0 && nameRva == 0 && firstThunk == 0)
+ {
+ break;
+ }
+
+ ImportDescriptor descriptor = new ImportDescriptor
+ {
+ OriginalFirstThunk = originalFirstThunk,
+ TimeDateStamp = timeDateStamp,
+ ForwarderChain = forwarderChain,
+ Name = nameRva,
+ FirstThunk = firstThunk,
+ DllName = "Unknown" // Default name in case we can't read it
+ };
+
+ // Try to read the DLL name
+ try
+ {
+ if (nameRva != 0)
+ {
+ uint nameOffset = _utility.RvaToOffset(nameRva);
+ reader.BaseStream.Seek(nameOffset, SeekOrigin.Begin);
+
+ // Read the null-terminated ASCII string
+ StringBuilder nameBuilder = new StringBuilder();
+ byte b;
+
+ while ((b = reader.ReadByte()) != 0)
+ {
+ nameBuilder.Append((char)b);
+ }
+
+ descriptor.DllName = nameBuilder.ToString();
+ }
+ }
+ catch (Exception)
+ {
+ // If we can't read the name, keep the default "Unknown"
+ }
+
+ // Parse the imported functions
+ ParseImportedFunctions(reader, descriptor);
+
+ descriptors.Add(descriptor);
+
+ // Return to the import table to read the next descriptor
+ reader.BaseStream.Seek(importTableOffset + (descriptorCount * 20), SeekOrigin.Begin);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error parsing import descriptors: {ex.Message}");
+ // Return whatever descriptors we've managed to parse
}
- ///
- /// Parse the Import Descriptors from the binary reader
- ///
- /// The binary reader
- /// The RVA of the Import Directory
- /// List of Import Descriptors
- public List Parse(BinaryReader reader, uint rva)
+ return descriptors;
+ }
+
+ ///
+ /// Parse the imported functions for a given import descriptor
+ ///
+ /// The binary reader
+ /// The Import Descriptor
+ private void ParseImportedFunctions(BinaryReader reader, ImportDescriptor descriptor)
+ {
+ try
{
- List descriptors = new List();
+ // Use OriginalFirstThunk if available, otherwise use FirstThunk
+ uint thunkRva = descriptor.OriginalFirstThunk != 0 ? descriptor.OriginalFirstThunk : descriptor.FirstThunk;
- try
+ if (thunkRva == 0)
{
- uint importTableOffset = _utility.RvaToOffset(rva);
- reader.BaseStream.Seek(importTableOffset, SeekOrigin.Begin);
+ return; // No functions to parse
+ }
+
+ uint thunkOffset = _utility.RvaToOffset(thunkRva);
+ int functionCount = 0;
+
+ while (true)
+ {
+ reader.BaseStream.Seek(thunkOffset + (functionCount * 4), SeekOrigin.Begin);
+ uint thunkData = reader.ReadUInt32();
- int descriptorCount = 0;
-
- while (true)
+ if (thunkData == 0)
{
- descriptorCount++;
-
- // Read the import descriptor
- uint originalFirstThunk = reader.ReadUInt32();
- uint timeDateStamp = reader.ReadUInt32();
- uint forwarderChain = reader.ReadUInt32();
- uint nameRva = reader.ReadUInt32();
- uint firstThunk = reader.ReadUInt32();
-
- // Check if we've reached the end of the import descriptors
- if (originalFirstThunk == 0 && nameRva == 0 && firstThunk == 0)
- {
- break;
- }
-
- ImportDescriptor descriptor = new ImportDescriptor
- {
- OriginalFirstThunk = originalFirstThunk,
- TimeDateStamp = timeDateStamp,
- ForwarderChain = forwarderChain,
- Name = nameRva,
- FirstThunk = firstThunk,
- DllName = "Unknown" // Default name in case we can't read it
- };
-
- // Try to read the DLL name
+ break; // End of the function list
+ }
+
+ ImportedFunction function = new ImportedFunction
+ {
+ ThunkRVA = thunkRva + (uint)(functionCount * 4)
+ };
+
+ // Check if imported by ordinal (high bit set)
+ if ((thunkData & 0x80000000) != 0)
+ {
+ function.IsOrdinal = true;
+ function.Ordinal = (ushort)(thunkData & 0xFFFF);
+ function.Name = $"Ordinal {function.Ordinal}";
+ }
+ else
+ {
+ // Imported by name - the thunkData is an RVA to a hint/name structure
try
{
- if (nameRva != 0)
+ uint hintNameOffset = _utility.RvaToOffset(thunkData);
+ reader.BaseStream.Seek(hintNameOffset, SeekOrigin.Begin);
+
+ // Read the hint (2 bytes)
+ function.Hint = reader.ReadUInt16();
+
+ // Read the function name (null-terminated ASCII string)
+ StringBuilder nameBuilder = new StringBuilder();
+ byte b;
+
+ while ((b = reader.ReadByte()) != 0)
{
- uint nameOffset = _utility.RvaToOffset(nameRva);
- reader.BaseStream.Seek(nameOffset, SeekOrigin.Begin);
-
- // Read the null-terminated ASCII string
- StringBuilder nameBuilder = new StringBuilder();
- byte b;
-
- while ((b = reader.ReadByte()) != 0)
- {
- nameBuilder.Append((char)b);
- }
-
- descriptor.DllName = nameBuilder.ToString();
+ nameBuilder.Append((char)b);
}
- }
- catch (Exception)
- {
- // If we can't read the name, keep the default "Unknown"
- }
-
- // Parse the imported functions
- ParseImportedFunctions(reader, descriptor);
-
- descriptors.Add(descriptor);
-
- // Return to the import table to read the next descriptor
- reader.BaseStream.Seek(importTableOffset + (descriptorCount * 20), SeekOrigin.Begin);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Error parsing import descriptors: {ex.Message}");
- // Return whatever descriptors we've managed to parse
- }
-
- return descriptors;
- }
-
- ///
- /// Parse the imported functions for a given import descriptor
- ///
- /// The binary reader
- /// The Import Descriptor
- private void ParseImportedFunctions(BinaryReader reader, ImportDescriptor descriptor)
- {
- try
- {
- // Use OriginalFirstThunk if available, otherwise use FirstThunk
- uint thunkRva = descriptor.OriginalFirstThunk != 0 ? descriptor.OriginalFirstThunk : descriptor.FirstThunk;
-
- if (thunkRva == 0)
- {
- return; // No functions to parse
- }
-
- uint thunkOffset = _utility.RvaToOffset(thunkRva);
- int functionCount = 0;
-
- while (true)
- {
- reader.BaseStream.Seek(thunkOffset + (functionCount * 4), SeekOrigin.Begin);
- uint thunkData = reader.ReadUInt32();
-
- if (thunkData == 0)
- {
- break; // End of the function list
- }
-
- ImportedFunction function = new ImportedFunction
- {
- ThunkRVA = thunkRva + (uint)(functionCount * 4)
- };
-
- // Check if imported by ordinal (high bit set)
- if ((thunkData & 0x80000000) != 0)
- {
- function.IsOrdinal = true;
- function.Ordinal = (ushort)(thunkData & 0xFFFF);
- function.Name = $"Ordinal {function.Ordinal}";
- }
- else
- {
- // Imported by name - the thunkData is an RVA to a hint/name structure
- try
- {
- uint hintNameOffset = _utility.RvaToOffset(thunkData);
- reader.BaseStream.Seek(hintNameOffset, SeekOrigin.Begin);
-
- // Read the hint (2 bytes)
- function.Hint = reader.ReadUInt16();
-
- // Read the function name (null-terminated ASCII string)
- StringBuilder nameBuilder = new StringBuilder();
- byte b;
-
- while ((b = reader.ReadByte()) != 0)
- {
- nameBuilder.Append((char)b);
- }
-
- function.Name = nameBuilder.ToString();
-
- if (string.IsNullOrEmpty(function.Name))
- {
- function.Name = $"Function_at_{thunkData:X8}";
- }
- }
- catch (Exception)
+
+ function.Name = nameBuilder.ToString();
+
+ if (string.IsNullOrEmpty(function.Name))
{
function.Name = $"Function_at_{thunkData:X8}";
}
}
-
- descriptor.Functions.Add(function);
- functionCount++;
+ catch (Exception)
+ {
+ function.Name = $"Function_at_{thunkData:X8}";
+ }
}
+
+ descriptor.Functions.Add(function);
+ functionCount++;
}
- catch (Exception ex)
- {
- Console.WriteLine($"Error parsing imported functions for {descriptor.DllName}: {ex.Message}");
- }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error parsing imported functions for {descriptor.DllName}: {ex.Message}");
}
}
}
diff --git a/X86Disassembler/PE/Parsers/OptionalHeaderParser.cs b/X86Disassembler/PE/Parsers/OptionalHeaderParser.cs
index c1f1a0a..7f75a51 100644
--- a/X86Disassembler/PE/Parsers/OptionalHeaderParser.cs
+++ b/X86Disassembler/PE/Parsers/OptionalHeaderParser.cs
@@ -1,114 +1,110 @@
-using System;
-using System.IO;
+namespace X86Disassembler.PE.Parsers;
-namespace X86Disassembler.PE.Parsers
+///
+/// Parser for the Optional header of a PE file
+///
+public class OptionalHeaderParser : IParser
{
+ // Optional Header Magic values
+ private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
+ private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
+
///
- /// Parser for the Optional header of a PE file
+ /// Parse the Optional header from the binary reader
///
- public class OptionalHeaderParser : IParser
+ /// The binary reader positioned at the start of the Optional header
+ /// The parsed Optional header
+ public OptionalHeader Parse(BinaryReader reader)
{
- // Optional Header Magic values
- private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
- private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
-
- ///
- /// Parse the Optional header from the binary reader
- ///
- /// The binary reader positioned at the start of the Optional header
- /// The parsed Optional header
- public OptionalHeader Parse(BinaryReader reader)
+ OptionalHeader header = new OptionalHeader();
+ bool is64Bit;
+
+ // Standard fields
+ header.Magic = reader.ReadUInt16();
+
+ // Determine if this is a PE32 or PE32+ file
+ is64Bit = header.Magic == PE32PLUS_MAGIC;
+
+ header.MajorLinkerVersion = reader.ReadByte();
+ header.MinorLinkerVersion = reader.ReadByte();
+ header.SizeOfCode = reader.ReadUInt32();
+ header.SizeOfInitializedData = reader.ReadUInt32();
+ header.SizeOfUninitializedData = reader.ReadUInt32();
+ header.AddressOfEntryPoint = reader.ReadUInt32();
+ header.BaseOfCode = reader.ReadUInt32();
+
+ // PE32 has BaseOfData, PE32+ doesn't
+ if (!is64Bit)
{
- OptionalHeader header = new OptionalHeader();
- bool is64Bit;
-
- // Standard fields
- header.Magic = reader.ReadUInt16();
-
- // Determine if this is a PE32 or PE32+ file
- is64Bit = header.Magic == PE32PLUS_MAGIC;
-
- header.MajorLinkerVersion = reader.ReadByte();
- header.MinorLinkerVersion = reader.ReadByte();
- header.SizeOfCode = reader.ReadUInt32();
- header.SizeOfInitializedData = reader.ReadUInt32();
- header.SizeOfUninitializedData = reader.ReadUInt32();
- header.AddressOfEntryPoint = reader.ReadUInt32();
- header.BaseOfCode = reader.ReadUInt32();
-
- // PE32 has BaseOfData, PE32+ doesn't
- if (!is64Bit)
- {
- header.BaseOfData = reader.ReadUInt32();
- }
-
- // Windows-specific fields
- if (is64Bit)
- {
- header.ImageBase = reader.ReadUInt64();
- }
- else
- {
- header.ImageBase = reader.ReadUInt32();
- }
-
- header.SectionAlignment = reader.ReadUInt32();
- header.FileAlignment = reader.ReadUInt32();
- header.MajorOperatingSystemVersion = reader.ReadUInt16();
- header.MinorOperatingSystemVersion = reader.ReadUInt16();
- header.MajorImageVersion = reader.ReadUInt16();
- header.MinorImageVersion = reader.ReadUInt16();
- header.MajorSubsystemVersion = reader.ReadUInt16();
- header.MinorSubsystemVersion = reader.ReadUInt16();
- header.Win32VersionValue = reader.ReadUInt32();
- header.SizeOfImage = reader.ReadUInt32();
- header.SizeOfHeaders = reader.ReadUInt32();
- header.CheckSum = reader.ReadUInt32();
- header.Subsystem = reader.ReadUInt16();
- header.DllCharacteristics = reader.ReadUInt16();
-
- // Size fields differ between PE32 and PE32+
- if (is64Bit)
- {
- header.SizeOfStackReserve = reader.ReadUInt64();
- header.SizeOfStackCommit = reader.ReadUInt64();
- header.SizeOfHeapReserve = reader.ReadUInt64();
- header.SizeOfHeapCommit = reader.ReadUInt64();
- }
- else
- {
- header.SizeOfStackReserve = reader.ReadUInt32();
- header.SizeOfStackCommit = reader.ReadUInt32();
- header.SizeOfHeapReserve = reader.ReadUInt32();
- header.SizeOfHeapCommit = reader.ReadUInt32();
- }
-
- header.LoaderFlags = reader.ReadUInt32();
- header.NumberOfRvaAndSizes = reader.ReadUInt32();
-
- // Data directories
- int numDirectories = (int)Math.Min(header.NumberOfRvaAndSizes, 16); // Maximum of 16 directories
- header.DataDirectories = new DataDirectory[numDirectories];
-
- for (int i = 0; i < numDirectories; i++)
- {
- DataDirectory dir = new DataDirectory();
- dir.VirtualAddress = reader.ReadUInt32();
- dir.Size = reader.ReadUInt32();
- header.DataDirectories[i] = dir;
- }
-
- return header;
+ header.BaseOfData = reader.ReadUInt32();
}
-
- ///
- /// Determines if the PE file is 64-bit based on the Optional header
- ///
- /// The Optional header
- /// True if the PE file is 64-bit, false otherwise
- public bool Is64Bit(OptionalHeader header)
+
+ // Windows-specific fields
+ if (is64Bit)
{
- return header.Magic == PE32PLUS_MAGIC;
+ header.ImageBase = reader.ReadUInt64();
}
+ else
+ {
+ header.ImageBase = reader.ReadUInt32();
+ }
+
+ header.SectionAlignment = reader.ReadUInt32();
+ header.FileAlignment = reader.ReadUInt32();
+ header.MajorOperatingSystemVersion = reader.ReadUInt16();
+ header.MinorOperatingSystemVersion = reader.ReadUInt16();
+ header.MajorImageVersion = reader.ReadUInt16();
+ header.MinorImageVersion = reader.ReadUInt16();
+ header.MajorSubsystemVersion = reader.ReadUInt16();
+ header.MinorSubsystemVersion = reader.ReadUInt16();
+ header.Win32VersionValue = reader.ReadUInt32();
+ header.SizeOfImage = reader.ReadUInt32();
+ header.SizeOfHeaders = reader.ReadUInt32();
+ header.CheckSum = reader.ReadUInt32();
+ header.Subsystem = reader.ReadUInt16();
+ header.DllCharacteristics = reader.ReadUInt16();
+
+ // Size fields differ between PE32 and PE32+
+ if (is64Bit)
+ {
+ header.SizeOfStackReserve = reader.ReadUInt64();
+ header.SizeOfStackCommit = reader.ReadUInt64();
+ header.SizeOfHeapReserve = reader.ReadUInt64();
+ header.SizeOfHeapCommit = reader.ReadUInt64();
+ }
+ else
+ {
+ header.SizeOfStackReserve = reader.ReadUInt32();
+ header.SizeOfStackCommit = reader.ReadUInt32();
+ header.SizeOfHeapReserve = reader.ReadUInt32();
+ header.SizeOfHeapCommit = reader.ReadUInt32();
+ }
+
+ header.LoaderFlags = reader.ReadUInt32();
+ header.NumberOfRvaAndSizes = reader.ReadUInt32();
+
+ // Data directories
+ int numDirectories = (int)Math.Min(header.NumberOfRvaAndSizes, 16); // Maximum of 16 directories
+ header.DataDirectories = new DataDirectory[numDirectories];
+
+ for (int i = 0; i < numDirectories; i++)
+ {
+ DataDirectory dir = new DataDirectory();
+ dir.VirtualAddress = reader.ReadUInt32();
+ dir.Size = reader.ReadUInt32();
+ header.DataDirectories[i] = dir;
+ }
+
+ return header;
}
-}
+
+ ///
+ /// Determines if the PE file is 64-bit based on the Optional header
+ ///
+ /// The Optional header
+ /// True if the PE file is 64-bit, false otherwise
+ public bool Is64Bit(OptionalHeader header)
+ {
+ return header.Magic == PE32PLUS_MAGIC;
+ }
+}
\ No newline at end of file
diff --git a/X86Disassembler/PE/Parsers/SectionHeaderParser.cs b/X86Disassembler/PE/Parsers/SectionHeaderParser.cs
index 8106c65..d55f358 100644
--- a/X86Disassembler/PE/Parsers/SectionHeaderParser.cs
+++ b/X86Disassembler/PE/Parsers/SectionHeaderParser.cs
@@ -1,38 +1,36 @@
-using System.IO;
using System.Text;
-namespace X86Disassembler.PE.Parsers
+namespace X86Disassembler.PE.Parsers;
+
+///
+/// Parser for section headers in a PE file
+///
+public class SectionHeaderParser : IParser
{
///
- /// Parser for section headers in a PE file
+ /// Parse a section header from the binary reader
///
- public class SectionHeaderParser : IParser
+ /// The binary reader positioned at the start of the section header
+ /// The parsed section header
+ public SectionHeader Parse(BinaryReader reader)
{
- ///
- /// Parse a section header from the binary reader
- ///
- /// The binary reader positioned at the start of the section header
- /// The parsed section header
- public SectionHeader Parse(BinaryReader reader)
- {
- SectionHeader header = new SectionHeader();
-
- // Read section name (8 bytes)
- byte[] nameBytes = reader.ReadBytes(8);
- // Convert to string, removing any null characters
- header.Name = Encoding.ASCII.GetString(nameBytes).TrimEnd('\0');
-
- header.VirtualSize = reader.ReadUInt32();
- header.VirtualAddress = reader.ReadUInt32();
- header.SizeOfRawData = reader.ReadUInt32();
- header.PointerToRawData = reader.ReadUInt32();
- header.PointerToRelocations = reader.ReadUInt32();
- header.PointerToLinenumbers = reader.ReadUInt32();
- header.NumberOfRelocations = reader.ReadUInt16();
- header.NumberOfLinenumbers = reader.ReadUInt16();
- header.Characteristics = reader.ReadUInt32();
-
- return header;
- }
+ SectionHeader header = new SectionHeader();
+
+ // Read section name (8 bytes)
+ byte[] nameBytes = reader.ReadBytes(8);
+ // Convert to string, removing any null characters
+ header.Name = Encoding.ASCII.GetString(nameBytes).TrimEnd('\0');
+
+ header.VirtualSize = reader.ReadUInt32();
+ header.VirtualAddress = reader.ReadUInt32();
+ header.SizeOfRawData = reader.ReadUInt32();
+ header.PointerToRawData = reader.ReadUInt32();
+ header.PointerToRelocations = reader.ReadUInt32();
+ header.PointerToLinenumbers = reader.ReadUInt32();
+ header.NumberOfRelocations = reader.ReadUInt16();
+ header.NumberOfLinenumbers = reader.ReadUInt16();
+ header.Characteristics = reader.ReadUInt32();
+
+ return header;
}
}
diff --git a/X86Disassembler/PE/SectionHeader.cs b/X86Disassembler/PE/SectionHeader.cs
index 62cfb9a..f2fac15 100644
--- a/X86Disassembler/PE/SectionHeader.cs
+++ b/X86Disassembler/PE/SectionHeader.cs
@@ -1,71 +1,70 @@
-namespace X86Disassembler.PE
+namespace X86Disassembler.PE;
+
+///
+/// Represents a section header in a PE file
+///
+public class SectionHeader
{
+ // Section characteristics flags
+ private const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code
+ private const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable
+ private const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable
+ private const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writable
+
+ public string Name; // Section name
+ public uint VirtualSize; // Virtual size
+ public uint VirtualAddress; // Virtual address
+ public uint SizeOfRawData; // Size of raw data
+ public uint PointerToRawData; // Pointer to raw data
+ public uint PointerToRelocations; // Pointer to relocations
+ public uint PointerToLinenumbers; // Pointer to line numbers
+ public ushort NumberOfRelocations; // Number of relocations
+ public ushort NumberOfLinenumbers; // Number of line numbers
+ public uint Characteristics; // Characteristics
+
///
- /// Represents a section header in a PE file
+ /// Initializes a new instance of the SectionHeader class
///
- public class SectionHeader
+ public SectionHeader()
{
- // Section characteristics flags
- private const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code
- private const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable
- private const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable
- private const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writable
-
- public string Name; // Section name
- public uint VirtualSize; // Virtual size
- public uint VirtualAddress; // Virtual address
- public uint SizeOfRawData; // Size of raw data
- public uint PointerToRawData; // Pointer to raw data
- public uint PointerToRelocations; // Pointer to relocations
- public uint PointerToLinenumbers; // Pointer to line numbers
- public ushort NumberOfRelocations; // Number of relocations
- public ushort NumberOfLinenumbers; // Number of line numbers
- public uint Characteristics; // Characteristics
-
- ///
- /// Initializes a new instance of the SectionHeader class
- ///
- public SectionHeader()
- {
- // Initialize string field to avoid nullability warning
- Name = string.Empty;
- }
-
- ///
- /// Checks if the section contains code
- ///
- /// True if the section contains code, false otherwise
- public bool ContainsCode()
- {
- return (Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
- (Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
- }
-
- ///
- /// Checks if the section is readable
- ///
- /// True if the section is readable, false otherwise
- public bool IsReadable()
- {
- return (Characteristics & IMAGE_SCN_MEM_READ) != 0;
- }
-
- ///
- /// Checks if the section is writable
- ///
- /// True if the section is writable, false otherwise
- public bool IsWritable()
- {
- return (Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
- }
-
- ///
- /// Checks if the section is executable
- ///
- /// True if the section is executable, false otherwise
- public bool IsExecutable()
- {
- return (Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
- }
+ // Initialize string field to avoid nullability warning
+ Name = string.Empty;
}
-}
+
+ ///
+ /// Checks if the section contains code
+ ///
+ /// True if the section contains code, false otherwise
+ public bool ContainsCode()
+ {
+ return (Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
+ (Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
+ }
+
+ ///
+ /// Checks if the section is readable
+ ///
+ /// True if the section is readable, false otherwise
+ public bool IsReadable()
+ {
+ return (Characteristics & IMAGE_SCN_MEM_READ) != 0;
+ }
+
+ ///
+ /// Checks if the section is writable
+ ///
+ /// True if the section is writable, false otherwise
+ public bool IsWritable()
+ {
+ return (Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
+ }
+
+ ///
+ /// Checks if the section is executable
+ ///
+ /// True if the section is executable, false otherwise
+ public bool IsExecutable()
+ {
+ return (Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
+ }
+}
\ No newline at end of file
diff --git a/X86Disassembler/Program.cs b/X86Disassembler/Program.cs
index cacd76c..1077eeb 100644
--- a/X86Disassembler/Program.cs
+++ b/X86Disassembler/Program.cs
@@ -1,148 +1,145 @@
-using System;
-using System.IO;
using X86Disassembler.PE;
-namespace X86Disassembler
+namespace X86Disassembler;
+
+internal class Program
{
- internal class Program
+ // Path to the DLL file to disassemble
+ private const string DllPath = @"C:\Program Files (x86)\Nikita\Iron Strategy\Terrain.dll"; // Example path, replace with your target DLL
+
+ static void Main(string[] args)
{
- // Path to the DLL file to disassemble
- private const string DllPath = @"C:\Program Files (x86)\Nikita\Iron Strategy\Terrain.dll"; // Example path, replace with your target DLL
-
- static void Main(string[] args)
+ Console.WriteLine("X86 Disassembler and Decompiler");
+ Console.WriteLine("--------------------------------");
+
+ Console.WriteLine($"Loading file: {DllPath}");
+
+ // Load the DLL file
+ byte[] binaryData = File.ReadAllBytes(DllPath);
+
+ Console.WriteLine($"Successfully loaded {DllPath}");
+ Console.WriteLine($"File size: {binaryData.Length} bytes");
+
+ // Create the PE format parser
+ PEFormat peFile = new PEFormat(binaryData);
+
+ // Parse the PE format
+ Console.WriteLine("\nParsing PE format...");
+ if (!peFile.Parse())
{
- Console.WriteLine("X86 Disassembler and Decompiler");
- Console.WriteLine("--------------------------------");
-
- Console.WriteLine($"Loading file: {DllPath}");
-
- // Load the DLL file
- byte[] binaryData = File.ReadAllBytes(DllPath);
-
- Console.WriteLine($"Successfully loaded {DllPath}");
- Console.WriteLine($"File size: {binaryData.Length} bytes");
-
- // Create the PE format parser
- PEFormat peFile = new PEFormat(binaryData);
-
- // Parse the PE format
- Console.WriteLine("\nParsing PE format...");
- if (!peFile.Parse())
- {
- Console.WriteLine("Failed to parse PE file. Exiting.");
- return;
- }
-
- // Display basic PE information
- DisplayPEInfo(peFile);
-
- // Display exported functions
- DisplayExportedFunctions(peFile);
-
- // Display imported functions
- DisplayImportedFunctions(peFile);
-
- // Find code sections for disassembly
- var codeSections = peFile.GetCodeSections();
- Console.WriteLine($"\nFound {codeSections.Count} code section(s):");
-
- foreach (int sectionIndex in codeSections)
- {
- var section = peFile.SectionHeaders[sectionIndex];
- Console.WriteLine($" - {section.Name}: Size={section.SizeOfRawData} bytes, RVA=0x{section.VirtualAddress:X8}");
-
- // Get the section data for disassembly
- byte[] sectionData = peFile.GetSectionData(sectionIndex);
-
- // TODO: Implement disassembling logic here
- // This is where we would pass the section data to our disassembler
- }
-
- Console.WriteLine("\nPress any key to exit...");
- Console.ReadKey();
+ Console.WriteLine("Failed to parse PE file. Exiting.");
+ return;
}
-
- private static void DisplayPEInfo(PEFormat peFile)
- {
- Console.WriteLine("\nPE File Information:");
- Console.WriteLine($"Architecture: {(peFile.Is64Bit ? "64-bit" : "32-bit")}");
- Console.WriteLine($"Entry Point: 0x{peFile.OptionalHeader.AddressOfEntryPoint:X8}");
- Console.WriteLine($"Image Base: 0x{peFile.OptionalHeader.ImageBase:X}");
- Console.WriteLine($"Number of Sections: {peFile.FileHeader.NumberOfSections}");
- // Display section information
- Console.WriteLine("\nSections:");
- for (int i = 0; i < peFile.SectionHeaders.Count; i++)
- {
- var section = peFile.SectionHeaders[i];
- string flags = "";
+ // Display basic PE information
+ DisplayPEInfo(peFile);
+
+ // Display exported functions
+ DisplayExportedFunctions(peFile);
+
+ // Display imported functions
+ DisplayImportedFunctions(peFile);
+
+ // Find code sections for disassembly
+ var codeSections = peFile.GetCodeSections();
+ Console.WriteLine($"\nFound {codeSections.Count} code section(s):");
+
+ foreach (int sectionIndex in codeSections)
+ {
+ var section = peFile.SectionHeaders[sectionIndex];
+ Console.WriteLine($" - {section.Name}: Size={section.SizeOfRawData} bytes, RVA=0x{section.VirtualAddress:X8}");
- if ((section.Characteristics & 0x00000020) != 0) flags += "Code "; // IMAGE_SCN_CNT_CODE
- if ((section.Characteristics & 0x20000000) != 0) flags += "Exec "; // IMAGE_SCN_MEM_EXECUTE
- if ((section.Characteristics & 0x40000000) != 0) flags += "Read "; // IMAGE_SCN_MEM_READ
- if ((section.Characteristics & 0x80000000) != 0) flags += "Write"; // IMAGE_SCN_MEM_WRITE
+ // Get the section data for disassembly
+ byte[] sectionData = peFile.GetSectionData(sectionIndex);
- Console.WriteLine($" {i}: {section.Name,-8} VA=0x{section.VirtualAddress:X8} Size={section.SizeOfRawData,-8} [{flags}]");
- }
+ // TODO: Implement disassembling logic here
+ // This is where we would pass the section data to our disassembler
}
+
+ Console.WriteLine("\nPress any key to exit...");
+ Console.ReadKey();
+ }
- private static void DisplayExportedFunctions(PEFormat peFile)
+ private static void DisplayPEInfo(PEFormat peFile)
+ {
+ Console.WriteLine("\nPE File Information:");
+ Console.WriteLine($"Architecture: {(peFile.Is64Bit ? "64-bit" : "32-bit")}");
+ Console.WriteLine($"Entry Point: 0x{peFile.OptionalHeader.AddressOfEntryPoint:X8}");
+ Console.WriteLine($"Image Base: 0x{peFile.OptionalHeader.ImageBase:X}");
+ Console.WriteLine($"Number of Sections: {peFile.FileHeader.NumberOfSections}");
+
+ // Display section information
+ Console.WriteLine("\nSections:");
+ for (int i = 0; i < peFile.SectionHeaders.Count; i++)
{
- if (peFile.ExportDirectory == null)
- {
- Console.WriteLine("\nNo exported functions found.");
- return;
- }
-
- Console.WriteLine("\nExported Functions:");
- Console.WriteLine($"DLL Name: {peFile.ExportDirectory.DllName}");
- Console.WriteLine($"Number of Functions: {peFile.ExportDirectory.NumberOfFunctions}");
- Console.WriteLine($"Number of Names: {peFile.ExportDirectory.NumberOfNames}");
-
- // Display all exported functions
- for (int i = 0; i < peFile.ExportedFunctions.Count; i++)
- {
- var function = peFile.ExportedFunctions[i];
- Console.WriteLine($" {i}: {function.Name} (Ordinal={function.Ordinal}, RVA=0x{function.Address:X8})");
- }
- }
-
- private static void DisplayImportedFunctions(PEFormat peFile)
- {
- if (peFile.ImportDescriptors.Count == 0)
- {
- Console.WriteLine("\nNo imported functions found.");
- return;
- }
-
- Console.WriteLine("\nImported Functions:");
- Console.WriteLine($"Number of Imported DLLs: {peFile.ImportDescriptors.Count}");
-
- // Display all imported DLLs and their functions
- for (int i = 0; i < peFile.ImportDescriptors.Count; i++)
- {
- var descriptor = peFile.ImportDescriptors[i];
- Console.WriteLine($" DLL: {descriptor.DllName}");
+ var section = peFile.SectionHeaders[i];
+ string flags = "";
- // Display all functions from this DLL
- for (int j = 0; j < descriptor.Functions.Count; j++)
+ if ((section.Characteristics & 0x00000020) != 0) flags += "Code "; // IMAGE_SCN_CNT_CODE
+ if ((section.Characteristics & 0x20000000) != 0) flags += "Exec "; // IMAGE_SCN_MEM_EXECUTE
+ if ((section.Characteristics & 0x40000000) != 0) flags += "Read "; // IMAGE_SCN_MEM_READ
+ if ((section.Characteristics & 0x80000000) != 0) flags += "Write"; // IMAGE_SCN_MEM_WRITE
+
+ Console.WriteLine($" {i}: {section.Name,-8} VA=0x{section.VirtualAddress:X8} Size={section.SizeOfRawData,-8} [{flags}]");
+ }
+ }
+
+ private static void DisplayExportedFunctions(PEFormat peFile)
+ {
+ if (peFile.ExportDirectory == null)
+ {
+ Console.WriteLine("\nNo exported functions found.");
+ return;
+ }
+
+ Console.WriteLine("\nExported Functions:");
+ Console.WriteLine($"DLL Name: {peFile.ExportDirectory.DllName}");
+ Console.WriteLine($"Number of Functions: {peFile.ExportDirectory.NumberOfFunctions}");
+ Console.WriteLine($"Number of Names: {peFile.ExportDirectory.NumberOfNames}");
+
+ // Display all exported functions
+ for (int i = 0; i < peFile.ExportedFunctions.Count; i++)
+ {
+ var function = peFile.ExportedFunctions[i];
+ Console.WriteLine($" {i}: {function.Name} (Ordinal={function.Ordinal}, RVA=0x{function.Address:X8})");
+ }
+ }
+
+ private static void DisplayImportedFunctions(PEFormat peFile)
+ {
+ if (peFile.ImportDescriptors.Count == 0)
+ {
+ Console.WriteLine("\nNo imported functions found.");
+ return;
+ }
+
+ Console.WriteLine("\nImported Functions:");
+ Console.WriteLine($"Number of Imported DLLs: {peFile.ImportDescriptors.Count}");
+
+ // Display all imported DLLs and their functions
+ for (int i = 0; i < peFile.ImportDescriptors.Count; i++)
+ {
+ var descriptor = peFile.ImportDescriptors[i];
+ Console.WriteLine($" DLL: {descriptor.DllName}");
+
+ // Display all functions from this DLL
+ for (int j = 0; j < descriptor.Functions.Count; j++)
+ {
+ var function = descriptor.Functions[j];
+ if (function.IsOrdinal)
{
- var function = descriptor.Functions[j];
- if (function.IsOrdinal)
- {
- Console.WriteLine($" {j}: Ordinal {function.Ordinal}");
- }
- else
- {
- Console.WriteLine($" {j}: {function.Name} (Hint={function.Hint})");
- }
+ Console.WriteLine($" {j}: Ordinal {function.Ordinal}");
}
-
- if (i < peFile.ImportDescriptors.Count - 1)
+ else
{
- Console.WriteLine(); // Add a blank line between DLLs for better readability
+ Console.WriteLine($" {j}: {function.Name} (Hint={function.Hint})");
}
}
+
+ if (i < peFile.ImportDescriptors.Count - 1)
+ {
+ Console.WriteLine(); // Add a blank line between DLLs for better readability
+ }
}
}
-}
+}
\ No newline at end of file