【问题标题】:How to find the proc name for `GetProcAddress` function using WinDbg如何使用 WinDbg 查找“GetProcAddress”函数的过程名称
【发布时间】:2018-04-04 09:35:08
【问题描述】:

我想使用GetProcAddress 来获取加载的DLL 中的一些函数地址。我在 PSAPI 库上运行了一些尝试,我可以看到预期的 proc 名称与我在 WinDbg x 语句中找到的符号名称不同。例如,我用x psapi!*EnumProcessModules* 查找“EnumProcessModules”(这是GetProcAddress 方法所期望的名称),我找到了

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>

当我向GetProcAddress 方法提供上面找到的任何符号(带有或不带有“PSAPI!”作为前缀)作为第二个参数 (procName) 时 - 它返回 NULL,但是当我使用方法名称时“ EnumProcessModules” - 返回 0xfe111030,即“PSAPI!EnumProcessModulesStub”的地址。

我怎么能提前知道预期的procName?如果我在一个 DLL 中有 2 个具有相同方法名称的不同类或命名空间怎么办?调用GetProcAddress时如何区分这两个方法名?

【问题讨论】:

    标签: c++ windbg getprocaddress


    【解决方案1】:

    PSAPI! 只是一个前缀,它是WinDbg 打印的DLL 名称。这是用来消除名称歧义的。一个明确的例子说明为什么这很有用:您的流程中会有很多DllMain

    GetProcAddress 的预期名称是函数的记录名称,如 MSDN 中所述。请记住,当 MSDN 声明两个版本都可用时,您需要添加 AW 后缀。例如。你不能用"GetDeviceDriverFileName" 调用GetProcAddress,你需要"GetDeviceDriverFileNameA"L"GetDeviceDriverFileNameW"

    对于非系统 DLL,您需要导出地址表中的函数名。

    背景:您在 WinDbg 中看到的是来自 .PDB 的名称,正如您所发现的,它可能与导出的名称不同。没有什么可以加强两者之间的关系。例如,在技术上可以使用 PDB 名称 FooBar,并在导出地址表中交换它们。更实际的是,Microsoft 可能随时在内部添加 _wrapper_EnumProcessModules,但记录和导出的名称将保留为 EnumProcessModules

    【讨论】:

      【解决方案2】:

      此 API 的核心功能在 kernel32.dll 中实现 并命名为 K32EnumProcessModules

      在 paspi.h 标头中,此 API 是基于 PSAPI_VERSION 的 ifdefed

      #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 
      

      如果你在 psapi.dll 中 GetProcAddress,你会得到一个存根,它会被转移到 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
      

      你可以在dll上使用dumpbin /exports 看看有没有关联 或者如果有名称更改(请参阅 Stub@16 )

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

      您还可以使用下面的方法从 psapi.dll 的导出表中找到相同的信息

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-15
        相关资源
        最近更新 更多