Basic PE Header Parser Snippet

Posts 13 of 3 · Page 1 of 1
Basic PE Header Parser Snippet
I made this pretty basic PE header parser for my injection library before I discovered PeNet, an amazing library for parsing PE headers.

Anyway, I thought I may as well drop the code here in case anyone needs it someday before I throw it out.

Code:
private static List<object> GetPeHeaders(string dllPath)
{
    var peHeaders = new List<object>();

    // Open a file stream to the dll
            
    using (var stream = new FileStream(dllPath, FileMode.Open, FileAccess.Read))
    {
        // Open a binary reader to the file stream
                
        var reader = new BinaryReader(stream);

        // Get the dos header
                
        var dosHeader = ConvertBytesToStructure<ImageDosHeader>(reader);
                
        // Skip the dos stub

        reader.BaseStream.Seek(dosHeader.E_Lfanew, SeekOrigin.Begin);
                
        // Get the nt header

        var ntHeader = new ImageNtHeader
        {
             Signature = ConvertBytesToStructure<uint>(reader),
                    
             FileHeader = ConvertBytesToStructure<ImageFileHeader>(reader)
        };

        var sectionHeaders = new List<ImageSectionHeader>();

        // If the dll is x86
                
        if ((ntHeader.FileHeader.Characteristics & 0x0100) == 0x0100)
        {
            // Get the optional header
                    
            ntHeader.OptionalHeader = ConvertBytesToStructure<ImageOptionalHeader>(reader);

            // Get the section headers
                    
            foreach (var i in Enumerable.Range(0, ntHeader.OptionalHeader.NumberOfRvaAndSizes))
            {
                 if (ntHeader.OptionalHeader.DataDirectory[i].Size > 0)
                 {
                      sectionHeaders.Add(ConvertBytesToStructure<ImageSectionHeader>(reader));
                  }
            }
        }

        // If the dll is x64
                
        else
        {
             // Get the optional header
                    
             ntHeader.OptionalHeader64 = ConvertBytesToStructure<ImageOptionalHeader64>(reader);

             // Get the section headers
                    
             foreach (var i in Enumerable.Range(0, ntHeader.OptionalHeader.NumberOfRvaAndSizes))
             {
                  if (ntHeader.OptionalHeader.DataDirectory[i].Size > 0)
                  {
                       sectionHeaders.Add(ConvertBytesToStructure<ImageSectionHeader>(reader));
                   }
              }
         }
                
              // Add the header objects to a list
                
              peHeaders.Add(dosHeader);
              peHeaders.Add(ntHeader);
              peHeaders.Add(sectionHeaders);
        }

          return peHeaders;
 }

        internal static TStructure ConvertBytesToStructure<TStructure>(BinaryReader reader)
        {
            // Get the size of the structure

            var structureSize = Marshal.SizeOf(typeof(TStructure));

            // Read the bytes

            var bytes = reader.ReadBytes(structureSize);

            // Allocate memory for a buffer

            var buffer = Marshal.AllocHGlobal(structureSize);

            Marshal.Copy(bytes, 0, buffer, structureSize);

            // Convert the bytes into a structure

            var structure = (TStructure) Marshal.PtrToStructure(buffer, typeof(TStructure));

            // Free the previously allocated memory

            Marshal.FreeHGlobal(buffer);

            return structure;
 }
And here are the structures used

