Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Text
''' <summary>
''' Written to make reading the information from a PE (Portable Executable)
''' easier and simple.
''' </summary>
Public Class PEReader

Public Const IMAGE_SUBSYSTEM_UNKNOWN As UInteger = 0
' Unknown subsystem.
Public Const IMAGE_SUBSYSTEM_NATIVE As UInteger = 1
' Image doesn't require a subsystem.
Public Const IMAGE_SUBSYSTEM_WINDOWS_GUI As UInteger = 2
' Image runs in the Windows GUI subsystem.
Public Const IMAGE_SUBSYSTEM_WINDOWS_CUI As UInteger = 3
' Image runs in the Windows character subsystem.
Public Const IMAGE_SUBSYSTEM_OS2_CUI As UInteger = 5
' image runs in the OS/2 character subsystem.
Public Const IMAGE_SUBSYSTEM_POSIX_CUI As UInteger = 7
' image runs in the Posix character subsystem.
Public Const IMAGE_SUBSYSTEM_NATIVE_WINDOWS As UInteger = 8
' image is a native Win9x driver.
Public Const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI As UInteger = 9
' Image runs in the Windows CE subsystem.
Public Const IMAGE_SUBSYSTEM_EFI_APPLICATION As UInteger = 10
'
Public Const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER As UInteger = 11
'
Public Const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER As UInteger = 12
'
Public Const IMAGE_SUBSYSTEM_EFI_ROM As UInteger = 13
Public Const IMAGE_SUBSYSTEM_XBOX As UInteger = 14

'DllCharacteristics Entries ************************************************** ************
Public Const IMAGE_DLLCHARACTERISTICS_NO_SEH As UInteger = &H400
' Image does not use SEH. No SE handler may reside in this image
Public Const IMAGE_DLLCHARACTERISTICS_NO_BIND As UInteger = &H800
' Do not bind this image.
Public Const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER As UInteger = &H2000
' Driver uses WDM model
Public Const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE As UInteger = &H8000

'DOS header format ************************************************** **********************
Public Structure IMAGE_DOS_HEADER
Public Magic As UShort
Public SizeOfLastPage As UShort
Public NumberOfPages As UShort
Public Relocations As UShort
Public SizeOfHeader As UShort
Public MinimumExtraParagraphs As UShort
Public MaximumExtraParagraphs As UShort
Public InitialSSValue As UShort
Public InitialSPValue As UShort
Public Checksum As UShort
Public InitialIPValue As UShort
Public InitialCSValue As UShort
Public RelocationTableAddress As UShort
Public OverlayNumber As UShort
'[MarshalAs(UnmanagedType.U2, SizeConst=8)]
'public ushort[] ReservedWords;
Public OemIdentifier As UShort
Public OemInformation As UShort
'[MarshalAs(UnmanagedType.U2, SizeConst=20)]
'public ushort[] ReservedWords2;
Public PEHeaderAddress As UInteger
End Structure

