Results 1 to 8 of 8

Thread: Inside the executable: a VB programmer's guide to the portable executable format

  1. #1

    Thread Starter
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616

    Inside the executable: a VB programmer's guide to the portable executable format

    Introduction
    The Portable Executable Format is the data structure that describes how the various parts of a Win32
    executable file are held together. It allows the operating system to load the executable and to locate the dynamically
    linked libraries required to run that executable and to navigate the code,data and resource sections compiled into that
    executable.
    Getting over DOS
    The PE Format was created for Windows but Microsoft had to make sure that running such an executable in DOS would
    yield a meaningful error message and exit. To this end the very first bit of a windows executable file is actually a DOS
    executable (sometimes known as the stub) which writes "This program requires Windows" or similar then exits.
    The format of the DOS stub is:

    VB Code:
    1. Private Type IMAGE_DOS_HEADER
    2.     e_magic As Integer   ''\\ Magic number
    3.     e_cblp As Integer    ''\\ Bytes on last page of file
    4.     e_cp As Integer      ''\\ Pages in file
    5.     e_crlc As Integer    ''\\ Relocations
    6.     e_cparhdr As Integer ''\\ Size of header in paragraphs
    7.     e_minalloc As Integer ''\\ Minimum extra paragraphs needed
    8.     e_maxalloc As Integer ''\\ Maximum extra paragraphs needed
    9.     e_ss As Integer    ''\\ Initial (relative) SS value
    10.     e_sp As Integer    ''\\ Initial SP value
    11.     e_csum As Integer  ''\\ Checksum
    12.     e_ip As Integer  ''\\ Initial IP value
    13.     e_cs As Integer  ''\\ Initial (relative) CS value
    14.     e_lfarlc As Integer ''\\ File address of relocation table
    15.     e_ovno As Integer ''\\ Overlay number
    16.     e_res(0 To 3) As Integer ''\\ Reserved words
    17.     e_oemid As Integer ''\\ OEM identifier (for e_oeminfo)
    18.     e_oeminfo As Integer ''\\ OEM information; e_oemid specific
    19.     e_res2(0 To 9) As Integer ''\\ Reserved words
    20.     e_lfanew As Long ''\\ File address of new exe header
    21. End Type

    The only field of this structure that is of interest to Windows is e_lfanew which is the file pointer to the new
    Windows executable header. To skip over the DOS part of the program, set the file pointer to the value held in this field:

    VB Code:
    1. Private Sub SkipDOSStub(ByVal hfile As Long)
    2.  
    3. Dim BytesRead As Long
    4.  
    5. '\\ Go to start of file...
    6. Call SetFilePointer(hfile, 0, 0, FILE_BEGIN)
    7. If Err.LastDllError Then
    8.     Debug.Print LastSystemError
    9. End If
    10.  
    11. Dim stub As IMAGE_DOS_HEADER
    12. Call ReadFileLong(hfile, VarPtr(stub), Len(stub), BytesRead, ByVal 0&)
    13. Call SetFilePointer(hfile, stub.e_lfanew, 0, FILE_BEGIN)
    14.  
    15. End Sub

    The NT header
    The NT header holds the information needed by the windows program loader to load the program. It consists of the PE File signature
    followed by an IMAGE_FILE_HEADER and IMAGE_OPTIONAL_HEADER records.
    For applications designed to run under Windows (i.e. not OS/2 or VxD files) the four bytes of the PE File signature should equal &h4550.
    The other defined signatures are:

    VB Code:
    1. Public Enum ImageSignatureTypes
    2.     IMAGE_DOS_SIGNATURE = &H5A4D     ''\\ MZ
    3.     IMAGE_OS2_SIGNATURE = &H454E     ''\\ NE
    4.     IMAGE_OS2_SIGNATURE_LE = &H454C  ''\\ LE
    5.     IMAGE_VXD_SIGNATURE = &H454C     ''\\ LE
    6.     IMAGE_NT_SIGNATURE = &H4550      ''\\ PE00
    7. End Enum

    Following the PE file signature is the IMAGE_NT_HEADERS structure that stores information about the target environment of the executable.
    The structure is:

    VB Code:
    1. Private Type IMAGE_FILE_HEADER
    2.     Machine As Integer
    3.     NumberOfSections As Integer
    4.     TimeDateStamp As Long
    5.     PointerToSymbolTable As Long
    6.     NumberOfSymbols As Long
    7.     SizeOfOptionalHeader As Integer
    8.     Characteristics As Integer
    9. End Type

    The Machine member describes what target CPU the executable was compiled for. It can be one of:

    VB Code:
    1. Public Enum ImageMachineTypes
    2.     IMAGE_FILE_MACHINE_I386 = &H14C   ''\\ Intel 386.
    3.     IMAGE_FILE_MACHINE_R3000 = &H162  ''\\ MIPS little-endian,= &H160 big-endian
    4.     IMAGE_FILE_MACHINE_R4000 = &H166  ''\\ MIPS little-endian
    5.     IMAGE_FILE_MACHINE_R10000 = &H168  ''\\ MIPS little-endian
    6.     IMAGE_FILE_MACHINE_WCEMIPSV2 = &H169  ''\\ MIPS little-endian WCE v2
    7.     IMAGE_FILE_MACHINE_ALPHA = &H184      ''\\ Alpha_AXP
    8.     IMAGE_FILE_MACHINE_POWERPC = &H1F0    ''\\ IBM PowerPC Little-Endian
    9.     IMAGE_FILE_MACHINE_SH3 = &H1A2   ''\\ SH3 little-endian
    10.     IMAGE_FILE_MACHINE_SH3E = &H1A4  ''\\ SH3E little-endian
    11.     IMAGE_FILE_MACHINE_SH4 = &H1A6   ''\\ SH4 little-endian
    12.     IMAGE_FILE_MACHINE_ARM = &H1C0   ''\\ ARM Little-Endian
    13.     IMAGE_FILE_MACHINE_IA64 = &b00  ''\\ Intel 64
    14. End Enum

    The SizeOfOptionalHeader member indicates the size (in bytes) of the IMAGE_OPTIONAL_HEADER structure that immediatley follows it.
    In practice this structure is not optional so that is a bit of a misnomer. This structure is defined as:

    VB Code:
    1. Private Type IMAGE_OPTIONAL_HEADER
    2.     Magic As Integer
    3.     MajorLinkerVersion As Byte
    4.     MinorLinkerVersion As Byte
    5.     SizeOfCode As Long
    6.     SizeOfInitializedData As Long
    7.     SizeOfUninitializedData As Long
    8.     AddressOfEntryPoint As Long
    9.     BaseOfCode As Long
    10.     BaseOfData As Long
    11. End Type

    and this in turn is immediately followed by the IMAGE_OPTIONAL_HEADER_NT structure:

    VB Code:
    1. Private Type IMAGE_OPTIONAL_HEADER_NT
    2.     ImageBase As Long
    3.     SectionAlignment As Long
    4.     FileAlignment As Long
    5.     MajorOperatingSystemVersion As Integer
    6.     MinorOperatingSystemVersion As Integer
    7.     MajorImageVersion As Integer
    8.     MinorImageVersion As Integer
    9.     MajorSubsystemVersion As Integer
    10.     MinorSubsystemVersion As Integer
    11.     Win32VersionValue As Long
    12.     SizeOfImage As Long
    13.     SizeOfHeaders As Long
    14.     CheckSum As Long
    15.     Subsystem As Integer
    16.     DllCharacteristics As Integer
    17.     SizeOfStackReserve As Long
    18.     SizeOfStackCommit As Long
    19.     SizeOfHeapReserve As Long
    20.     SizeOfHeapCommit As Long
    21.     LoaderFlags As Long
    22.     NumberOfRvaAndSizes As Long
    23.     DataDirectory(0 To 15) As IMAGE_DATA_DIRECTORY
    24. End Type

    The most useful field of this structure (to my purposes, anyhow) are the 16 IMAGE_DATA_DIRECTORY entries. These describe whereabouts
    (if at all) the particular sections of the executable are located. The structure is defined thus:

    VB Code:
    1. Private Type IMAGE_DATA_DIRECTORY
    2.     VirtualAddress As Long
    3.     Size As Long
    4. End Type

    And the directories are held in order thus:

    VB Code:
    1. Public Enum ImageDataDirectoryIndexes
    2.     IMAGE_DIRECTORY_ENTRY_EXPORT = 0  ''\\ Export Directory
    3.     IMAGE_DIRECTORY_ENTRY_IMPORT = 1  ''\\ Import Directory
    4.     IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 ''\\ Resource Directory
    5.     IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3   ''\\ Exception Directory
    6.     IMAGE_DIRECTORY_ENTRY_SECURITY = 4   ''\\ Security Directory
    7.     IMAGE_DIRECTORY_ENTRY_BASERELOC = 5  ''\\ Base Relocation Table
    8.     IMAGE_DIRECTORY_ENTRY_DEBUG = 6   ''\\ Debug Directory
    9.     IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7   ''\\ Architecture Specific Data
    10.     IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8  ''\\ RVA of GP
    11.     IMAGE_DIRECTORY_ENTRY_TLS = 9  ''\\ TLS Directory
    12.     IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10    ''\\ Load Configuration Directory
    13.     IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11   ''\\ Bound Import Directory in headers
    14.     IMAGE_DIRECTORY_ENTRY_IAT = 12  ''\\ Import Address Table
    15.     IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13   ''\\ Delay Load Import Descriptors
    16. End Enum

    Note that is an executable does not contain one of the sections (as is often the case) there will be an IMAGE_DATA_DIRECTORY for it but the
    address and size will both be zero.
    The image data directories
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  2. #2

    Thread Starter
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    The image data directories...continued
    The exports directory
    The exports directory holds details of the functions exported by this executable. For example, if you were to look in the exports directory
    of the MSVBVM50.dll it would list all the functions it exports that make up the visual basic 5 runtime environment.
    This directory consists of some info to tell you how many exported functions there are followed by three parallel arrays which give you the
    address, name and ordinal of the functions respectively. The structure is defined thus:


    VB Code:
    1. Private Type IMAGE_EXPORT_DIRECTORY
    2.     Characteristics As Long
    3.     TimeDateStamp As Long
    4.     MajorVersion As Integer
    5.     MinorVersion As Integer
    6.     lpName As Long
    7.     Base As Long
    8.     NumberOfFunctions As Long
    9.     NumberOfNames As Long
    10.     lpAddressOfFunctions As Long    '\\ Three parrallel arrays...(LONG)
    11.     lpAddressOfNames As Long        '\\ (LONG)
    12.     lpAddressOfNameOrdinals As Long '\\ (INTEGER)
    13. End Type

    And you can read this info from the executable thus:

    VB Code:
    1. Private Sub ProcessExportTable(ExportDirectory As IMAGE_DATA_DIRECTORY)
    2.  
    3. Dim deThis As IMAGE_EXPORT_DIRECTORY
    4. Dim lBytesWritten As Long
    5. Dim lpAddress As Long
    6.  
    7. Dim nFunction As Long
    8.  
    9. If ExportDirectory.VirtualAddress &gt; 0 And ExportDirectory.Size &gt; 0 Then
    10.     '\\ Get the true address from the RVA
    11.     lpAddress = AbsoluteAddress(ExportDirectory.VirtualAddress)
    12.     '\\ Copy the image_export_directory structure...
    13.     Call ReadProcessMemoryLong(DebugProcess.Handle, lpAddress, VarPtr(deThis), Len(deThis), lBytesWritten)
    14.     With deThis
    15.         If .lpName &lt;&gt; 0 Then
    16.             image.Name = StringFromOutOfProcessPointer(DebugProcess.Handle, image.AbsoluteAddress(.lpName), 32, False)
    17.         End If
    18.         If .NumberOfFunctions &gt; 0 Then
    19.             For nFunction = 1 To .NumberOfFunctions
    20.                 lpAddress = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(.lpAddressOfNames) + ((nFunction - 1) * 4))
    21.                 fExport.Name = StringFromOutOfProcessPointer(DebugProcess.Handle, image.AbsoluteAddress(lpAddress), 64, False)
    22.                 fExport.Ordinal = .Base + IntegerFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(.lpAddressOfNameOrdinals) + ((nFunction - 1) * 2))
    23.                 fExport.ProcAddress = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(.lpAddressOfFunctions) + ((nFunction - 1) * 4))
    24.             Next nFunction
    25.         End If
    26.     End With
    27. End If
    28.  
    29.    
    30. End Sub


    The imports directory
    The imports directory lists the dynamic link libraries that this executable depends on and which functions it imports from that dynamic link library.
    It consists of an array of IMAGE_IMPORT_DESCRIPTOR structures terminated by an instance of this structure where the lpName parameter is zero.
    The structure is defined as:


    VB Code:
    1. Private Type IMAGE_IMPORT_DESCRIPTOR
    2.     lpImportByName As Long ''\\ 0 for terminating null import descriptor
    3.     TimeDateStamp As Long  ''\\ 0 if not bound,
    4.                            ''\\ -1 if bound, and real date\time stamp
    5.                            ''\\ in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
    6.                            ''\\ O.W. date/time stamp of DLL bound to (Old BIND)
    7.     ForwarderChain As Long ''\\ -1 if no forwarders
    8.     lpName As Long
    9.     lpFirstThunk As Long ''\\ RVA to IAT (if bound this IAT has actual addresses)
    10. End Type

    And you can walk the import directory thus:

    VB Code:
    1. Private Sub ProcessImportTable(ImportDirectory As IMAGE_DATA_DIRECTORY)
    2.  
    3. Dim lpAddress As Long
    4. Dim diThis As IMAGE_IMPORT_DESCRIPTOR
    5. Dim byteswritten As Long
    6. Dim sName As String
    7. Dim lpNextName As Long
    8. Dim lpNextThunk As Long
    9.  
    10. Dim lImportEntryIndex As Long
    11.  
    12. Dim nOrdinal As Integer
    13. Dim lpFuncAddress As Long
    14.  
    15.  
    16. '\\ If the image has an imports section...
    17. If ImportDirectory.VirtualAddress &gt; 0 And ImportDirectory.Size &gt; 0 Then
    18.     '\\ Get the true address from the RVA
    19.     lpAddress = AbsoluteAddress(ImportDirectory.VirtualAddress)
    20.     Call ReadProcessMemoryLong(DebugProcess.Handle, lpAddress, VarPtr(diThis), Len(diThis), byteswritten)
    21.    
    22.     While diThis.lpName &lt;&gt; 0
    23.         '\\ Process this import directory entry
    24.         sName = StringFromOutOfProcessPointer(DebugProcess.Handle, image.AbsoluteAddress(diThis.lpName), 32, False)
    25.  
    26.         '\\ Process the import file's functions list
    27.         If diThis.lpImportByName &lt;&gt; 0 Then
    28.             lpNextName = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(diThis.lpImportByName))
    29.             lpNextThunk = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(diThis.lpFirstThunk))
    30.             While (lpNextName &lt;&gt; 0) And (lpNextThunk &lt;&gt; 0)
    31.                 '\\ get the function address
    32.                 lpFuncAddress = LongFromOutOfprocessPointer(DebugProcess.Handle, lpNextThunk)
    33.                 nOrdinal = IntegerFromOutOfprocessPointer(DebugProcess.Handle, lpNextName)
    34.                 '\\ Skip the two-byte ordinal hint
    35.                 lpNextName = lpNextName + 2
    36.                 '\\ Get this function's name
    37.                 sName = StringFromOutOfProcessPointer(DebugProcess.Handle, image.AbsoluteAddress(lpNextName), 64, False)
    38.                 If Trim$(sName) &lt;&gt; "" Then
    39.                     '\\ Get the next imported function...
    40.                     lImportEntryIndex = lImportEntryIndex + 1
    41.                     lpNextName = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(diThis.lpImportByName + (lImportEntryIndex * 4)))
    42.                     lpNextThunk = LongFromOutOfprocessPointer(DebugProcess.Handle, image.AbsoluteAddress(diThis.lpFirstThunk + (lImportEntryIndex * 4)))
    43.                 Else
    44.                     lpNextName = 0
    45.                 End If
    46.             Wend
    47.         End If
    48.                
    49.         '\\ And get the next one
    50.         lpAddress = lpAddress + Len(diThis)
    51.         Call ReadProcessMemoryLong(DebugProcess.Handle, lpAddress, VarPtr(diThis), Len(diThis), byteswritten)
    52.     Wend
    53.  
    54. End If
    55.    
    56. End Sub

    The resource directory
    The structure of the resource director is somewhat more involved. It consists of a root directory (defined by the structure
    IMAGE_RESOURCE_DIRECTORY immediately followed by a number of resource directory entries (defined by the structure
    IMAGE_RESOURCE_DIRECTORY_ENTRY
    ). These are defined thus:

    VB Code:
    1. Private Type IMAGE_RESOURCE_DIRECTORY
    2.     Characteristics As Long '\\Seems to be always zero?
    3.     TimeDateStamp As Long
    4.     MajorVersion As Integer
    5.     MinorVersion As Integer
    6.     NumberOfNamedEntries As Integer
    7.     NumberOfIdEntries As Integer
    8. End Type
    9.  
    10. Private Type IMAGE_RESOURCE_DIRECTORY_ENTRY
    11.     dwName As Long
    12.     dwDataOffset As Long
    13.     CodePage As Long
    14.     Reserved As Long
    15. End Type

    Each resource directory entry can either point to the actual resource data or to another layer of resource directory entries. If the highest bit of
    dwDataOffset is set then this points to a directory otherwise it points to the resource data.

    How is this information useful?
    Once you know how an executable is put together you can use this information to peer into its workings. You can view the resources compiled into
    it, the dlls it depends on and the actual functions it imports from them. More importantly you can attach to the executable as a debugger and
    track down any of those really troublesome general protection faults. The next article will describe how to attach a debugger and use the PE file
    format.
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  3. #3
    Frenzied Member KayJay's Avatar
    Join Date
    Jul 2001
    Location
    Chennai
    Posts
    1,849
    Hi Duncan! LTNS! How are you?

    I know its a bit dated - this thread - but I could sure do with some help

    Note
    It's no virus, as in it's not malicious. All users will be aware of whats going on, though not how it's carried out. Hey, thats where I get my bread and butter from

    The Prob.
    All commericial and hacker tooled (and the crappy one I coded in VB) EXE Joiners rely solely on the System Temp or some other Hard Disk dump area, to de-bundle and execute the joined executables from that directory. No can do for my App, as its run off a CD-ROM with extensive "App.Path" dependencies.

    The Q.
    Would it be possible to crack open an EXE with what you have listed above and insert another arbitary EXE which is to be executed when the EXE is launched? If so, could you point me to how to get it done. If not, thanx for taking the time to answer.

    Regards

    Kaushik Janardhanan

    "Brothers, you asked for it."
    ...Francisco Domingo Carlos Andres Sebastian D'Anconia

  4. #4
    PowerPoster
    Join Date
    Jul 2002
    Location
    Dublin, Ireland
    Posts
    2,148
    Introduction
    [P]Windows NT (and successive operating system versions) expose a set of API functions and structures for debugging a running process. This article shows how these can be accessed from Visual Basic (version 5 or 6). It is recomended that the article [a href="http://www.thecodeproject.com/win32/vbdebugger.asp"]Inside the executable: an introduction to the Portable Executable format for VB programmers[/a] be read in conjunction with this article, and the source code attached to it has the code for this article included. [/P]

    Getting a process to debug
    [P]There are two ways to get a process to debug. Either (a) attach a debugger to a process that is already running or (b) start a new process with a debugger attached to it.[/P]

    Starting a new process with a debugger attached
    [P]To start a process you can use the CreateProcess API call:[/P]
    VB Code:
    1. Private Declare Function CreateProcess Lib _
    2.     "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, _
    3.                                        ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, _
    4.                                        ByVal dwCreationFlags As ProcessCreationFlags, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
    [P]In addition to the functionality of the Shell command this allows you to specify additional flags that affect how the process is created:[/p]
    VB Code:
    1. Public Enum ProcessCreationFlags
    2.     DEBUG_PROCESS = &H1
    3.     DEBUG_ONLY_THIS_PROCESS = &H2
    4.     CREATE_SUSPENDED = &H4
    5.     DETACHED_PROCESS = &H8
    6.     CREATE_NEW_CONSOLE = &H10
    7.     NORMAL_PRIORITY_CLASS = &H20
    8.     IDLE_PRIORITY_CLASS = &H40
    9.     HIGH_PRIORITY_CLASS = &H80
    10.     REALTIME_PRIORITY_CLASS = &H100
    11.     CREATE_NEW_PROCESS_GROUP = &H200
    12.     CREATE_UNICODE_ENVIRONMENT = &H400
    13.     CREATE_SEPARATE_WOW_VDM = &H800
    14.     CREATE_SHARED_WOW_VDM = &H1000
    15.     CREATE_FORCEDOS = &H2000
    16.     CREATE_DEFAULT_ERROR_MODE = &H4000000
    17.     CREATE_NO_WINDOW = &H8000000
    18. End Enum
    [P]In order to start the process with an attached debugger you specify the flags DEBUG_PROCESS + DEBUG_ONLY_THIS_PROCESS
    [/P]

    Attaching a debugger to an existing process
    [P]To attach a debugger to a process which is already running you need to obtain a handle to it and then attach a debugger using the DebugActiveProcess API call[/P]
    VB Code:
    1. Private Declare Function DebugActiveProcess Lib "kernel32" (ByVal dwProcessId As Long) As Long

    The debug loop
    [P]Once you have attached your debugger to the process you need to go into a debug loop. This consists of waiting for a debug event, processing the event when it comes in and then allowing the debugee to continue.[/P]
    Waiting for a debug event to occur
    [P]To wait for a debug event you call the WaitForDebugEvent API call:[/P]
    VB Code:
    1. Private Declare Function WaitForDebugEvent Lib "kernel32" (lpDebugEvent As DEBUG_EVENT_BUFFER, ByVal dwMilliseconds As Long) As Long
    [P]This will return TRUE when a debug event has occured and fill out the DEBUG_EVENT_... structure, which depends on what event occured but always starts with a DEBUG_EVENT_HEADER:[/P]
    VB Code:
    1. Private Type DEBUG_EVENT_HEADER
    2.     dwDebugEventCode As DebugEventTypes
    3.     dwProcessId As Long
    4.     dwThreadId As Long
    5. End Type
    Processing the debug event
    [P]How you deal with a debug event depends, naturally enough, on what event occured. The event types are:[/P]
    VB Code:
    1. Public Enum DebugEventTypes
    2.     EXCEPTION_DEBUG_EVENT = 1&
    3.     CREATE_THREAD_DEBUG_EVENT = 2&
    4.     CREATE_PROCESS_DEBUG_EVENT = 3&
    5.     EXIT_THREAD_DEBUG_EVENT = 4&
    6.     EXIT_PROCESS_DEBUG_EVENT = 5&
    7.     LOAD_DLL_DEBUG_EVENT = 6&
    8.     UNLOAD_DLL_DEBUG_EVENT = 7&
    9.     OUTPUT_DEBUG_STRING_EVENT = 8&
    10.     RIP_EVENT = 9&
    11. End Enum

    [P]EXCEPTION_DEBUG_EVENT[/P]
    [P]This debug event is thrown whenever an exception occurs in the application being debugged. For example if there was code in that application that was attempting to divide by zero then you would get an EXCEPTION_DEBUG_EVENT. The buffer that is passed back for this event is:[/P]
    VB Code:
    1. Public Enum ExceptionCodes
    2.     EXCEPTION_GUARD_PAGE_VIOLATION = &H80000001
    3.     EXCEPTION_DATATYPE_MISALIGNMENT = &H80000002
    4.     EXCEPTION_BREAKPOINT = &H80000003
    5.     EXCEPTION_SINGLE_STEP = &H80000004
    6.     EXCEPTION_ACCESS_VIOLATION = &HC0000005
    7.     EXCEPTION_IN_PAGE_ERROR = &HC0000006
    8.     EXCEPTION_INVALID_HANDLE = &HC0000008
    9.     EXCEPTION_NO_MEMORY = &HC0000017
    10.     EXCEPTION_ILLEGAL_INSTRUCTION = &HC000001D
    11.     EXCEPTION_NONCONTINUABLE_EXCEPTION = &HC0000025
    12.     EXCEPTION_INVALID_DISPOSITION = &HC0000026
    13.     EXCEPTION_ARRAY_BOUNDS_EXCEEDED = &HC000008C
    14.     EXCEPTION_FLOAT_DENORMAL_OPERAND = &HC000008D
    15.     EXCEPTION_FLOAT_DIVIDE_BY_ZERO = &HC000008E
    16.     EXCEPTION_FLOAT_INEXACT_RESULT = &HC000008F
    17.     EXCEPTION_FLOAT_INVALID_OPERATION = &HC0000090
    18.     EXCEPTION_FLOAT_OVERFLOW = &HC0000091
    19.     EXCEPTION_FLOAT_STACK_CHECK = &HC0000092
    20.     EXCEPTION_FLOAT_UNDERFLOW = &HC0000093
    21.     EXCEPTION_INTEGER_DIVIDE_BY_ZERO = &HC0000094
    22.     EXCEPTION_INTEGER_OVERFLOW = &HC0000095
    23.     EXCEPTION_PRIVILEGED_INSTRUCTION = &HC0000096
    24.     EXCEPTION_STACK_OVERFLOW = &HC00000FD
    25.     EXCEPTION_CONTROL_C_EXIT = &HC000013A
    26. End Enum
    27.  
    28. Public Enum ExceptionFlags
    29.     EXCEPTION_CONTINUABLE = 0
    30.     EXCEPTION_NONCONTINUABLE = 1   '\\ Noncontinuable exception
    31. End Enum
    32.  
    33. Private Type DEBUG_EXCEPTION_DEBUG_INFO
    34.     Header As DEBUG_EVENT_HEADER
    35.     ExceptionCode                                        As ExceptionCodes
    36.     ExceptionFlags                                       As ExceptionFlags
    37.     pExceptionRecord                                     As Long
    38.     ExceptionAddress                                     As Long
    39.     NumberParameters                                     As Long
    40.     ExceptionInformation(EXCEPTION_MAXIMUM_PARAMETERS)   As Long
    41.     dwFirstChance As Long
    42. End Type
    [P]The exception flags tell you if it is possible to resume from the exception or not[/P]

    [P]CREATE_THREAD_DEBUG_EVENT[/P]
    [P]This event occurs whenever a new thread is created by the debugee application. The buffer that is passed in is:[/P]
    VB Code:
    1. Private Type DEBUG_CREATE_THREAD_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     hThread As Long
    4.     lpThreadLocalBase As Long
    5.     lpStartAddress As Long
    6. End Type
    [P]This gives you a thread handle (for thread control API calls) and the base address and start address of the thread in the debugee process which is useful for analysing the memory of that application[/P]

  5. #5
    PowerPoster
    Join Date
    Jul 2002
    Location
    Dublin, Ireland
    Posts
    2,148
    CREATE_PROCESS_DEBUG_EVENT
    This event occurs when the process is created. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_CREATE_PROCESS_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     hfile As Long
    4.     hProcess As Long
    5.     hThread As Long
    6.     lpBaseOfImage As Long
    7.     dwDebugInfoFileOffset As Long
    8.     nDebugInfoSize As Long
    9.     lpThreadLocalBase As Long
    10.     lpStartAddress As Long
    11.     lpImageName As Long
    12.     fUnicode As Integer
    13. End Type
    You can use the file handle passed in as part of this buffer to find the different parts of the process (imports section, exports, debug information etc.) as per this article

    EXIT_THREAD_DEBUG_EVENT
    This event occurs when a thread exits. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_EXIT_THREAD_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     dwExitCode As Long
    4. End Type
    The exit code is whatever the thread set it to but is usually set to be non zero if an error caused the thread exit

    EXIT_PROCESS_DEBUG_EVENT
    This event occurs when the process exits. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_EXIT_PROCESS_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     dwExitCode As Long
    4. End Type
    The exit code is whatever the process set it to but is usually set to be non zero if an error caused the thread exit. You should stop the debug loop after you recieve this event.


    LOAD_DLL_DEBUG_EVENT
    This event occurs when teh application being debugged loads a dynamic link library. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_LOAD_DLL_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     hfile As Long
    4.     lpBaseOfDll As Long
    5.     dwDebugInfoFileOffset As Long
    6.     nDebugInfoSize As Long
    7.     lpImageName As Long
    8.     fUnicode As Integer
    9. End Type
    You can use the file handle passed in as part of this buffer to find the different parts of the dll (imports section, exports, debug information etc.) as per this article

    UNLOAD_DLL_DEBUG_EVENT
    This event occurs when the process being debugged unloads a dll it had loaded. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_UNLOAD_DLL_DEBUG_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     lpBaseOfDll As Long
    4. End Type
    And you can use the lpBaseOfDll value to identify which dll was unloaded

    OUTPUT_DEBUG_STRING_EVENT
    This event occurs when the debugee calls the API call OutputDebugString to send debugging information to a debugger (where one is attached). The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_OUTPUT_DEBUG_STRING_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     lpDebugStringData As Long
    4.     fUnicode As Integer
    5.     nDebugStringLength As Integer
    6. End Type
    And you can read the string from the debugee using the ReadProcessMemory API call

    RIP_EVENT
    This occurs if your process being debugged dies unexpectedly. The buffer passed in is:
    VB Code:
    1. Private Type DEBUG_RIP_INFO
    2.     Header As DEBUG_EVENT_HEADER
    3.     dwError As Long
    4.     dwType As Long
    5. End Type

    Resuming the debugee
    Once you have extracted the information you need form the debug event you need to resume the debugee so that it can continue running. To do this you call the ContinueDebugEvent API call:
    VB Code:
    1. Public Enum DebugStates
    2.     DBG_CONTINUE = &H10002
    3.     DBG_TERMINATE_THREAD = &H40010003
    4.     DBG_TERMINATE_PROCESS = &H40010004
    5.     DBG_CONTROL_C = &H40010005
    6.     DBG_CONTROL_BREAK = &H40010008
    7.     DBG_EXCEPTION_NOT_HANDLED = &H80010001
    8. End Enum
    9.  
    10. Private Declare Function ContinueDebugEvent Lib "kernel32" (ByVal dwProcessId As Long, ByVal dwThreadId As Long, ByVal dwContinueStatus As DebugStates) As Long

    Further development
    To expand on this framework and create a full debugger requires the ability to walk the memory and stack of the process being debugged and also to set breakpoints. I hope to get to this in the next article

  6. #6
    I'm about to be a PowerPoster! mendhak's Avatar
    Join Date
    Feb 2002
    Location
    Ulaan Baator GooGoo: Frog
    Posts
    38,173
    Good post, Merrion. Seems useful, and I should be able to understand it completely after a couple more reads. Right now it's some at a time.

  7. #7

    Thread Starter
    Frenzied Member MerrionComputin's Avatar
    Join Date
    Apr 2001
    Location
    Dublin, Ireland
    Posts
    1,616
    There's source code too - bit scary but if you trace through it you should see how it all hangs together.

    Note : do not debug apps without saving your work first - this can lead to things falling over...
    Attached Files Attached Files
    ----8<---------------------------------------
    NEW - The .NET printer queue monitor component
    ----8<---------------------------------------
    Now with Examples of use

  8. #8

    Re: Inside the executable: a VB programmer's guide to the portable executable format

    Talk about digging up old threads.
    Merrion, I saw your code for the PE_Utilities.bas posted on another website can't remember where now. I was trying to convert it over to vb2005 but it is throwing to many errors for me. I'm a hobbiest programmer.

    I was wondering if you ever converted this code over to vb.net or if you knew of a way to get header info from a file to determine if it is a exe, dll, sys or whichever executable type in vb.net

    Hope you can help,
    Dave

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width