Code:
[StructLayout(LayoutKind.Sequential)]
        internal struct ImageDosHeader
        {
            internal readonly ushort E_Magic;       
            
            private readonly ushort E_Cblp;    
            private readonly ushort E_Cp;      
            private readonly ushort E_Crlc;    
            private readonly ushort E_Cparhdr;
            
            private readonly ushort E_Minalloc;
            private readonly ushort E_Maxalloc;
            
            private readonly ushort E_Ss;
            private readonly ushort E_Sp;
            
            private readonly ushort E_Csum;
            
            private readonly ushort E_Ip;
            private readonly ushort E_Cs;
            
            private readonly ushort E_Lfarlc;
            
            private readonly ushort E_Ovno;
            
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
            private readonly ushort[] E_Res1;
            
            private readonly ushort E_Oemid;
            private readonly ushort E_Oeminfo;
            
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
            private readonly ushort[] E_Res2;
            
            internal readonly int E_Lfanew;
        }
        
        [StructLayout(LayoutKind.Sequential)]
        public struct ImageFileHeader
        {
            public readonly ushort Machine;
            public readonly ushort NumberOfSections;
            
            public readonly uint TimeDateStamp;
            public readonly uint PointerToSymbolTable;
            public readonly uint NumberOfSymbols;
            
            public readonly ushort SizeOfOptionalHeader;
            public readonly ushort Characteristics;
        }
        
        [StructLayout(LayoutKind.Sequential)]
        public struct ImageDataDirectory
        {
            public readonly uint VirtualAddress;
            
            public readonly uint Size;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ImageOptionalHeader
        {
            public ushort Magic;
            
            public byte MajorLinkerVersion; 
            public byte MinorLinkerVersion;
            
            public uint SizeOfCode;
            public uint SizeOfInitializedData;
            public uint SizeOfUninitializedData;
            
            public uint AddressOfEntryPoint;
            
            public uint BaseOfCode;
            public uint BaseOfData;
            
            public uint ImageBase;
            
            public uint SectionAlignment;
            public uint FileAlignment;
            
            public ushort MajorOperatin****temVersion;
            public ushort MinorOperatin****temVersion;
            
            public ushort MajorImageVersion;
            public ushort MinorImageVersion;
            
            public ushort MajorSubsystemVersion;
            public ushort MinorSubsystemVersion;
            
            public uint Win32VersionValue;
            
            public int SizeOfImage;
            public uint SizeOfHeaders;
            
            public uint CheckSum;

            public ushort Subsystem;

            public ushort DllCharacteristics;
            
            public uint SizeOfStackReserve;
            public uint SizeOfStackCommit;
            
            public uint SizeOfHeapReserve;
            public uint SizeOfHeapCommit;

            public uint LoaderFlags;
            public int NumberOfRvaAndSizes;

            public ImageDataDirectory ExportTable;
            
            public ImageDataDirectory ImportTable;

            public ImageDataDirectory ResourceTable;

            public ImageDataDirectory ExceptionTable;

            public ImageDataDirectory CertificateTable;

            public ImageDataDirectory BaseRelocationTable;

            public ImageDataDirectory Debug;

            public ImageDataDirectory Architecture;

            public ImageDataDirectory GlobalPtr;

            public ImageDataDirectory TLSTable;

            public ImageDataDirectory LoadConfigTable;

            public ImageDataDirectory BoundImport;

            public ImageDataDirectory IAT;

            public ImageDataDirectory DelayImportDescriptor;

            public ImageDataDirectory CLRRuntimeHeader;

            public ImageDataDirectory Reserved;
        }
        
        [StructLayout(LayoutKind.Sequential)]
        public struct ImageOptionalHeader64
        {
            public readonly ushort Magic;

            private readonly byte MajorLinkerVersion;
            private readonly byte MinorLinkerVersion;

            private readonly uint SizeOfCode;
            public readonly uint SizeOfInitializedData;
            private readonly uint SizeOfUninitializedData;
            
            public readonly uint AddressOfEntryPoint;

            private readonly uint BaseOfCode;
            
            public readonly uint ImageBase;

            private readonly uint SectionAlignment;
            private readonly uint FileAlignment;

            private readonly ushort MajorOperatin****temVersion;
            private readonly ushort MinorOperatin****temVersion;

            private readonly ushort MajorImageVersion;
            private readonly ushort MinorImageVersion;

            private readonly ushort MajorSubsystemVersion;
            private readonly ushort MinorSubsystemVersion;

            private readonly uint Win32VersionValue;
            
            public readonly int SizeOfImage;
            private readonly uint SizeOfHeaders;

            private readonly uint CheckSum;

            private readonly ushort Subsystem;

            private readonly ushort DllCharacteristics;

            private readonly uint SizeOfStackReserve;
            private readonly uint SizeOfStackCommit;

            private readonly uint SizeOfHeapReserve;
            private readonly uint SizeOfHeapCommit;

            private readonly uint LoaderFlags;
            
            public readonly int NumberOfRvaAndSizes;
            
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            private readonly ImageDataDirectory[] DataDirectory;
            
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ImageNtHeader
        {
            public uint Signature;

            public ImageFileHeader FileHeader;
            
            public ImageOptionalHeader OptionalHeader;

            public ImageOptionalHeader64 OptionalHeader64;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ImageSectionHeader
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] Name;
            
            public uint VirtualSize;
            public uint VirtualAddress;
            
            public uint SizeOfRawData;
            
            public uint PointerToRawData;
            public uint PointerToRelocations;
            public uint PointerToLinenumbers;
            
            public ushort NumberOfRelocations;
            public ushort NumberOfLinenumbers;

            public uint Characteristics;

        }
        
        [StructLayout(LayoutKind.Sequential)]
        public struct ImageBaseRelocation
        {
            public uint VirtualAddress;
            
            public uint SizeOfBlock;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct ImageImportDescription
        {
            public uint OriginalFirstThunk;
            
            public uint TimeDateStamp;
            
            public uint ForwarderChain;
            
            public uint Name;
            
            public uint FirstThunk;
        }
Well commented! good work
Thank you very informative
Posts 13 of 3 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Need help?