'File header format ************************************************** *********************
Public Const IMAGE_SIZEOF_FILE_HEADER As Integer = 20
Public Structure IMAGE_FILE_HEADER
Public Machine As UShort
Public NumberOfSections As UShort
Public TimeDateStamp As UInteger
Public PointerToSymbolTable As UInteger
Public NumberOfSymbols As UInteger
Public SizeOfOptionalHeader As UShort
Public Characteristics As UShort
End Structure
Public Const IMAGE_FILE_RELOCS_STRIPPED As UShort = &H1
' Relocation info stripped from file.
Public Const IMAGE_FILE_EXECUTABLE_IMAGE As UShort = &H2
' File is executable (i.e. no unresolved externel references).
Public Const IMAGE_FILE_LINE_NUMS_STRIPPED As UShort = &H4
' Line nunbers stripped from file.
Public Const IMAGE_FILE_LOCAL_SYMS_STRIPPED As UShort = &H8
' Local symbols stripped from file.
Public Const IMAGE_FILE_AGGRESIVE_WS_TRIM As UShort = &H10
' Agressively trim working set
Public Const IMAGE_FILE_LARGE_ADDRESS_AWARE As UShort = &H20
' App can handle >2gb addresses
Public Const IMAGE_FILE_BYTES_REVERSED_LO As UShort = &H80
' Bytes of machine word are reversed.
Public Const IMAGE_FILE_32BIT_MACHINE As UShort = &H100
' 32 bit word machine.
Public Const IMAGE_FILE_DEBUG_STRIPPED As UShort = &H200
' Debugging info stripped from file in .DBG file
Public Const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP As UShort = &H400
' If Image is on removable media, copy and run from the swap file.
Public Const IMAGE_FILE_NET_RUN_FROM_SWAP As UShort = &H800
' If Image is on Net, copy and run from the swap file.
Public Const IMAGE_FILE_SYSTEM As UShort = &H1000
' System File.
Public Const IMAGE_FILE_DLL As UShort = &H2000
' File is a DLL.
Public Const IMAGE_FILE_UP_SYSTEM_ONLY As UShort = &H4000
' File should only be run on a UP machine
Public Const IMAGE_FILE_BYTES_REVERSED_HI As UShort = &H8000
' Bytes of machine word are reversed.
Public Const IMAGE_FILE_MACHINE_UNKNOWN As UShort = 0
Public Const IMAGE_FILE_MACHINE_I386 As UShort = &H14C
' Intel 386.
Public Const IMAGE_FILE_MACHINE_R3000 As UShort = &H162
' MIPS little-endian, 0x160 big-endian
Public Const IMAGE_FILE_MACHINE_R4000 As UShort = &H166
' MIPS little-endian
Public Const IMAGE_FILE_MACHINE_R10000 As UShort = &H168
' MIPS little-endian
Public Const IMAGE_FILE_MACHINE_WCEMIPSV2 As UShort = &H169
' MIPS little-endian WCE v2
Public Const IMAGE_FILE_MACHINE_ALPHA As UShort = &H184
' Alpha_AXP
Public Const IMAGE_FILE_MACHINE_SH3 As UShort = &H1A2
' SH3 little-endian
Public Const IMAGE_FILE_MACHINE_SH3DSP As UShort = &H1A3
Public Const IMAGE_FILE_MACHINE_SH3E As UShort = &H1A4
' SH3E little-endian
Public Const IMAGE_FILE_MACHINE_SH4 As UShort = &H1A6
' SH4 little-endian
Public Const IMAGE_FILE_MACHINE_SH5 As UShort = &H1A8
' SH5
Public Const IMAGE_FILE_MACHINE_ARM As UShort = &H1C0
' ARM Little-Endian
Public Const IMAGE_FILE_MACHINE_THUMB As UShort = &H1C2
Public Const IMAGE_FILE_MACHINE_AM33 As UShort = &H1D3
Public Const IMAGE_FILE_MACHINE_POWERPC As UShort = &H1F0
' IBM PowerPC Little-Endian
Public Const IMAGE_FILE_MACHINE_POWERPCFP As UShort = &H1F1
Public Const IMAGE_FILE_MACHINE_IA64 As UShort = &H200
' Intel 64
Public Const IMAGE_FILE_MACHINE_MIPS16 As UShort = &H266
' MIPS
Public Const IMAGE_FILE_MACHINE_ALPHA64 As UShort = &H284
' ALPHA64
Public Const IMAGE_FILE_MACHINE_MIPSFPU As UShort = &H366
' MIPS
Public Const IMAGE_FILE_MACHINE_MIPSFPU16 As UShort = &H466
' MIPS
Public Const IMAGE_FILE_MACHINE_AXP64 As UShort = &H284
Public Const IMAGE_FILE_MACHINE_TRICORE As UShort = &H520
' Infineon
Public Const IMAGE_FILE_MACHINE_CEF As UShort = &HCEF
Public Const IMAGE_FILE_MACHINE_EBC As UShort = &HEBC
' EFI Byte Code
Public Const IMAGE_FILE_MACHINE_AMD64 As UShort = &H8664
' AMD64 (K8)
Public Const IMAGE_FILE_MACHINE_M32R As UShort = &H9041
' M32R little-endian
Public Const IMAGE_FILE_MACHINE_CEE As UShort = &HC0EE

