mirror of
				https://github.com/sampletext32/ParkanPlayground.git
				synced 2025-11-04 07:19:45 +03:00 
			
		
		
		
	Refactor PEFormat into smaller classes following Single Responsibility Principle
This commit is contained in:
		@@ -2,6 +2,7 @@ using System;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.IO;
 | 
					using System.IO;
 | 
				
			||||||
using System.Text;
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using X86Disassembler.PE.Parsers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace X86Disassembler.PE
 | 
					namespace X86Disassembler.PE
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -44,6 +45,15 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
        // PE file data
 | 
					        // PE file data
 | 
				
			||||||
        private byte[] _fileData;
 | 
					        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
 | 
					        // Parsed headers
 | 
				
			||||||
        public DOSHeader DosHeader { get; private set; }
 | 
					        public DOSHeader DosHeader { get; private set; }
 | 
				
			||||||
        public FileHeader FileHeader { get; private set; }
 | 
					        public FileHeader FileHeader { get; private set; }
 | 
				
			||||||
@@ -66,6 +76,12 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
            SectionHeaders = new List<SectionHeader>();
 | 
					            SectionHeaders = new List<SectionHeader>();
 | 
				
			||||||
            ExportedFunctions = new List<ExportedFunction>();
 | 
					            ExportedFunctions = new List<ExportedFunction>();
 | 
				
			||||||
            ImportDescriptors = new List<ImportDescriptor>();
 | 
					            ImportDescriptors = new List<ImportDescriptor>();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Initialize parsers
 | 
				
			||||||
 | 
					            _dosHeaderParser = new DOSHeaderParser();
 | 
				
			||||||
 | 
					            _fileHeaderParser = new FileHeaderParser();
 | 
				
			||||||
 | 
					            _optionalHeaderParser = new OptionalHeaderParser();
 | 
				
			||||||
 | 
					            _sectionHeaderParser = new SectionHeaderParser();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@@ -80,7 +96,7 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
                using (BinaryReader reader = new BinaryReader(stream))
 | 
					                using (BinaryReader reader = new BinaryReader(stream))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // Parse DOS header
 | 
					                    // Parse DOS header
 | 
				
			||||||
                    DosHeader = ParseDOSHeader(reader);
 | 
					                    DosHeader = _dosHeaderParser.Parse(reader);
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // Move to PE header
 | 
					                    // Move to PE header
 | 
				
			||||||
                    reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
 | 
					                    reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
 | 
				
			||||||
@@ -93,30 +109,40 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // Parse File Header
 | 
					                    // Parse File Header
 | 
				
			||||||
                    FileHeader = ParseFileHeader(reader);
 | 
					                    FileHeader = _fileHeaderParser.Parse(reader);
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // Parse Optional Header
 | 
					                    // Parse Optional Header
 | 
				
			||||||
                    OptionalHeader = ParseOptionalHeader(reader);
 | 
					                    OptionalHeader = _optionalHeaderParser.Parse(reader);
 | 
				
			||||||
 | 
					                    Is64Bit = _optionalHeaderParser.Is64Bit(OptionalHeader);
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // Parse Section Headers
 | 
					                    // Parse Section Headers
 | 
				
			||||||
                    for (int i = 0; i < FileHeader.NumberOfSections; i++)
 | 
					                    for (int i = 0; i < FileHeader.NumberOfSections; i++)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        SectionHeaders.Add(ParseSectionHeader(reader));
 | 
					                        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
 | 
					                    // Parse Export Directory
 | 
				
			||||||
                    if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT && 
 | 
					                    if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT && 
 | 
				
			||||||
                        OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
 | 
					                        OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        ExportDirectory = ParseExportDirectory(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
 | 
					                        uint exportDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
 | 
				
			||||||
                        ParseExportedFunctions(reader);
 | 
					                        uint exportDirSize = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
 | 
				
			||||||
 | 
					                        
 | 
				
			||||||
 | 
					                        ExportDirectory = _exportDirectoryParser.Parse(reader, exportDirRva);
 | 
				
			||||||
 | 
					                        ExportedFunctions = _exportDirectoryParser.ParseExportedFunctions(reader, ExportDirectory, exportDirRva, exportDirSize);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    
 | 
					                    
 | 
				
			||||||
                    // Parse Import Descriptors
 | 
					                    // Parse Import Descriptors
 | 
				
			||||||
                    if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT && 
 | 
					                    if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT && 
 | 
				
			||||||
                        OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
 | 
					                        OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        ImportDescriptors = ParseImportDescriptors(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
 | 
					                        uint importDirRva = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
 | 
				
			||||||
 | 
					                        ImportDescriptors = _importDescriptorParser.Parse(reader, importDirRva);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
@@ -129,494 +155,6 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the DOS header
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the File header
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the Optional header
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses a section header
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the Export Directory
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the Import Descriptors
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        private List<ImportDescriptor> ParseImportDescriptors(BinaryReader reader, uint rva)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            List<ImportDescriptor> descriptors = new List<ImportDescriptor>();
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            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;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the imported functions for a given import descriptor
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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}");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Parses the exported functions using the export directory information
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        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<ushort, string> ordinalToName = new Dictionary<ushort, string>();
 | 
					 | 
				
			||||||
            for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // Read the function name
 | 
					 | 
				
			||||||
                reader.BaseStream.Seek(RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
 | 
					 | 
				
			||||||
                List<byte> nameBytes = new List<byte>();
 | 
					 | 
				
			||||||
                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<byte> forwarderBytes = new List<byte>();
 | 
					 | 
				
			||||||
                    byte b;
 | 
					 | 
				
			||||||
                    while ((b = reader.ReadByte()) != 0)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        forwarderBytes.Add(b);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    function.ForwarderName = Encoding.ASCII.GetString(forwarderBytes.ToArray());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                ExportedFunctions.Add(function);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets the raw data for a specific section
 | 
					        /// Gets the raw data for a specific section
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@@ -655,17 +193,6 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
            throw new ArgumentException($"Section '{sectionName}' not found");
 | 
					            throw new ArgumentException($"Section '{sectionName}' not found");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// Checks if a section contains code
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        /// <param name="section">The section to check</param>
 | 
					 | 
				
			||||||
        /// <returns>True if the section contains code, false otherwise</returns>
 | 
					 | 
				
			||||||
        public bool IsSectionContainsCode(SectionHeader section)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return (section.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
 | 
					 | 
				
			||||||
                   (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Gets all code sections
 | 
					        /// Gets all code sections
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
@@ -676,7 +203,7 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
            for (int i = 0; i < SectionHeaders.Count; i++)
 | 
					            for (int i = 0; i < SectionHeaders.Count; i++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (IsSectionContainsCode(SectionHeaders[i]))
 | 
					                if (_sectionHeaderParser.IsSectionContainsCode(SectionHeaders[i]))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    codeSections.Add(i);
 | 
					                    codeSections.Add(i);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -686,40 +213,13 @@ namespace X86Disassembler.PE
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Converts a Relative Virtual Address (RVA) to a file offset
 | 
					        /// Checks if a section contains code
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="rva">The RVA to convert</param>
 | 
					        /// <param name="section">The section to check</param>
 | 
				
			||||||
        /// <returns>The corresponding file offset</returns>
 | 
					        /// <returns>True if the section contains code, false otherwise</returns>
 | 
				
			||||||
        public uint RvaToOffset(uint rva)
 | 
					        public bool IsSectionContainsCode(SectionHeader section)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (rva == 0)
 | 
					            return _sectionHeaderParser.IsSectionContainsCode(section);
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                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");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								X86Disassembler/PE/PEUtility.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								X86Disassembler/PE/PEUtility.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Utility class for PE format operations
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class PEUtility
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly List<SectionHeader> _sectionHeaders;
 | 
				
			||||||
 | 
					        private readonly uint _sizeOfHeaders;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Initialize a new instance of the PEUtility class
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="sectionHeaders">The section headers</param>
 | 
				
			||||||
 | 
					        /// <param name="sizeOfHeaders">The size of the headers</param>
 | 
				
			||||||
 | 
					        public PEUtility(List<SectionHeader> sectionHeaders, uint sizeOfHeaders)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _sectionHeaders = sectionHeaders;
 | 
				
			||||||
 | 
					            _sizeOfHeaders = sizeOfHeaders;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Converts a Relative Virtual Address (RVA) to a file offset
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="rva">The RVA to convert</param>
 | 
				
			||||||
 | 
					        /// <returns>The corresponding file offset</returns>
 | 
				
			||||||
 | 
					        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 < _sizeOfHeaders)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return rva;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            throw new ArgumentException($"RVA {rva:X8} is not within any section");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								X86Disassembler/PE/Parsers/DOSHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								X86Disassembler/PE/Parsers/DOSHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for the DOS header of a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class DOSHeaderParser : IParser<DOSHeader>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // DOS Header constants
 | 
				
			||||||
 | 
					        private const ushort DOS_SIGNATURE = 0x5A4D;       // 'MZ'
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the DOS header from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader positioned at the start of the DOS header</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed DOS header</returns>
 | 
				
			||||||
 | 
					        public DOSHeader Parse(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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										176
									
								
								X86Disassembler/PE/Parsers/ExportDirectoryParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								X86Disassembler/PE/Parsers/ExportDirectoryParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for the Export Directory of a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class ExportDirectoryParser
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly PEUtility _utility;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public ExportDirectoryParser(PEUtility utility)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _utility = utility;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the Export Directory from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader</param>
 | 
				
			||||||
 | 
					        /// <param name="rva">The RVA of the Export Directory</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed Export Directory</returns>
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the exported functions using the export directory information
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader</param>
 | 
				
			||||||
 | 
					        /// <param name="directory">The Export Directory</param>
 | 
				
			||||||
 | 
					        /// <param name="exportDirRva">The RVA of the Export Directory</param>
 | 
				
			||||||
 | 
					        /// <param name="exportDirSize">The size of the Export Directory</param>
 | 
				
			||||||
 | 
					        /// <returns>List of exported functions</returns>
 | 
				
			||||||
 | 
					        public List<ExportedFunction> ParseExportedFunctions(BinaryReader reader, ExportDirectory directory, uint exportDirRva, uint exportDirSize)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<ExportedFunction> exportedFunctions = new List<ExportedFunction>();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            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<ushort, string> ordinalToName = new Dictionary<ushort, string>();
 | 
				
			||||||
 | 
					            for (int i = 0; i < directory.NumberOfNames; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // Read the function name
 | 
				
			||||||
 | 
					                reader.BaseStream.Seek(_utility.RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
 | 
				
			||||||
 | 
					                List<byte> nameBytes = new List<byte>();
 | 
				
			||||||
 | 
					                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;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                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<byte> forwarderBytes = new List<byte>();
 | 
				
			||||||
 | 
					                    byte b;
 | 
				
			||||||
 | 
					                    while ((b = reader.ReadByte()) != 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        forwarderBytes.Add(b);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    function.ForwarderName = Encoding.ASCII.GetString(forwarderBytes.ToArray());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                exportedFunctions.Add(function);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            return exportedFunctions;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								X86Disassembler/PE/Parsers/FileHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								X86Disassembler/PE/Parsers/FileHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for the File header of a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class FileHeaderParser : IParser<FileHeader>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the File header from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader positioned at the start of the File header</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed File header</returns>
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								X86Disassembler/PE/Parsers/IParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								X86Disassembler/PE/Parsers/IParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Interface for PE format component parsers
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <typeparam name="T">The type of component to parse</typeparam>
 | 
				
			||||||
 | 
					    public interface IParser<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse a component from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader positioned at the start of the component</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed component</returns>
 | 
				
			||||||
 | 
					        T Parse(BinaryReader reader);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										192
									
								
								X86Disassembler/PE/Parsers/ImportDescriptorParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								X86Disassembler/PE/Parsers/ImportDescriptorParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for Import Descriptors in a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class ImportDescriptorParser
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private readonly PEUtility _utility;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        public ImportDescriptorParser(PEUtility utility)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _utility = utility;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the Import Descriptors from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader</param>
 | 
				
			||||||
 | 
					        /// <param name="rva">The RVA of the Import Directory</param>
 | 
				
			||||||
 | 
					        /// <returns>List of Import Descriptors</returns>
 | 
				
			||||||
 | 
					        public List<ImportDescriptor> Parse(BinaryReader reader, uint rva)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            List<ImportDescriptor> descriptors = new List<ImportDescriptor>();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            return descriptors;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the imported functions for a given import descriptor
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader</param>
 | 
				
			||||||
 | 
					        /// <param name="descriptor">The Import Descriptor</param>
 | 
				
			||||||
 | 
					        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 = $"Function_at_{thunkData:X8}";
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    descriptor.Functions.Add(function);
 | 
				
			||||||
 | 
					                    functionCount++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (Exception ex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Console.WriteLine($"Error parsing imported functions for {descriptor.DllName}: {ex.Message}");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										114
									
								
								X86Disassembler/PE/Parsers/OptionalHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								X86Disassembler/PE/Parsers/OptionalHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for the Optional header of a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class OptionalHeaderParser : IParser<OptionalHeader>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Optional Header Magic values
 | 
				
			||||||
 | 
					        private const ushort PE32_MAGIC = 0x10B;           // 32-bit executable
 | 
				
			||||||
 | 
					        private const ushort PE32PLUS_MAGIC = 0x20B;       // 64-bit executable
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse the Optional header from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader positioned at the start of the Optional header</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed Optional header</returns>
 | 
				
			||||||
 | 
					        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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Determines if the PE file is 64-bit based on the Optional header
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="header">The Optional header</param>
 | 
				
			||||||
 | 
					        /// <returns>True if the PE file is 64-bit, false otherwise</returns>
 | 
				
			||||||
 | 
					        public bool Is64Bit(OptionalHeader header)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return header.Magic == PE32PLUS_MAGIC;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								X86Disassembler/PE/Parsers/SectionHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								X86Disassembler/PE/Parsers/SectionHeaderParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace X86Disassembler.PE.Parsers
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Parser for section headers in a PE file
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public class SectionHeaderParser : IParser<SectionHeader>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Parse a section header from the binary reader
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="reader">The binary reader positioned at the start of the section header</param>
 | 
				
			||||||
 | 
					        /// <returns>The parsed section header</returns>
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// Checks if a section contains code
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="section">The section to check</param>
 | 
				
			||||||
 | 
					        /// <returns>True if the section contains code, false otherwise</returns>
 | 
				
			||||||
 | 
					        public bool IsSectionContainsCode(SectionHeader section)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            const uint IMAGE_SCN_CNT_CODE = 0x00000020;     // Section contains code
 | 
				
			||||||
 | 
					            const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000;   // Section is executable
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            return (section.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
 | 
				
			||||||
 | 
					                   (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user