Imports System.IO Imports System.ComponentModel Imports System.Runtime.InteropServices '------------------ 'Creator: aeonhack 'Site: nimoru.com 'Created: 05/06/2014 'Changed: 05/06/2014 'Version: 1.0.0.0 '------------------ Public NotInheritable Class ExecutableReader Implements IDisposable #Region " Properties " Private _Is32Bit As Boolean ReadOnly Property Is32Bit() As Boolean Get Return _Is32Bit End Get End Property Private _DosHeader As Win32.IMAGE_DOS_HEADER ReadOnly Property DosHeader As Win32.IMAGE_DOS_HEADER Get Return _DosHeader End Get End Property Private _Signature As UInteger ReadOnly Property Signature As UInteger Get Return _Signature End Get End Property Private _FileHeader As Win32.IMAGE_FILE_HEADER ReadOnly Property FileHeader As Win32.IMAGE_FILE_HEADER Get Return _FileHeader End Get End Property Private _OptionalHeader32 As Win32.IMAGE_OPTIONAL_HEADER32 ReadOnly Property OptionalHeader32 As Win32.IMAGE_OPTIONAL_HEADER32 Get Return _OptionalHeader32 End Get End Property Private _OptionalHeader64 As Win32.IMAGE_OPTIONAL_HEADER64 ReadOnly Property OptionalHeader64 As Win32.IMAGE_OPTIONAL_HEADER64 Get Return _OptionalHeader64 End Get End Property Private _DataDirectory As Win32.IMAGE_DATA_DIRECTORY() ReadOnly Property DataDirectory As Win32.IMAGE_DATA_DIRECTORY() Get Return _DataDirectory End Get End Property Private _SectionHeaders As Win32.IMAGE_SECTION_HEADER() ReadOnly Property SectionHeaders() As Win32.IMAGE_SECTION_HEADER() Get Return _SectionHeaders End Get End Property Private _IsDisposed As Boolean ReadOnly Property IsDisposed As Boolean Get Return _IsDisposed End Get End Property Private _IsLoaded As Boolean ReadOnly Property IsLoaded As Boolean Get Return _IsLoaded End Get End Property #End Region #Region " Constants " Private Const PROCESS_VM_OPERATION As Integer = 8 Private Const PROCESS_VM_READ As Integer = 16 Private Const PAGE_NOACCESS As Integer = 1 Private Const PAGE_EXECUTE_READWRITE As Integer = 64 #End Region #Region " Members " Private _IsRuntime As Boolean Private _ProcessHandle As IntPtr Private _FileStream As FileStream Private _Address As IntPtr Private _BaseAddress As IntPtr #End Region #Region " Initialization " Public Sub LoadFromProcess(process As Process) ThrowOnDisposed() ThrowOnLoaded() _IsLoaded = True _IsRuntime = True _BaseAddress = process.MainModule.BaseAddress _Address = _BaseAddress _ProcessHandle = Win32.OpenProcess(PROCESS_VM_READ Or PROCESS_VM_OPERATION, False, process.Id) If _ProcessHandle = IntPtr.Zero Then Throw New Win32Exception(Marshal.GetLastWin32Error()) End If ProcessExecutable() End Sub Public Sub LoadFromFile(fileName As String) ThrowOnDisposed() ThrowOnLoaded() _IsLoaded = True _FileStream = File.OpenRead(fileName) ProcessExecutable() End Sub #End Region #Region " Processing " Private Sub ProcessExecutable() _DosHeader = Read(Of Win32.IMAGE_DOS_HEADER)() Seek(_DosHeader.e_lfanew) _Signature = Read(Of UInteger)() _FileHeader = Read(Of Win32.IMAGE_FILE_HEADER)() _Is32Bit = (_FileHeader.Machine = 332) If _Is32Bit Then _OptionalHeader32 = Read(Of Win32.IMAGE_OPTIONAL_HEADER32)() Else _OptionalHeader64 = Read(Of Win32.IMAGE_OPTIONAL_HEADER64)() End If _DataDirectory = New Win32.IMAGE_DATA_DIRECTORY(16 - 1) {} For I As Integer = 0 To _DataDirectory.Length - 1 _DataDirectory(I) = Read(Of Win32.IMAGE_DATA_DIRECTORY)() Next SeekToSectionHeaders() _SectionHeaders = New Win32.IMAGE_SECTION_HEADER(_FileHeader.NumberOfSections - 1) {} For I As Integer = 0 To _FileHeader.NumberOfSections - 1 _SectionHeaders(I) = Read(Of Win32.IMAGE_SECTION_HEADER)() Next End Sub Private Function Read(Of T As Structure)() As T Dim Data As Byte() = Read(Marshal.SizeOf(GetType(T))) Dim Item As New T() Dim Handle As IntPtr = Marshal.AllocCoTaskMem(Data.Length) Marshal.Copy(Data, 0, Handle, Data.Length) Item = DirectCast(Marshal.PtrToStructure(Handle, GetType(T)), T) Marshal.FreeCoTaskMem(Handle) Return Item End Function Private Function Read(length As Integer) As Byte() Dim Data(length - 1) As Byte If _IsRuntime Then Dim BytesRead As Integer If Not Win32.ReadProcessMemory(_ProcessHandle, _Address, Data, Data.Length, BytesRead) Then Throw New Win32Exception(Marshal.GetLastWin32Error()) End If _Address = New IntPtr(_Address.ToInt64() + Data.Length) Else _FileStream.Read(Data, 0, Data.Length) End If Return Data End Function Private Sub Seek(offset As Integer) If _IsRuntime Then _Address = New IntPtr(_BaseAddress.ToInt64() + offset) Else _FileStream.Seek(offset, SeekOrigin.Begin) End If End Sub Private Sub SeekToSectionHeaders() Dim Offset As Integer = _DosHeader.e_lfanew Offset += Marshal.SizeOf(_Signature) Offset += Marshal.SizeOf(_FileHeader) Offset += _FileHeader.SizeOfOptionalHeader Seek(Offset) End Sub #End Region #Region " Extraction " Public Function DumpSection(sectionHeader As Win32.IMAGE_SECTION_HEADER) As Byte() ThrowOnDisposed() ThrowOnNotLoaded() If _IsRuntime Then Seek(sectionHeader.VirtualAddress) Else Seek(sectionHeader.PointerToRawData) End If Return GetDump(sectionHeader.VirtualSize) End Function Public Function DumpDataDirectory(dataDirectory As Win32.IMAGE_DATA_DIRECTORY) As Byte() ThrowOnDisposed() ThrowOnNotLoaded() If dataDirectory.VirtualAddress = 0 Then Return New Byte() {} End If If _IsRuntime Then Seek(dataDirectory.VirtualAddress) Else Seek(GetPointerToRawData(dataDirectory.VirtualAddress)) End If Return GetDump(dataDirectory.Size) End Function Public Function DumpUnmappedData() As Byte() ThrowOnDisposed() ThrowOnNotLoaded() If _IsRuntime Then Return New Byte() {} Else Dim HighestOffset As Integer For Each Section As Win32.IMAGE_SECTION_HEADER In _SectionHeaders If Section.PointerToRawData + Section.SizeOfRawData > HighestOffset Then HighestOffset = Section.PointerToRawData + Section.SizeOfRawData End If Next For Each Directory As Win32.IMAGE_DATA_DIRECTORY In _DataDirectory Dim PointerToRawData As Integer = GetPointerToRawData(Directory.VirtualAddress) If PointerToRawData + Directory.Size > HighestOffset Then HighestOffset = PointerToRawData + Directory.Size End If Next Seek(HighestOffset) Return Read(CInt(_FileStream.Length) - HighestOffset) End If End Function Private Function GetPointerToRawData(virtualAddress As Integer) As Integer For Each Section As Win32.IMAGE_SECTION_HEADER In _SectionHeaders If (virtualAddress < Section.VirtualAddress) OrElse (virtualAddress > (Section.VirtualAddress + Section.SizeOfRawData)) Then Continue For End If Return Section.PointerToRawData + (virtualAddress - Section.VirtualAddress) Next Return -1 End Function Private Function GetDump(size As Integer) As Byte() If size = 0 Then Return New Byte() {} End If Dim Address As IntPtr = _Address Dim Protection As Integer = SetMemProtection(Address, size, PAGE_EXECUTE_READWRITE) If Protection = -1 Then Return New Byte() {} End If Dim Data As Byte() = Read(size) SetMemProtection(Address, size, Protection) Return Data End Function Private Function SetMemProtection(address As IntPtr, size As Integer, protection As Integer) As Integer If Not _IsRuntime Then Return 0 Dim OldProtection As Integer If Win32.VirtualProtectEx(_ProcessHandle, address, size, protection, OldProtection) = 0 Then If OldProtection = PAGE_NOACCESS Then Return -1 Else Throw New Win32Exception(Marshal.GetLastWin32Error()) End If End If Return OldProtection End Function #End Region #Region " State Handling " Private Sub ThrowOnDisposed() If _IsDisposed Then Throw New ObjectDisposedException([GetType]().FullName) End If End Sub Private Sub ThrowOnLoaded() If _IsLoaded Then Throw New Exception("An executable has already been loaded.") End If End Sub Private Sub ThrowOnNotLoaded() If Not _IsLoaded Then Throw New Exception("No executable has been loaded.") End If End Sub #End Region #Region " IDisposable " Protected Sub Dispose(disposing As Boolean) If Not _IsDisposed Then If disposing Then If _FileStream IsNot Nothing Then _FileStream.Close() End If End If Win32.CloseHandle(_ProcessHandle) End If _IsDisposed = True End Sub Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Public Sub Close() Dispose() End Sub #End Region End Class Public NotInheritable Class Win32 #Region " Methods " _ Public Shared Function OpenProcess( _ ByVal access As Integer, _ ByVal inherit As Boolean, _ ByVal processId As Integer) As IntPtr End Function _ Public Shared Function VirtualProtectEx( _ ByVal handle As IntPtr, _ ByVal address As IntPtr, _ ByVal size As Integer, _ ByVal newProtection As Integer, _ ByRef oldProtection As Integer) As Integer End Function _ Public Shared Function ReadProcessMemory( _ ByVal handle As IntPtr, _ ByVal address As IntPtr, _ ByVal data As Byte(), _ ByVal dataLength As Integer, _ ByRef length As Integer) As Boolean End Function _ Public Shared Function CloseHandle( _ ByVal handle As IntPtr) As Boolean End Function #End Region #Region " Structures " _ Public Structure IMAGE_DOS_HEADER Public e_magic As UShort Public e_cblp As UShort Public e_cp As UShort Public e_crlc As UShort Public e_cparhdr As UShort Public e_minalloc As UShort Public e_maxalloc As UShort Public e_ss As UShort Public e_sp As UShort Public e_csum As UShort Public e_ip As UShort Public e_cs As UShort Public e_lfarlc As UShort Public e_ovno As UShort _ Public e_res As UShort() Public e_oemid As UShort Public e_oeminfo As UShort _ Public e_res2 As UShort() Public e_lfanew As Integer 'NOTE: Should be unsigned End Structure _ Public Structure IMAGE_FILE_HEADER Public Machine As UShort Public NumberOfSections As UShort Public TimeDateStamp As Integer Public PointerToSymbolTable As Integer Public NumberOfSymbols As Integer Public SizeOfOptionalHeader As UShort Public Characteristics As UShort End Structure _ Public Structure IMAGE_OPTIONAL_HEADER32 Public Magic As UShort Public MajorLinkerVersion As Byte Public MinorLinkerVersion As Byte Public SizeOfCode As Integer Public SizeOfInitializedData As Integer Public SizeOfUninitializedData As Integer Public AddressOfEntryPoint As Integer Public BaseOfCode As Integer Public BaseOfData As Integer Public ImageBase As Integer Public SectionAlignment As Integer Public FileAlignment As Integer 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 Integer Public SizeOfImage As Integer Public SizeOfHeaders As Integer Public CheckSum As Integer Public Subsystem As UShort Public DllCharacteristics As UShort Public SizeOfStackReserve As Integer Public SizeOfStackCommit As Integer Public SizeOfHeapReserve As Integer Public SizeOfHeapCommit As Integer Public LoaderFlags As Integer Public NumberOfRvaAndSizes As Integer End Structure _ Public Structure IMAGE_OPTIONAL_HEADER64 Public Magic As UShort Public MajorLinkerVersion As Byte Public MinorLinkerVersion As Byte Public SizeOfCode As Integer Public SizeOfInitializedData As Integer Public SizeOfUninitializedData As Integer Public AddressOfEntryPoint As Integer Public BaseOfCode As Integer Public ImageBase As Long Public SectionAlignment As Integer Public FileAlignment As Integer 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 Integer Public SizeOfImage As Integer Public SizeOfHeaders As Integer Public CheckSum As Integer Public Subsystem As UShort Public DllCharacteristics As UShort Public SizeOfStackReserve As Long Public SizeOfStackCommit As Long Public SizeOfHeapReserve As Long Public SizeOfHeapCommit As Long Public LoaderFlags As Integer Public NumberOfRvaAndSizes As Integer End Structure _ Public Structure IMAGE_DATA_DIRECTORY Public VirtualAddress As Integer Public Size As Integer End Structure _ Public Structure IMAGE_SECTION_HEADER _ Public Name As String Public VirtualSize As Integer 'NOTE: Alias of Misc Public VirtualAddress As Integer Public SizeOfRawData As Integer Public PointerToRawData As Integer Public PointerToRelocations As Integer Public PointerToLineNumbers As Integer Public NumberOfRelocations As UShort Public NumberOfLineNumbers As UShort Public Characteristics As Integer End Structure #End Region End Class