'Directory format ************************************************** ***********************
Public Const IMAGE_DIRECTORY_ENTRY_EXPORT As UInteger = 0
' Export Directory
Public Const IMAGE_DIRECTORY_ENTRY_IMPORT As UInteger = 1
' Import Directory
Public Const IMAGE_DIRECTORY_ENTRY_RESOURCE As UInteger = 2
' Resource Directory
Public Const IMAGE_DIRECTORY_ENTRY_EXCEPTION As UInteger = 3
' Exception Directory
Public Const IMAGE_DIRECTORY_ENTRY_SECURITY As UInteger = 4
' Security Directory
Public Const IMAGE_DIRECTORY_ENTRY_BASERELOC As UInteger = 5
' Base Relocation Table
Public Const IMAGE_DIRECTORY_ENTRY_DEBUG As UInteger = 6
' Debug Directory
Public Const IMAGE_DIRECTORY_ENTRY_COPYRIGHT As UInteger = 7
' Copyright
Public Const IMAGE_DIRECTORY_ENTRY_GLOBALPTR As UInteger = 8
' RVA of GP
Public Const IMAGE_DIRECTORY_ENTRY_TLS As UInteger = 9
' TLS Directory
Public Const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG As UInteger = 10
' Load Configuration Directory
Public Const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT As UInteger = 11
' Bound Import Directory in headers
Public Const IMAGE_DIRECTORY_ENTRY_IAT As UInteger = 12
' Import Address Table
Public Const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT As UInteger = 13
' Delay Load Import Descriptors
Public Const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR As UInteger = 14
' COM Runtime descriptor
Public Const IMAGE_NUMBEROF_DIRECTORY_ENTRIES As Integer = 16
Public Structure IMAGE_DATA_DIRECTORY
Public Type As String
Public VirtualAddress As UInteger
Public Size As UInteger
End Structure

'Optional header 64-bit ************************************************** *****************
Public Structure IMAGE_OPTIONAL_HEADER64
Public Magic As UShort
Public MajorLinkerVersion As Byte
Public MinorLinkerVersion As Byte
Public SizeOfCode As UInteger
Public SizeOfInitializedData As UInteger
Public SizeOfUninitializedData As UInteger
Public AddressOfEntryPoint As UInteger
Public BaseOfCode As UInteger
Public ImageBase As UInt64
Public SectionAlignment As UInteger
Public FileAlignment As UInteger
Public MajorOperatingSystemVersion As UShort
Public MinorOperatingSystemVersion As UShort
Public MajorImageVersion As UShort
Public MinorImageVersion As UShort
Public MajorSubsystemVersion As UShort
Public MinorSubsystemVersion As UShort
Public Win32VersionValue As UInteger
Public SizeOfImage As UInteger
Public SizeOfHeaders As UInteger
Public CheckSum As UInteger
Public Subsystem As UShort
Public DllCharacteristics As UShort
Public SizeOfStackReserve As UInt64
Public SizeOfStackCommit As UInt64
Public SizeOfHeapReserve As UInt64
Public SizeOfHeapCommit As UInt64
Public LoaderFlags As UInteger
Public NumberOfRvaAndSizes As UInteger
Public DataDirectory As IMAGE_DATA_DIRECTORY()
End Structure

