Page 3 of 3

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:00
by Drugwash
Yep, looks good. If you could squeeze in the module count (maybe in the header, in left hand list?) it would be perfect. :)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:13
by jNizM
If I would minify the GetDllExports function to return the number of functions in a module it would looks like this. And every dll needs a call to this function for the listview.

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
}
If you find something else on your search engine here let me now =)

or do you mean the count of moduls in this listview?

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:34
by Drugwash
I meant the count of libraries/files (modules as you call them) in the selected directory.
I.e. user selects C:\Windows\System32 and the left-hand list displays XXXX Modules (or libraries or whatever) in its header. :)
May not be that important to most people but some control freaks (like me :D ) might get tipped off it the current count doesn't match the previous one.

I'll have to look again in my Pale Moon profile or just run it (ugh, the bloat I created there!) and then fire up all search engines, one at a time, and look at the queries. Tedious job, I tell you that. ;)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:41
by jNizM
Like this:
Image

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:51
by Drugwash
Yes, that's the idea. :thumbup:
Yikes, over 3000 libraries?! Gosh… :)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 05:54
by Helgef
:shock: Looks great!
Most wanted :D
  • Bookmark dll
  • Put GetProcAddress code to clipboard. Eg, clipboard = DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\LoadLibrary", "Str", ModuleName, "Ptr"), "AStr", Function Name, "Ptr")
If it is not of general interest, I might dig in and make it myself :wave:

Cheers.

Re: DLL Export Viewer

Posted: 03 Aug 2017, 06:24
by Drugwash
Getting procedure address for named functions may be of use sometimes, probably mostly when trying to improve script speed, but more useful would be for ordinals, where there's no function name to call directly.
Unfortunately I haven't seen any ordinals with this script… yet. ;)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 07:42
by jNizM
Where DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", ModuleName, "Ptr"), "AStr", FunctionName, "Ptr") is for already loaded library's like kernel32 / user32 / gdi32 /...
You should use LoadLibrary in place of GetModuleHandle if the dll is not already loaded.

But:
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.
We got this already discussed in an old thread of mine (https://autohotkey.com/boards/viewtopic ... 461#p46461)

@lexikos
Correct me if I missed something

Re: DLL Export Viewer

Posted: 03 Aug 2017, 07:53
by Helgef
It is not for explicit dllcalls, it is for passing fnptrs to compiled code.

Edit: I guess there isn't a general interest :D

Re: DLL Export Viewer

Posted: 03 Aug 2017, 07:59
by jNizM
So you want on the rightlick menu (or gui menu) a copy address of an exported function?
How should I name this? Copy ProcAddress or Copy FuncAddress or something else?

btw. can someone check the whole english part of the gui? it's not my main language :D

Re: DLL Export Viewer

Posted: 03 Aug 2017, 08:04
by Helgef
Where it is matters less, what I need in the clipboard is the explicit text,

Code: Select all

DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", ModuleName, "Ptr"), "AStr", FunctionName, "Ptr") 
where ModuleName and FunctionName matches whatever is selected. :)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 08:10
by Helgef
btw. can someone check the whole english part of the gui? it's not my main language
File -> Load Common Dll's change to -> File -> Load common Dlls. ' is for possessive, not plural.

I see nothing else.

Edit: ModuleName -> Module Name in the right ListView.

Re: DLL Export Viewer

Posted: 03 Aug 2017, 08:17
by jNizM
Changed =)
What do you mean with Bookmark?
Most used modules? If yes, that's why I added common dll's in menu.

If I move Module Name (List) to right the Expand Listview menu will be removed (no need any more)

Re: DLL Export Viewer

Posted: 03 Aug 2017, 08:52
by Helgef
With Bookmark, I mean something like save to ini file, so next time I load the app, I can select my favourite* modules from some list or something. Some dll names are hard for me to remember :facepalm: :oops:
*Yes, I have favourite modules :ugeek:
Edit
this one will be bigger and bigger
:dance:

Re: DLL Export Viewer

Posted: 03 Aug 2017, 09:09
by jNizM
I love one-file-ahk-projects.. but since this one will be bigger and bigger, I will move to includes now :? and will the first time (for me) add releases (x86.exe - x64.exe - ahk.zip)

Re: DLL Export Viewer

Posted: 09 Aug 2017, 09:04
by just me
This is rather a proof of concept than an improvement. I was wondering whether all needed information could be retrieved directly from the DLL file without calling external functions. Apparently ist's possible. The only required step seems to be to 'load' the section data contained in the file to their (relative) virtual addresses as defined in the section headers. After this the RVAs defined in the optional header data directory entry and the export directory table are matching the corresponding data.

It also demonstrates the power of AHK's File Object.

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
}

Re: DLL Export Viewer

Posted: 09 Aug 2017, 09:27
by Delta Pythagorean
@just me
That's quite an interesting take on this project. I'll say I now know how to return errorlevel with a number instead of just returning a normal number.

Re: DLL Export Viewer

Posted: 07 Feb 2020, 09:21
by jNizM
Edit
- rewritten

Re: DLL Export Viewer

Posted: 07 Feb 2020, 16:13
by TLM
Thanks @jNizM
Wish i'd seen this before trying to do it myself :headwall:

Re: DLL Export Viewer

Posted: 02 Dec 2022, 06:08
by jNizM