benams
benams

Reputation: 4656

How to find the proc name for `GetProcAddress` function using WinDbg

I want to use GetProcAddress to get some functions addresses inside a loaded DLL. I run some attempts on PSAPI library and I can see the the expected proc name is not identical to the symbol names I find with WinDbg x statements. For example, I look for "EnumProcessModules"(which is the name expected by GetProcAddress method) with x psapi!*EnumProcessModules* and I find

00007ff9`fe112210 PSAPI!_imp_K32EnumProcessModulesEx = <no type information>
00007ff9`fe111360 PSAPI!EnumProcessModulesExStub (<no parameter info>)
00007ff9`fe111030 PSAPI!EnumProcessModulesStub (<no parameter info>)
00007ff9`fe1121a8 PSAPI!_imp_K32EnumProcessModules = <no type information>

When I provide any of the found symbols above (with or without "PSAPI!" as a prefix) to the GetProcAddress method as the second parameter (procName) - it returns NULL, but when I use the method name "EnumProcessModules" - it returns 0xfe111030, which is the address of "PSAPI!EnumProcessModulesStub".

How could I know the expected procName in advance? What if I have 2 different classes or namespaces with the same method name in one DLL? How can I distinguish between the two method names when I call GetProcAddress?

Upvotes: 1

Views: 1332

Answers (2)

blabb
blabb

Reputation: 9007

The Core Functionality for this API is implemented in kernel32.dll and Named K32EnumProcessModules

in paspi.h header this API is ifdeffed based on PSAPI_VERSION

#ifndef PSAPI_VERSION
#if (NTDDI_VERSION >= NTDDI_WIN7)
#define PSAPI_VERSION 2
#else
#define PSAPI_VERSION 1
#endif
#endif

#if (PSAPI_VERSION > 1)
#define EnumProcessModules          K32EnumProcessModules 

if you GetProcAddress in psapi.dll you get a stub which gets transferred to kernel32.dll

0:001> u PSAPI!EnumProcessModulesStub l 5
PSAPI!EnumProcessModulesStub:
762d1408 8bff            mov     edi,edi
762d140a 55              push    ebp
762d140b 8bec            mov     ebp,esp
762d140d 5d              pop     ebp
762d140e eb05            jmp     PSAPI!K32EnumProcessModules (762d1415)

0:001> u 762d1415 l1
PSAPI!K32EnumProcessModules:
762d1415 ff2504102d76    jmp     dword ptr [PSAPI!_imp__K32EnumProcessModules (762d1004)]

0:001> u poi(762d1004) l1
kernel32!K32EnumProcessModules:
7668cc52 8bff            mov     edi,edi

you can use dumpbin /exports on the dll to see if there is any correlation or if there is a name change (see the Stub@16 )

:\>dumpbin /exports c:\windows\System32\psapi.dll | grep -w EnumProcessModules
          5    4 00001408 EnumProcessModules = _EnumProcessModulesStub@16

you could also find the same info from the export table of psapi.dll using some thing like below

0:001> .shell -ci "!dh psapi" grep Export
    1088 [     359] address [size] of Export Directory
.shell: Process exited
0:001> dt ole32!_IMAGE_EXPORT_DIRECTORY  (psapi + 1088)
   +0x000 Characteristics  : 0
   +0x004 TimeDateStamp    : 0x4a5bc026
   +0x008 MajorVersion     : 0
   +0x00a MinorVersion     : 0
   +0x00c Name             : 0x11be
   +0x010 Base             : 1
   +0x014 NumberOfFunctions : 0x1b
   +0x018 NumberOfNames    : 0x1b
   +0x01c AddressOfFunctions : 0x10b0
   +0x020 AddressOfNames   : 0x111c
   +0x024 AddressOfNameOrdinals : 0x1188
0:001> r? $t0 = (int *) @@(psapi + 10b0)
0:001> r? $t1 = (int *) @@(psapi + 111c)
0:001> r? $t2 = (short *) @@(psapi + 1188)
0:001> .printf "%x %ma %y\n" , @@(@$t2[4]) , (@@(@$t1[4]) + psapi) , (@@(@$t0[4]) + psapi)
4 EnumProcessModules PSAPI!EnumProcessModulesStub (762d1408)

Upvotes: 0

MSalters
MSalters

Reputation: 180205

PSAPI! is just a prefix, it's the DLL name printed by WinDbg. That's used to disambiguate names. A clear example why this is useful: you will have many DllMain's in your process.

The expected name for GetProcAddress is the documented name of the function, as stated on MSDN. Keep in mind that you will need to add either the A or W suffix when MSDN states both versions are available. E.g. you can't call GetProcAddress with "GetDeviceDriverFileName", you need either "GetDeviceDriverFileNameA" or L"GetDeviceDriverFileNameW".

For non-system DLL's, you need the function name from the Export Address Table.

Background: What you see in WinDbg is the name from the .PDB, which as you have discovered can differ from the exported name. There is nothing which enforces a relation between the two. For instance, it's technically possible to have PDB names Foo and Bar, and have them swapped in the Export Address Table. More realistically, Microsoft may internally add an _wrapper_EnumProcessModules at any time, but the documented and exported name will stay EnumProcessModules.

Upvotes: 2

Related Questions