'Optional header 32-bit ************************************************** *****************
Public Structure IMAGE_OPTIONAL_HEADER32
Public Magic As UShort
Public MajorLinkerVersion As Byte
Public MinorLinkerVersion As Byte
Public SizeOfCode As UInteger
Public SizeOfInitializedData As UInteger
Public SizeOfUninitializedData As UInteger
Public AddressOfEntryPoint As UInteger
Public BaseOfCode As UInteger
Public BaseOfData As UInteger
Public ImageBase As UInteger
Public SectionAlignment As UInteger
Public FileAlignment As UInteger
Public MajorOperatingSystemVersion As UShort
Public MinorOperatingSystemVersion As UShort
Public MajorImageVersion As UShort
Public MinorImageVersion As UShort
Public MajorSubsystemVersion As UShort
Public MinorSubsystemVersion As UShort
Public Win32VersionValue As UInteger
Public SizeOfImage As UInteger
Public SizeOfHeaders As UInteger
Public CheckSum As UInteger
Public Subsystem As UShort
Public DllCharacteristics As UShort
Public SizeOfStackReserve As UInteger
Public SizeOfStackCommit As UInteger
Public SizeOfHeapReserve As UInteger
Public SizeOfHeapCommit As UInteger
Public LoaderFlags As UInteger
Public NumberOfRvaAndSizes As UInteger
Public DataDirectory As IMAGE_DATA_DIRECTORY()
End Structure

'Section header format ************************************************** ******************
Public Structure IMAGE_SECTION_HEADER
Public Name As String
Public PhysicalAddress As UInteger
Public VirtualSize As UInteger
Public VirtualAddress As UInteger
Public SizeOfRawData As UInteger
Public PointerToRawData As UInteger
Public PointerToRelocations As UInteger
Public PointerToLinenumbers As UInteger
Public NumberOfRelocations As UShort
Public NumberOfLinenumbers As UShort
Public Characteristics As UInteger
End Structure

Private inputExe As FileStream
Private inputReader As BinaryReader
Private m_dosHeader As IMAGE_DOS_HEADER
Private m_fileHeader As IMAGE_FILE_HEADER
Private dataDirectory As IMAGE_DATA_DIRECTORY() = New IMAGE_DATA_DIRECTORY(15) {}
Private optionalHeader32 As IMAGE_OPTIONAL_HEADER32
Private m_sectionHeaders As IMAGE_SECTION_HEADER()
Private isExeLoaded As Boolean = False

Private directoryTypeStrings As String() = New String(15) _
{"Export Table", "Import Table", "Resource Table", "Exception Table", "Certificate Table", "Base Relocation Table", _
"Debug Directory", "Architecture Specific Data", "Global Pointer Register", "Thread Local Storage Table", "Load Configuration Table", "Bound Import Table", _
"Import Address Table", "Delay Load Import Descriptors", "COM Runtime Descriptor", "Reserved"}

Public ReadOnly Property DOSHeader() As IMAGE_DOS_HEADER
Get
Return m_dosHeader
End Get
End Property

Public ReadOnly Property FileHeader() As IMAGE_FILE_HEADER
Get
Return m_fileHeader
End Get
End Property

Public ReadOnly Property PEHeader() As IMAGE_OPTIONAL_HEADER32
Get
Return optionalHeader32
End Get
End Property

Public ReadOnly Property DataDirectories() As IMAGE_DATA_DIRECTORY()
Get
Return dataDirectory
End Get
End Property

Public ReadOnly Property SectionHeaders() As IMAGE_SECTION_HEADER()
Get
Return m_sectionHeaders
End Get
End Property

Public Function DoesSectionExist(ByVal sectionName As String) As Boolean
For i As Integer = 0 To m_fileHeader.NumberOfSections - 1
If m_sectionHeaders(i).Name = sectionName Then
Return True
End If
Next
Return False
End Function

Public Function GetSectionDataByName(ByVal sectionName As String) As Byte()
Dim result As Byte()
For i As Integer = 0 To m_fileHeader.NumberOfSections - 1
If m_sectionHeaders(i).Name = sectionName Then
inputExe.Position = m_sectionHeaders(i).PointerToRawData
result = inputReader.ReadBytes(CInt(m_sectionHeaders(i).Siz eOfRawData))
Return result
End If
Next
Return Nothing
End Function

