Re: DLL Export Viewer
Posted: 03 Aug 2017, 05:00
Yep, looks good. If you could squeeze in the module count (maybe in the header, in left hand list?) it would be perfect.
Code: Select all
MsgBox % GetNumberOfFunctions("gdi32.dll") ; -> 923 on Win10
GetNumberOfFunctions(DllFile)
{
VarSetCapacity(LOADED_IMAGE, 88, 0)
if (DllCall("imagehlp\MapAndLoad", "astr", DllFile, "ptr", 0, "ptr", &LOADED_IMAGE, "int", 1, "int", 1)) {
Machine := NumGet(NumGet(LOADED_IMAGE, A_PtrSize * 3, "uptr") + 4, "ushort")
if (Machine = 0x014c) || (Machine = 0x8664)
if (IMAGE_EXPORT_DIRECTORY := DllCall("imagehlp\ImageDirectoryEntryToData", "ptr", NumGet(LOADED_IMAGE, A_PtrSize * 2, "uptr"), "int", 0, "ushort", 0, "uint*", size, "uptr"))
NumberOfNames := NumGet(IMAGE_EXPORT_DIRECTORY + 0x18, "uint")
DllCall("imagehlp\UnMapAndLoad", "ptr", &LOADED_IMAGE)
}
return NumberOfNames
}
We got this already discussed in an old thread of mine (https://autohotkey.com/boards/viewtopic ... 461#p46461)lexikos wrote:It's also completely ineffective to do the GetProcAddress "optimization" for functions in DLLs which AutoHotkey imports (i.e. because they are always resolved at startup). At minimum, that includes User32.dll, Kernel32.dll, ComCtl32.dll, and Gdi32.dll. That is, unless the function name is an expression/variable.
Code: Select all
DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", ModuleName, "Ptr"), "AStr", FunctionName, "Ptr")
File -> Load Common Dll's change to -> File -> Load common Dlls. ' is for possessive, not plural.btw. can someone check the whole english part of the gui? it's not my main language
this one will be bigger and bigger
Code: Select all
#NoEnv
SetBatchLines, -1
DllFile := A_WinDir . "\System32\Ntdll.dll"
S := A_TickCount
Exports := DllExports(DllFile)
T := A_TickCount - S
Module := Exports.Module
Named := Exports.Named
Bitness := Exports.Bitness
OrdBase := Exports.OrdBase
Gui, Add, ListView, xm ym w800 h450 Count%Named% vMyLV1 hWndhMyLV1 +LV0x14000, Ordinal|Function Name|Entry Point (RVA)
For Index, Function In Exports.Functions
LV_Add("", Function.Ordinal, Function.Name, Function.EntryPoint)
LV_ModifyCol(1, "Integer 50")
LV_ModifyCol(2, "AutoHdr")
LV_ModifyCol(3, "AutoHdr")
Gui, Add, StatusBar
SB_SetText(" Module: " . Module . " - " . Bitness . "-bit - " . Named . " named functions - ordinal base: " . OrdBase)
Gui, Show, , %DllFile% (%T% ms)
Return
; --------------------------------------------------------------------------------------------------------------------------------
GuiClose:
ExitApp
; ================================================================================================================================
DllExports(DllPath) {
Static LocSignatureOff := 0x3C ; location of the file offset to the PE signature
Static SizeOfSignature := 4 ; size of the PE signature
Static SizeOfCoffHdr := 20 ; size of the COFF header
Static SizeOfSectionHdr := 40 ; size of a section header
; Check the file path ---------------------------------------------------------------------------------------------------------
SplitPath, DllPath, , , FileExt
If (FileExt <> "dll")
Return !(ErrorLevel := 1) ; invalid file extension
; Open the file ---------------------------------------------------------------------------------------------------------------
If !(DllFile := FileOpen(DllPath, "r"))
Return !(ErrorLevel := 2) ; could not open the file for reading
If (DllFile.Pos <> 0)
Return !(ErrorLevel := 3) ; AHK found a BOM, it isn't a DLL
; MS-DOS header----------------------------------------------------------------------------------------------------------------
DllFile.RawRead(RawBytes, 2)
If !(StrGet(&RawBytes, 2, "CP0") == "MZ")
Return !(ErrorLevel := 4) ; no MS-DOS stub
; PE Signature ----------------------------------------------------------------------------------------------------------------
DllFile.Pos := LocSignatureOff
DllFile.Pos := DllFile.ReadUInt() ; offset to the PE signature
; Read the signature and advance the file pointer to the begin of the COFF header.
DllFile.RawRead(RawBytes, SizeOfSignature)
If !(StrGet(&RawBytes, SizeOfSignature, "CP0") == "PE")
Return !(ErrorLevel := 5) ; no PE file
; COFF header -----------------------------------------------------------------------------------------------------------------
; Machine types: IMAGE_FILE_MACHINE_I386 (x86) = 0x014C, IMAGE_FILE_MACHINE_AMD64 (x64) = 0x8664
; Characteristics: IMAGE_FILE_DLL = 0x2000
; Read the COFF file header and advance the file pointer to the begin of the optional header.
DllFile.RawRead(RawBytes, SizeOfCoffHdr)
Machine := NumGet(RawBytes, 0, "UShort") ; the type of the target machine
If (Machine <> 0x014C) && (Machine <> 0x8664)
Return !(ErrorLevel := 6) ; wrong CPU type
NumberOfSections := NumGet(RawBytes, 2, "UShort") ; the number of section headers
SizeOfOptionalHeader := NumGet(RawBytes, 16, "UShort") ; the size of the optional header (required for DLL files)
Characteristics := NumGet(RawBytes, 18, "UShort") ; the attributes of the file
If !(Characteristics & 0x2000) ; IMAGE_FILE_DLL
Return !(ErrorLevel := 7) ; not a valid DLL file
; Optional header -------------------------------------------------------------------------------------------------------------
; PE format (magic number): PE32 (32-bit) = 0x010B, PE32+ (64-bit) = 0x020B
; Read the optional header and advance the file pointer to the begin of the section headers.
DllFile.RawRead(RawBytes, SizeOfOptionalHeader)
Magic := NumGet(RawBytes, 0, "UShort") ; the state of the image file
Off_64 := (Magic = 0x020B) ? 16 : 0 ; additional offset for 64-bit, zero for 32-bit
SizeOfImage := NumGet(RawBytes, 56, "UInt") ; the size of the image as loaded into memory
OffSet := 92 + Off_64
If ((NumberOfRvaAndSizes := NumGet(RawBytes, Offset + 0, "UInt")) < 1) ; the number of data directory entries
|| ((ExportAddr := NumGet(RawBytes, Offset + 4, "UInt")) < 1) ; the address of the export table (RVA)
|| ((ExportSize := NumGet(RawBytes, Offset + 8, "UInt")) < 1) ; the size of the export table
Return !(ErrorLevel := 8) ; couldn't find an export table
; Section headers -------------------------------------------------------------------------------------------------------------
; The section data have to be 'loaded' to the relative virtual addresses defined in the section headers.
; Otherwise, the RVAs defined in the export table don't match the corresponding data.
; Read the section headers
SectionsLength := SizeOfSectionHdr * NumberOfSections
DllFile.RawRead(RawBytes, SectionsLength)
; 'Load' the sections.
VarSetCapacity(ImageData, SizeOfImage, 0) ; create a variable capable to store the sections data
Offset := 0
Loop, %NumberOfSections%
{
VirtualAddress := NumGet(RawBytes, Offset + 12, "UInt")
SizeOfRawData := NumGet(RawBytes, Offset + 16, "UInt")
PointerToRawData := NumGet(RawBytes, Offset + 20, "UInt")
DllFile.Pos := PointerToRawData
DllFile.RawRead(&ImageData + VirtualAddress, SizeOfRawData)
Offset += SizeOfSectionHdr
}
; Export table ----------------------------------------------------------------------------------------------------------------
ImageBase := &ImageData ; the address of the string buffer of ImageData is used as image base address.
EndOfSection := ExportAddr + ExportSize
ModNamePtr := NumGet(ImageBase + ExportAddr + 0x0C, "UInt") ; pointer to an ASCII string that contains the name of the DLL
OrdinalBase := NumGet(ImageBase + ExportAddr + 0x10, "UInt") ; starting ordinal number for exports in this image
FuncCount := NumGet(ImageBase + ExportAddr + 0x14, "UInt") ; number of entries in the export address table
NameCount := NumGet(ImageBase + ExportAddr + 0x18, "UInt") ; number of entries in the name pointer table
FuncTblPtr := NumGet(ImageBase + ExportAddr + 0x1C, "uint") ; pointer to the export address table
NameTblPtr := NumGet(ImageBase + ExportAddr + 0x20, "UInt") ; pointer to the export name pointer table
OrdTblPtr := NumGet(ImageBase + ExportAddr + 0x24, "UInt") ; pointer to the ordinal table
Exports := {Module: StrGet(ImageBase + ModNamePtr, "CP0")
, Total: FuncCount
, Named: NameCount
, OrdBase: OrdinalBase
, Bitness: (Magic = 0x020B) ? 64 : 32
, Functions: []}
Loop %NameCount%
{
NamePtr := NumGet(ImageBase + NameTblPtr, "UInt")
Ordinal := NumGet(ImageBase + OrdTblPtr, "UShort")
FnAddr := NumGet(ImageBase + FuncTblPtr + (Ordinal * 4), "UInt")
EntryPt := (FnAddr > ExportAddr) && (FnAddr < EndOfSection) ? StrGet(ImageBase + FnAddr, "CP0")
: Format("0x{:08X}", FnAddr)
Exports.Functions.Push({Name: StrGet(ImageBase + NamePtr, "CP0"), EntryPoint: EntryPt, Ordinal: Ordinal + OrdinalBase})
NameTblPtr += 4, OrdTblPtr += 2
}
VarSetCapacity(ImageData, 0) ; free the memory used to store the image data
Return Exports
}