|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic System Services MapDebugInformation: Obtain Debugging Info for an Image |
||
Posted: | Saturday January 15, 2000 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB6, Windows NT4 | |
OS restrictions: | Requires Imagehlp.dll | |
Author: | Dev Ashish, VBnet - Randy Birch | |
Prerequisites |
Imagehlp.dll. Available as a redistributable for Windows 95. |
|
Those
who've used Microsoft's Dependency Walker (depends.exe) are familiar with the listing of exported functions / methods from DLL's. This code,
originally authored by Dev Ashish for use under MS Access, has been graciously
provided to VBnet by Dev. Using the MapDebugInformation API this code allows you to select any DLL (or any other file for that
matter) in order to see the names of any methods that might be exported by the file. Note that not all files export methods. And in
Windows parlance an executable file is an 'image' ... and an executable file can be either an exe or a dll
The MSDN offers the following explanation of imagehlp's MapDebugInformation API in a 1997 Under the Hood article by Matt Pietrek. Slightly paraphrased here to make sense taken out of context (from the entire article), it covers significantly more details than this demo shows, is included for its completeness (and to spark ideas). MapDebugInformation maps the executable file into memory, then figures out what the best type of symbol information is as well as some basic information about that symbol table. 'Best' means best - it turns out that an executable can be built with more than one type of debug information. For example, an executable can have both CodeView (PDB) information and a COFF symbol table. IMAGEHLP knows how to read both formats, as well as a few others, and knows which one is optimal for your executable. Once finished with the file, MapDebugInformation needs to be cleaned up by calling UnmapDebugInformation. Because in C the symbols for an executable may be in a file other than the executable itself (a debug file), the MapDebugInformation API can take a parameter specifying the symbol search path, if such a file was available. Besides mapping and loading the executable and its symbols (if present), the MapDebugInformation API returns a pointer to an IMAGE_DEBUG_INFORMATION structure. This structure contains many more fields than a LOADED_IMAGE structure (used with MapandLood), although nearly every field in the LOADED_IMAGE structure can be found in the IMAGE_DEBUG_INFORMATION structure. For example, the MappedBase field contains the address where the executable was mapped, and is the same as the MappedAddress field in a LOADED_IMAGE structure. Similarly, the Sections field is a pointer to the executable’s section table, and so forth. More useful information found in the IMAGE_DEBUG_INFORMATION structure includes the preferred load address (the ImageBase field), and the size of the executable in memory (the SizeOfImage field). There are also pointers to the table of names for the exported functions, as well as the executable’s time/date stamp DWORD. The meaning of some fields in the IMAGE_DEBUG_INFORMATION structure isn’t so obvious, like the pointers to Function and FPO tables. The Function table is data used by the structured exception handling code on the Alpha and MIPS platforms (it’s not encountered with Intel-based executables). FPO information is seen only on the Intel platform; it helps debuggers walk the call stack in the absence of standard EBP register stack frames. Finally, the IMAGE_DEBUG_INFORMATION has a variety of fields that indicate if CodeView and COFF information are present, and if so, where. There’s even a pointer to the debug directory. This is the data structure in the PE file that tells you what types of debug information are present and where. The MapDebugInformation API does a good job of extracting this information and presenting it in the IMAGE_DEBUG_INFORMATION structure. Still, if you’re so inclined, you can go straight to the same raw data that IMAGEHLP uses to generate the IMAGE_DEBUG_INFORMATION structure. Remember though, the whole advantage of using IMAGEHLP is to avoid such low-level grunginess. |
BAS Module Code |
None. |
|
Form Code |
To a form, add a command button, label, listbox and common dialog control. Use the default names and add the following code: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const GENERIC_READ = &H80000000 Private Const GENERIC_WRITE = &H40000000 Private Const INVALID_HANDLE_VALUE = -1 Private Const OPEN_EXISTING = 3 Private Const FILE_SHARE_READ = &H1 Private Const FILE_SHARE_WRITE = &H2 Private Const FILE_ATTRIBUTE_NORMAL = &H80 Private Const MAX_PATH As Long = 260 Private Type IMAGE_DEBUG_INFORMATION List As Long Size As Long MappedBase As Long Machine As Long Characteristics As Long CheckSum As Long ImageBase As Long SizeOfImage As Long NumberOfSections As Long Sections As Long 'pointer to a IMAGE_SECTION_HEADER type ExportedNamesSize As Long ExportedNames As Long NumberOfFunctionTableEntries As Long FunctionTableEntries As Long 'pointer to a IMAGE_FUNCTION_ENTRY type LowestFunctionStartingAddress As Long HighestFunctionEndingAddress As Long NumberOfFpoTableEntries As Long FpoTableEntries As Long SizeOfCoffSymbols As Long CoffSymbols As Long 'pointer to the COFF symbol table SizeOfCodeViewSymbols As Long CodeViewSymbols As Long ImageFilePath As Long ImageFileName As Long DebugFilePath As Long TimeDateStamp As Long RomImage As Long DebugDirectory As Long 'pointer to a IMAGE_DEBUG_DIRECTORY type NumberOfDebugDirectories As Long OriginalFunctionTableBaseAddress As Long Reserved0 As Long Reserved1 As Long Reserved2 As Long End Type Private Declare Function MapDebugInformation Lib "ImageHlp.dll" _ (ByVal FileHandle As Long, _ ByVal FileName As String, _ ByVal SymbolPath As String, _ ByVal ImageBase As Long) _ As Long Private Declare Function UnmapDebugInformation Lib "imagehlp.dll" _ (ByVal DebugInfo As Long) As Long Private Declare Function CreateFile Lib "kernel32" _ Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal lpSecurityAttributes As Long, _ ByVal dwCreationDisposition As Long, _ ByVal dwFlagsAndAttributes As Long, _ ByVal hTemplateFile As Long) _ As Long Private Declare Function CloseHandle Lib "kernel32" _ (ByVal hObject As Long) As Long Private Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long) Private Function GetFileImageInformation(sDLLName As String) As String On Local Error GoTo fileExport_error Dim IMGDBG As IMAGE_DEBUG_INFORMATION Dim hFile As Long Dim ptrDbg As Long Dim strOut As String Const ERR_GENERIC = vbObjectError + 5555 'obtain a handle to the specified file hFile = CreateFile(sDLLName, GENERIC_READ, _ FILE_SHARE_READ Or FILE_SHARE_WRITE, _ 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0&) 'if the handle is invalid, raise an 'error to properly clean up and exit If hFile = INVALID_HANDLE_VALUE Then Err.Raise ERR_GENERIC End If 'obtain a pointer to the image debug 'info in the passed file ptrDbg = MapDebugInformation(hFile, sDLLName, vbNullString, 0&) 'if the handle is invalid, raise an 'error to properly clean up and exit If ptrDbg = 0 Then Err.Raise ERR_GENERIC End If 'fill the UDT with the image debug info Call CopyMemory(IMGDBG, ByVal ptrDbg, Len(IMGDBG)) 'pad a string sufficiently large enough to 'receive the string of exported functions 'and copy the functions into the string. With IMGDBG strOut = String$(.ExportedNamesSize, vbNullChar) Call CopyMemory(ByVal strOut, ByVal .ExportedNames, .ExportedNamesSize) End With 'if the calls above are successful, and the 'file has exported methods, return the string 'consisting of a series of null-terminated 'strings naming all the functions exported 'from the image GetFileImageInformation = strOut fileExport_exit: Call UnmapDebugInformation(ptrDbg) Call CloseHandle(hFile) On Error GoTo 0 Exit Function fileExport_error: GetFileImageInformation = vbNullString Resume fileExport_exit End Function Private Sub Command1_Click() Dim sExports As String Dim tmp As String On Local Error GoTo enumdata_error 'set up the common dialog With CommonDialog1 .Flags = cdlOFNExplorer Or cdlOFNPathMustExist .CancelError = True .Filter = "DLL's (*.dll)|*.dll|OCX's (*.ocx)|*.ocx|All Files (*.*)|*.*" 'get the file .ShowOpen 'double check If Len(.FileName) > 0 Then 'set up the form List1.Clear Label1.Caption = LCase$(.FileName) 'retrieve the exported functions sExports = GetFileImageInformation(.FileName) 'double check If Len(sExports) > 0 Then 'remove an item from the string 'returned and add to the list Do While Len(sExports) > 0 List1.AddItem StripNulls(sExports) Loop End If 'If Len(sExports) End If 'If .FileName End With 'With CDlg1 enumdata_exit: Exit Sub enumdata_error: Label1.Caption = Err.Description Resume enumdata_exit End Sub Private Function StripNulls(startstr As String) As String Dim pos As Long pos = InStr(startstr, Chr$(0)) If pos Then StripNulls = Mid$(startstr, 1, pos - 1) startstr = Mid$(startstr, pos + 1, Len(startstr)) End If End Function |
Comments |
Try experimenting with the other attributes. Of particular interest might be the Checksum member of the UDT. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |