diff --git a/X86Disassembler/PE/DOSHeader.cs b/X86Disassembler/PE/DOSHeader.cs
new file mode 100644
index 0000000..d477807
--- /dev/null
+++ b/X86Disassembler/PE/DOSHeader.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace X86Disassembler.PE
+{
+ ///
+ /// 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
+ }
+}
diff --git a/X86Disassembler/PE/ExportDirectory.cs b/X86Disassembler/PE/ExportDirectory.cs
new file mode 100644
index 0000000..3b188e1
--- /dev/null
+++ b/X86Disassembler/PE/ExportDirectory.cs
@@ -0,0 +1,33 @@
+namespace X86Disassembler.PE
+{
+ ///
+ /// 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
+ }
+
+ ///
+ /// Represents an exported function in a PE file
+ ///
+ public class ExportedFunction
+ {
+ public string Name; // Function name
+ public ushort Ordinal; // Function ordinal
+ public uint Address; // Function RVA
+ public bool IsForwarder; // True if this is a forwarder
+ public string ForwarderName; // Name of the forwarded function
+ }
+}
diff --git a/X86Disassembler/PE/FileHeader.cs b/X86Disassembler/PE/FileHeader.cs
new file mode 100644
index 0000000..00a8538
--- /dev/null
+++ b/X86Disassembler/PE/FileHeader.cs
@@ -0,0 +1,16 @@
+namespace X86Disassembler.PE
+{
+ ///
+ /// 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
+ }
+}
diff --git a/X86Disassembler/PE/ImportDescriptor.cs b/X86Disassembler/PE/ImportDescriptor.cs
new file mode 100644
index 0000000..c2d8ed3
--- /dev/null
+++ b/X86Disassembler/PE/ImportDescriptor.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+
+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 imported function in a PE file
+ ///
+ public class ImportedFunction
+ {
+ public string Name; // Function name
+ public ushort Hint; // Hint value
+ public bool IsOrdinal; // True if imported by ordinal
+ public ushort Ordinal; // Ordinal value (if imported by ordinal)
+ public uint ThunkRVA; // RVA of the thunk for this function
+ }
+}
diff --git a/X86Disassembler/PE/OptionalHeader.cs b/X86Disassembler/PE/OptionalHeader.cs
new file mode 100644
index 0000000..ca44156
--- /dev/null
+++ b/X86Disassembler/PE/OptionalHeader.cs
@@ -0,0 +1,53 @@
+namespace X86Disassembler.PE
+{
+ ///
+ /// Represents the Optional header of a PE file
+ ///
+ public class OptionalHeader
+ {
+ // 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 a data directory in the optional header
+ ///
+ public class DataDirectory
+ {
+ public uint VirtualAddress; // RVA of the table
+ public uint Size; // Size of the table
+ }
+}
diff --git a/X86Disassembler/PE/PEFormat.cs b/X86Disassembler/PE/PEFormat.cs
new file mode 100644
index 0000000..f195932
--- /dev/null
+++ b/X86Disassembler/PE/PEFormat.cs
@@ -0,0 +1,715 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+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;
+
+ // 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; }
+
+ ///
+ /// Parses a PE file from the given byte array
+ ///
+ /// The raw file data
+ public PEFormat(byte[] fileData)
+ {
+ _fileData = fileData;
+ SectionHeaders = new List();
+ ExportedFunctions = new List();
+ ImportDescriptors = new List();
+ Parse();
+ }
+
+ ///
+ /// Parses the PE file structure
+ ///
+ private void Parse()
+ {
+ using (MemoryStream stream = new MemoryStream(_fileData))
+ using (BinaryReader reader = new BinaryReader(stream))
+ {
+ // Parse DOS header
+ DosHeader = ParseDOSHeader(reader);
+
+ // Move to PE header
+ reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
+
+ // Verify PE signature
+ uint peSignature = reader.ReadUInt32();
+ if (peSignature != PE_SIGNATURE)
+ {
+ throw new InvalidDataException("Invalid PE signature");
+ }
+
+ // Parse File Header
+ FileHeader = ParseFileHeader(reader);
+
+ // Parse Optional Header
+ OptionalHeader = ParseOptionalHeader(reader);
+
+ // Parse Section Headers
+ for (int i = 0; i < FileHeader.NumberOfSections; i++)
+ {
+ SectionHeaders.Add(ParseSectionHeader(reader));
+ }
+
+ // Parse Export Directory
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
+ {
+ ExportDirectory = ParseExportDirectory(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
+ ParseExportedFunctions(reader);
+ }
+
+ // Parse Import Descriptors
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
+ {
+ ImportDescriptors = ParseImportDescriptors(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+ }
+ }
+ }
+
+ ///
+ /// Parses the DOS header
+ ///
+ private DOSHeader ParseDOSHeader(BinaryReader reader)
+ {
+ 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;
+ }
+
+ ///
+ /// Parses the File header
+ ///
+ private FileHeader ParseFileHeader(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;
+ }
+
+ ///
+ /// Parses the Optional header
+ ///
+ private OptionalHeader ParseOptionalHeader(BinaryReader reader)
+ {
+ OptionalHeader header = new OptionalHeader();
+
+ // 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;
+ }
+
+ ///
+ /// Parses a section header
+ ///
+ private SectionHeader ParseSectionHeader(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;
+ }
+
+ ///
+ /// Parses the Export Directory
+ ///
+ private ExportDirectory ParseExportDirectory(BinaryReader reader, uint rva)
+ {
+ ExportDirectory directory = new ExportDirectory();
+
+ reader.BaseStream.Seek(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 = 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;
+ }
+
+ ///
+ /// Parses the Import Descriptors
+ ///
+ private List ParseImportDescriptors(BinaryReader reader, uint rva)
+ {
+ List descriptors = new List();
+
+ try
+ {
+ uint importTableOffset = 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 = 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
+ }
+
+ return descriptors;
+ }
+
+ ///
+ /// Parses the imported functions for a given 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 = 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 = 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 = $"Function_at_{thunkData:X8}";
+ }
+ }
+
+ descriptor.Functions.Add(function);
+ functionCount++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error parsing imported functions for {descriptor.DllName}: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Parses the exported functions using the export directory information
+ ///
+ private void ParseExportedFunctions(BinaryReader reader)
+ {
+ if (ExportDirectory == null)
+ {
+ return;
+ }
+
+ // Read the array of function addresses (RVAs)
+ uint[] functionRVAs = new uint[ExportDirectory.NumberOfFunctions];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfFunctions), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfFunctions; i++)
+ {
+ functionRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name RVAs
+ uint[] nameRVAs = new uint[ExportDirectory.NumberOfNames];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfNames), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ nameRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name ordinals
+ ushort[] nameOrdinals = new ushort[ExportDirectory.NumberOfNames];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfNameOrdinals), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ nameOrdinals[i] = reader.ReadUInt16();
+ }
+
+ // Create a dictionary to map ordinals to names
+ Dictionary ordinalToName = new Dictionary();
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ // Read the function name
+ reader.BaseStream.Seek(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 < ExportDirectory.NumberOfFunctions; i++)
+ {
+ uint functionRVA = functionRVAs[i];
+ if (functionRVA == 0)
+ {
+ continue; // Skip empty entries
+ }
+
+ ExportedFunction function = new ExportedFunction();
+ function.Ordinal = (ushort)(i + ExportDirectory.Base);
+ function.Address = functionRVA;
+
+ // Check if this function has a name
+ if (ordinalToName.TryGetValue(i, out string name))
+ {
+ function.Name = name;
+ }
+ else
+ {
+ function.Name = $"Ordinal_{function.Ordinal}";
+ }
+
+ // Check if this is a forwarder
+ uint exportDirStart = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ uint exportDirEnd = exportDirStart + OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+
+ if (functionRVA >= exportDirStart && functionRVA < exportDirEnd)
+ {
+ function.IsForwarder = true;
+
+ // Read the forwarder string
+ reader.BaseStream.Seek(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);
+ }
+ }
+
+ ///
+ /// 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");
+ }
+
+ ///
+ /// 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.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
+ (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
+ }
+
+ ///
+ /// 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 (IsSectionContainsCode(SectionHeaders[i]))
+ {
+ codeSections.Add(i);
+ }
+ }
+
+ return codeSections;
+ }
+
+ ///
+ /// 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)
+ {
+ // 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;
+
+ // 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 < OptionalHeader.SizeOfHeaders)
+ {
+ return rva;
+ }
+
+ throw new ArgumentException($"RVA {rva:X8} is not within any section");
+ }
+ }
+}
diff --git a/X86Disassembler/PE/SectionHeader.cs b/X86Disassembler/PE/SectionHeader.cs
new file mode 100644
index 0000000..7eac445
--- /dev/null
+++ b/X86Disassembler/PE/SectionHeader.cs
@@ -0,0 +1,19 @@
+namespace X86Disassembler.PE
+{
+ ///
+ /// Represents a section header in a PE file
+ ///
+ public class SectionHeader
+ {
+ 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
+ }
+}
diff --git a/X86Disassembler/Program.cs b/X86Disassembler/Program.cs
index 752401a..e25a0b6 100644
--- a/X86Disassembler/Program.cs
+++ b/X86Disassembler/Program.cs
@@ -1,12 +1,13 @@
using System;
using System.IO;
+using X86Disassembler.PE;
namespace X86Disassembler
{
internal class Program
{
// Path to the DLL file to disassemble
- private const string DllPath = @"C:\Windows\SysWOW64\msvcrt.dll"; // Example path, replace with your target DLL
+ 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)
{