Public Function LoadExecutable(ByVal fileName As String) As Boolean
Try
inputExe = New FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)
inputReader = New BinaryReader(inputExe)
ReadMZHeader()
If m_dosHeader.PEHeaderAddress > 0 Then
inputExe.Position = m_dosHeader.PEHeaderAddress + 4
ReadFileHeader()
ReadSectionHeaders()
End If
isExeLoaded = True
Return True
Catch ex As Exception
Return False
End Try
End Function

Public Sub CloseExecutable()
If isExeLoaded Then
inputExe.Close()
End If
isExeLoaded = False
End Sub

Private Function ReadMZHeader() As Boolean
Try
m_dosHeader.Magic = inputReader.ReadUInt16()
m_dosHeader.SizeOfLastPage = inputReader.ReadUInt16()
m_dosHeader.NumberOfPages = inputReader.ReadUInt16()
m_dosHeader.Relocations = inputReader.ReadUInt16()
m_dosHeader.SizeOfHeader = inputReader.ReadUInt16()
m_dosHeader.MinimumExtraParagraphs = inputReader.ReadUInt16()
m_dosHeader.MaximumExtraParagraphs = inputReader.ReadUInt16()
m_dosHeader.InitialSSValue = inputReader.ReadUInt16()
m_dosHeader.InitialSPValue = inputReader.ReadUInt16()
m_dosHeader.Checksum = inputReader.ReadUInt16()
m_dosHeader.InitialIPValue = inputReader.ReadUInt16()
m_dosHeader.InitialCSValue = inputReader.ReadUInt16()
m_dosHeader.RelocationTableAddress = inputReader.ReadUInt16()
m_dosHeader.OverlayNumber = inputReader.ReadUInt16()
For i As Integer = 0 To 3
inputReader.ReadUInt16()
Next
m_dosHeader.OemIdentifier = inputReader.ReadUInt16()
m_dosHeader.OemInformation = inputReader.ReadUInt16()
For i As Integer = 0 To 9
inputReader.ReadUInt16()
Next
m_dosHeader.PEHeaderAddress = inputReader.ReadUInt32()

Return True
Catch ex As Exception
Return False
End Try
End Function

Private Function ReadFileHeader() As Boolean
Try
m_fileHeader.Machine = inputReader.ReadUInt16()
m_fileHeader.NumberOfSections = inputReader.ReadUInt16()
m_fileHeader.TimeDateStamp = inputReader.ReadUInt32()
m_fileHeader.PointerToSymbolTable = inputReader.ReadUInt32()
m_fileHeader.NumberOfSymbols = inputReader.ReadUInt32()
m_fileHeader.SizeOfOptionalHeader = inputReader.ReadUInt16()
m_fileHeader.Characteristics = inputReader.ReadUInt16()
If m_fileHeader.SizeOfOptionalHeader > 0 Then
If ReadPEHeader() Then
Return True
Else
Return False
End If
End If
Return True
Catch ex As Exception
Return False
End Try
End Function

