DllListExports() - List of Function exports of a DLL

Post your working scripts, libraries and tools
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

DllListExports() - List of Function exports of a DLL

13 Sep 2014, 21:25

DllListExports(). Rewrite of PE_FunctionExports()
- AutoHotkey 1.1 and 2.0
Usage example: MsgBox % DllListExports( "shell32.dll" )

Code: Select all

/*
 _      _    _               __ __      _      _                      _         _                        
| |__  | |_ | |_  _ __  _   / // /__ _ | |__  | | __ ___   ___  _ __ (_) _ __  | |_     ___   _ __  __ _ 
| '_ \ | __|| __|| '_ \(_) / // // _` || '_ \ | |/ // __| / __|| '__|| || '_ \ | __|   / _ \ | '__|/ _` |
| | | || |_ | |_ | |_) |_ / // /| (_| || | | ||   < \__ \| (__ | |   | || |_) || |_  _| (_) || |  | (_| |
|_| |_| \__| \__|| .__/(_)_//_/  \__,_||_| |_||_|\_\|___/ \___||_|   |_|| .__/  \__|(_)\___/ |_|   \__, |
                 |_|                                                    |_|                        |___/ 
DllListExports() - List of Function exports of a DLL  |  http://ahkscript.org/boards/viewtopic.php?t=4563
Author: Suresh Kumar A N ( arian.suresh@gmail.com )        
_________________________________________________________________________________________________________
*/

DllListExports( DLL, Hdr := 0 ) {   ;   By SKAN,  http://goo.gl/DsMqa6 ,  CD:26/Aug/2010 | MD:14/Sep/2014         

Local LOADED_IMAGE, nSize := VarSetCapacity( LOADED_IMAGE, 84, 0 ), pMappedAddress, pFileHeader
    , pIMGDIR_EN_EXP, IMAGE_DIRECTORY_ENTRY_EXPORT := 0, RVA, VA, LIST := ""  
    , hModule := DllCall( "LoadLibrary", "Str","ImageHlp.dll", "Ptr" ) 

  If ! DllCall( "ImageHlp\MapAndLoad", "AStr",DLL, "Int",0, "Ptr",&LOADED_IMAGE, "Int",True, "Int",True )
    Return                

  pMappedAddress := NumGet( LOADED_IMAGE, ( A_PtrSize = 4 ) ?  8 : 16 )
  pFileHeader    := NumGet( LOADED_IMAGE, ( A_PtrSize = 4 ) ? 12 : 24 )
 
  pIMGDIR_EN_EXP := DllCall( "ImageHlp\ImageDirectoryEntryToData", "Ptr",pMappedAddress 
                           , "Int",False, "UShort",IMAGE_DIRECTORY_ENTRY_EXPORT, "PtrP",nSize, "Ptr" )

  VA  := DllCall( "ImageHlp\ImageRvaToVa", "Ptr",pFileHeader, "Ptr",pMappedAddress, "UInt"
, RVA := NumGet( pIMGDIR_EN_EXP + 12 ), "Ptr",0, "Ptr" )

  If ( VA ) {
     VarSetCapacity( LIST, nSize, 0 )
     Loop % NumGet( pIMGDIR_EN_EXP + 24, "UInt" ) + 1
        LIST .= StrGet( Va + StrLen( LIST ), "" ) "`n"
             ,  ( Hdr = 0 and A_Index = 1 and ( Va := Va + StrLen( LIST ) ) ? LIST := "" : "" )  
  }
    
  DllCall( "ImageHlp\UnMapAndLoad", "Ptr",&LOADED_IMAGE ),   DllCall( "FreeLibrary", "Ptr",hModule )

Return RTrim( List, "`n" )
}
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
jballi
Posts: 515
Joined: 29 Sep 2013, 17:34

Re: DllListExports() - List of Function exports of a DLL

13 Sep 2014, 21:47

Looks useful. :thumbup: Now if I could only remember to use it when I need it next...
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

Re: DllListExports() - List of Function exports of a DLL

13 Sep 2014, 22:42

Hi jballi :)

I have this third party dll with 135 functions with decorated names like _my_function_d@24 whereas the documentation is for my_function().
So, this is the idea: Create a function that will load all functions names ( tinkered to match documentation ) along with the proc-address into an associative array... and within wrapper functions I can initialize them like Static MyDescriptiveFunction := MyDll( "My_Function" ). That will be too much code, maybe, but at least the main script will be easy to follow.

:)
jballi
Posts: 515
Joined: 29 Sep 2013, 17:34

Re: DllListExports() - List of Function exports of a DLL

13 Sep 2014, 23:40

Definitely out of my purview but it does look like one way to separate the real functions from the documented "front-end" functions. Yes, it does look like a lot of extra code.

I noticed that you joined this forum 36 minutes before I did. I was planning to join an hour earlier but I had to call my Mom. Yeah, that's what happened. :)

Thanks for the great function.
just me
Posts: 5574
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: DllListExports() - List of Function exports of a DLL

14 Sep 2014, 03:57