Private Function ReadPEHeader() As Boolean
Try
optionalHeader32.Magic = inputReader.ReadUInt16()
optionalHeader32.MajorLinkerVersion = inputReader.ReadByte()
optionalHeader32.MinorLinkerVersion = inputReader.ReadByte()
optionalHeader32.SizeOfCode = inputReader.ReadUInt32()
optionalHeader32.SizeOfInitializedData = inputReader.ReadUInt32()
optionalHeader32.SizeOfUninitializedData = inputReader.ReadUInt32()
optionalHeader32.AddressOfEntryPoint = inputReader.ReadUInt32()
optionalHeader32.BaseOfCode = inputReader.ReadUInt32()
optionalHeader32.BaseOfData = inputReader.ReadUInt32()
optionalHeader32.ImageBase = inputReader.ReadUInt32()
optionalHeader32.SectionAlignment = inputReader.ReadUInt32()
optionalHeader32.FileAlignment = inputReader.ReadUInt32()
optionalHeader32.MajorOperatingSystemVersion = inputReader.ReadUInt16()
optionalHeader32.MinorOperatingSystemVersion = inputReader.ReadUInt16()
optionalHeader32.MajorImageVersion = inputReader.ReadUInt16()
optionalHeader32.MinorImageVersion = inputReader.ReadUInt16()
optionalHeader32.MajorSubsystemVersion = inputReader.ReadUInt16()
optionalHeader32.MinorSubsystemVersion = inputReader.ReadUInt16()
optionalHeader32.Win32VersionValue = inputReader.ReadUInt32()
optionalHeader32.SizeOfImage = inputReader.ReadUInt32()
optionalHeader32.SizeOfHeaders = inputReader.ReadUInt32()
optionalHeader32.CheckSum = inputReader.ReadUInt32()
optionalHeader32.Subsystem = inputReader.ReadUInt16()
optionalHeader32.DllCharacteristics = inputReader.ReadUInt16()
optionalHeader32.SizeOfStackReserve = inputReader.ReadUInt32()
optionalHeader32.SizeOfStackCommit = inputReader.ReadUInt32()
optionalHeader32.SizeOfHeapReserve = inputReader.ReadUInt32()
optionalHeader32.SizeOfHeapCommit = inputReader.ReadUInt32()
optionalHeader32.LoaderFlags = inputReader.ReadUInt32()
optionalHeader32.NumberOfRvaAndSizes = inputReader.ReadUInt32()
Console.WriteLine("Magic: {0}", optionalHeader32.Magic)
Console.WriteLine("Number of Directories: {0}", optionalHeader32.ImageBase)
For i As Integer = 0 To dataDirectory.Length - 1
dataDirectory(i).Type = directoryTypeStrings(i)
dataDirectory(i).VirtualAddress = inputReader.ReadUInt32()
dataDirectory(i).Size = inputReader.ReadUInt32()
Next

Return True
Catch ex As Exception
Return False
End Try
End Function

Private Function ReadSectionHeaders() As Boolean
Try
Dim sectionNameBuffer As Byte()
Dim sectionName As String
Dim sectionNameClean As String
m_sectionHeaders = New IMAGE_SECTION_HEADER(m_fileHeader.NumberOfSections - 1) {}
For i As Integer = 0 To m_fileHeader.NumberOfSections - 1
sectionNameBuffer = inputReader.ReadBytes(8)
sectionName = Encoding.ASCII.GetString(sectionNameBuffer)
sectionNameClean = sectionName.Substring(0, sectionName.IndexOf(vbNullChar))
m_sectionHeaders(i).Name = sectionNameClean
'm_sectionHeaders(i).PhysicalAddress = inputReader.ReadUInt32()
m_sectionHeaders(i).VirtualSize = inputReader.ReadUInt32()
m_sectionHeaders(i).VirtualAddress = inputReader.ReadUInt32()
m_sectionHeaders(i).SizeOfRawData = inputReader.ReadUInt32()
m_sectionHeaders(i).PointerToRawData = inputReader.ReadUInt32()
m_sectionHeaders(i).PointerToRelocations = inputReader.ReadUInt32()
m_sectionHeaders(i).PointerToLinenumbers = inputReader.ReadUInt32()
m_sectionHeaders(i).NumberOfRelocations = inputReader.ReadUInt16()
m_sectionHeaders(i).NumberOfLinenumbers = inputReader.ReadUInt16()
m_sectionHeaders(i).Characteristics = inputReader.ReadUInt32()
Next
Return True
Catch ex As Exception
Return False
End Try
End Function

Protected Overrides Sub Finalize()
Try
If isExeLoaded Then
inputReader.Close()
inputExe = Nothing
inputReader = Nothing
End If
Finally
MyBase.Finalize()
End Try
End Sub
End Class