So, this is the idea: Create a function that will load all functions names ( tinkered to match documentation ) along with the proc-address into an associative array...
Bentschi published a function (without the tinkering part) in the old forum -> /board/topic/90266-funktionen-loadlibrary-freelibrary-schnellere-dllcalls/.
User avatar
joedf
Posts: 6603
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada, Quebec
Contact:

Re: DllListExports() - List of Function exports of a DLL

14 Sep 2014, 05:14

haha
http://aspdm.tk/#loadlibrary
aspdm://aspdm.tk/loadlibrary
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 3.00 GHz, 16GB DDR4 3200 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

Re: DllListExports() - List of Function exports of a DLL

14 Sep 2014, 10:29

Bentschi published a function (without the tinkering part) in the old forum -> /board/topic/90266-funktionen-loadlibrary-freelibrary-schnellere-dllcalls/.
Thanks just me, very useful info.. The code is broken though.
http://aspdm.tk/#loadlibrary
aspdm://aspdm.tk/loadlibrary
Those links never worked for me. Any pointers to working code, please.
just me
Posts: 5574
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: DllListExports() - List of Function exports of a DLL

14 Sep 2014, 15:17

Well, that's my version, created because I tried to understand what Bentsch's script is actually doing, and working AFAIK.

Code: Select all

#NoEnv
SetBatchLines, -1
DllFile := "Shell32.dll"
Global DLL := LoadLibrary(DllFile)
Gui, Margin, 20, 20
Gui, Add, ListView, w600 r20 Grid, #|Function|Address
LV_ModifyCol(1, "Integer 50")
LV_ModifyCol(2, "300")
LV_ModifyCol(3, "200")
For Function, Address In DLL
   LV_Add("", A_Index, Function, Address)
Gui, Show, , % DllFile
MsgBox
Return
GuiClose:
DLL := ""
ExitApp
; ======================================================================================================================
LoadLibrary(DllFile) { ; originally released by Bentschi
   ; All adresses of interest stored in the DLL are relative (i.e. offsets)!!!
   Static Off_64 := (A_PtrSize - 4) * 4   ; Additional offset for 64-bit, zero for 32-bit
   Static Off_PEHeaderPtr := 0x3C         ; Offset of the pointer to the PE header
   Static SizeOfSignature := 4            ; Size of the PE signature
   Static SizeOfCOFF      := 20           ; Size of the COFF header
   Static Loaded := {}                    ; Previously loaded DLLs
   If !(HDLL := DllCall("Kernel32.dll\LoadLibrary", "Str", DllFile, "UPtr"))
      Return False
   If (Loaded[HDLL])
      Return Loaded[HDLL]
   DllObj := {Base: {__Delete: Func("FreeLibrary"), "&": HDLL}}                  ; & : HMODULE
   If ((Off_Signature := NumGet(HDLL + 0, Off_PEHeaderPtr, "UInt")) < 1)         ; signature offset
      Return DllObj
   If !(StrGet(HDLL + Off_Signature, 4, "CP0") == "PE")                          ; no PE format image file
      Return DllObj
   Off_COFF := Off_Signature + SizeOfSignature                                   ; COFF offset
   If (NumGet(HDLL + Off_COFF, 16, "Short") = 0)                                 ; SizeOfOptionalHeader
      Return DllObj
   Off_OptHeader := Off_COFF + SizeOfCOFF                                        ; Optional header offset
   If (NumGet(HDLL + Off_OptHeader, 92 + Off_64, "Int") < 1)                     ; NumberOfRvaAndSizes
   || ((Off_Export := NumGet(HDLL + Off_OptHeader, 096 + Off_64, "UInt")) < 1)   ; export table offset
   || ((ExportSize := NumGet(HDLL + Off_OptHeader, 100 + Off_64, "UInt")) < 1)   ; export table size
      Return DllObj
   ; Now we are sure to have found an export table
   NumOfEntries := NumGet(HDLL + Off_Export, 24, "Int")                          ; number of functions
   Off_NamePtrs := NumGet(HDLL + Off_Export, 32, "UInt")                         ; name-pointer table offset
   Loop, % NumOfEntries {
      If (NamePtr := NumGet(HDLL + Off_NamePtrs, (A_Index - 1) * 4, "UInt")) {
         Name := StrGet(HDLL + NamePtr, "CP0")
         Addr := DllCall("Kernel32.dll\GetProcAddress", "Ptr", HDLL, "AStr", Name, "UPtr")
         DllObj[Name] := Addr
      }
   }
   Return (Loaded[HDLL] := DllObj)
}
; ======================================================================================================================
FreeLibrary(This) {
   DllCall("Kernel32.dll\FreeLibrary", "Ptr", This.Base["&"])
}
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

Re: DllListExports() - List of Function exports of a DLL

14 Sep 2014, 16:33

Thank you just me... I tried it and works great!.. but I have already written my own version.
Locating IMAGE_EXPORT_DIRECTORY is very simple as I have demonstrated in DllListExports()

something like this:

Code: Select all

   If !(HDLL := DllCall("Kernel32.dll\LoadLibrary", "Str", DllFile, "UPtr"))
        Return False
   If (Loaded[HDLL])
      Return Loaded[HDLL]
   DllObj := {Base: {__Delete: Func("FreeLibrary"), "&": HDLL}}                  ; & : HMODULE      
   Off_Export := DllCall( "ImageHlp\ImageDirectoryEntryToData", "Ptr",HDLL, "Int",True
                        , "UShort",IMAGE_DIRECTORY_ENTRY_EXPORT := 0, "PtrP",nSize := 0, "UPtr" )
   If not ( Off_Export and nSize )
   ...
 ; Now we surely have an export table
   NumOfEntries := NumGet( Off_Export+24, "Int")                          ; number of functions
   Off_NamePtrs := NumGet( Off_Export+32, "UInt")                         ; name-pointer table offset
However, I wouldn't prefer calling GetProcAddress() umpteen times while Proc addresses are already available.

Code: Select all

  DllObj := {Base: {__Delete: Func("FreeLibrary"), "&": HDLL}}                  ; & : HMODULE
Thanks. I think I will understand it. :?

Here is my code so far , adapted from DllListExports():

Code: Select all

#Warn
#SingleInstance, Force

pBASE := DllCall( "LoadLibrary", "Str","shell32.dll", "UPtr" )

; Locate Structure IMAGE_EXPORT_DIRECTORY 
pIMAGE_EXPORT_DIRECTORY := DllCall( "ImageHlp\ImageDirectoryEntryToData", "Ptr",pBASE, "Int",True
                         , "UShort",IMAGE_DIRECTORY_ENTRY_EXPORT := 0, "PtrP",nSize := 0, "UPtr" )

If not ( pIMAGE_EXPORT_DIRECTORY and nSize ) 
{
   MsgBox, No Export Directory found!
   ExitApp
}   
    
/*
Structure IMAGE_EXPORT_DIRECTORY
----------------------------------------------------------------------------------------------------
Off Size Type   Description            Comment
----------------------------------------------------------------------------------------------------
  0    4 UInt   Characteristics
  4    4 UInt   TimeDateStamp
  8    2 UShort MajorVersion
 10    2 UShort MinorVersion
 12    4 UInt   Name
 16    4 UInt   Base
 20    4 UInt   NumberOfFunctions
 24    4 UInt   NumberOfNames
 28    4 UInt   AddressOfFunctions     RVA from base of image 
 32    4 UInt   AddressOfNames         RVA from base of image
 36    4 UInt   AddressOfNameOrdinals  RVA from base of image   
----------------------------------------------------------------------------------------------------
 40 bytes in total.  Note: AddressOfNameOrdinals should be pronounced as "AddressOfName's Ordinals".
----------------------------------------------------------------------------------------------------
*/

pAddressOfFunctions    := pBASE + NumGet( pIMAGE_EXPORT_DIRECTORY + 28, "UInt" )  ; Array of UINTs
pAddressOfNames        := pBASE + NumGet( pIMAGE_EXPORT_DIRECTORY + 32, "UInt" )  ; Array of UINTs
pAddressOfNameOrdinals := pBASE + NumGet( pIMAGE_EXPORT_DIRECTORY + 36, "UInt" )  ; Array of USHORTs

; Note: AddressOfNameOrdinals does not contain any Address (RVA). It is list of zero-based ordinals.

nNumberOfNames := NumGet( pIMAGE_EXPORT_DIRECTORY + 24, "UInt" )

List := ""
Loop % nNumberOfNames
{
   zbIndex   := A_Index - 1 
   RVA1      := NumGet( pAddressOfNames + ( zbIndex * 4 ), "UInt" )
   sFunction := StrGet( pBASE + RVA1, "" ) 
   
   Ordinal   := NumGet( pAddressOfNameOrdinals + ( zbIndex * 2 ), "UShort" )  
   RVA2      := NumGet( pAddressOfFunctions    + ( Ordinal * 4 ), "UInt"   )
   pProc     := pBASE + RVA2   
    
   List .=  sFunction A_Tab pProc "`n" 
}
 
MsgBox % Clipboard := List
User avatar
joedf
Posts: 6603
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada, Quebec
Contact:

Re: DllListExports() - List of Function exports of a DLL

15 Sep 2014, 00:18

@SKAN looks like server is down... Some bozo DDoS my free hosting service :(
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 3.00 GHz, 16GB DDR4 3200 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
just me
Posts: 5574
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: DllListExports() - List of Function exports of a DLL

15 Sep 2014, 07:40

However, I wouldn't prefer calling GetProcAddress() umpteen times while Proc addresses are already available.
That's exactly the question I asked Bentschi. The answer was: Export Forwarding.
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

Re: DllListExports() - List of Function exports of a DLL

15 Sep 2014, 11:19

Thanks for the link. :)
Bookmarked!.
User avatar
SKAN
Posts: 320
Joined: 29 Sep 2013, 16:58

Re: DllListExports() - List of Function exports of a DLL

15 Sep 2014, 11:20

@SKAN looks like server is down... Some bozo DDoS my free hosting service :(
Free hosting service? I didn't know.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Google [Bot] and 41 guests