2

我正在尝试在 user32 中设置断点!RegisterClipboardFormat 显然,此函数已导出(链接 /dump /exports - 它就在那里)。在从 Microsoft 符号服务器下载 PDB 文件之前,我能够找到这个函数:

0:001> lm m user32
start    end
76eb0000 76fcf000   USER32     (export symbols)       c:\Windows\system32\USER32.dll

0:001> x user32!RegisterClipboardFormat*
76ec4eae USER32!RegisterClipboardFormatA (<no parameter info>)
76ec6ffa USER32!RegisterClipboardFormatW (<no parameter info>)

没问题。我能够“购买”任何这些功能。但是当我从 Microsoft PDB 服务器下载 PDB 符号时:

0:001> 
start    end        module name
76d50000 76e6f000   USER32     (pdb symbols)          c:\symbols\user32.pdb\561A146545614951BDB6282F2E3522F72\user32.pdb

0:000> x user32!RegisterClipboardFormat

WinDBG 找不到符号。但是,它可以找到 RegisterWindowMesssage:

0:000> x user32!RegisterWindowMessage*
76d64eae          USER32!RegisterWindowMessageA = <no type information>
76d66ffa          USER32!RegisterWindowMessageW = <no type information>

请注意,这些函数具有相同的地址(这是在 Windows 8 上。不确定以前的版本)。这可能是通过优化器或在 DEF 文件中实现的(EXPORT 部分中的 func1=func2)。'link /dump /exports' 显示 RegisterWindowMessage 和 RegisterClipboardFormat 具有相同的 RVA。

问题是我在这上面花了太多时间。所以我的问题是:

  1. 是否有一种简单的方法,从 WinDBG 中找出丢失的别名导出符号。
  2. 假设我只想打破 RegisterClipboardFormatW。如果我没记错的话,应该有一个 JMP 指令(在调用模块导入表中)。我如何找到那个符号?有没有办法在所有调用模块中找到这个条目?
4

1 回答 1

3

由于RegisterWindowMessageRegisterClipboardFormat具有相同的 RVA,因此它们共享相同的实现。显然,Windows 对这两者没有任何区别,剪贴板格式和窗口消息共享相同的标识符域。

对于您的第一个问题——如何找出哪个实现函数对应于导出的函数。(假设您已修复符号)首先找出导出的 RVA:

C:\>link /dump /exports C:\Windows\Syswow64\user32.dll |findstr RegisterClipboardFormat
   2104  24F 00020AFA RegisterClipboardFormatA
   2105  250 00019EBD RegisterClipboardFormatW

然后在 WinDbg 中找到加载 DLL 的起始地址。命令lmlml列出所有模块,你只需要找到你所追求的模块:

0:001> lml
start    end        module name
75460000 75560000   USER32   

使用 RVA 作为起始地址的偏移量,获取与其对应的符号:

0:002> ln 75460000+00020AFA
(75480afa)   USER32!RegisterWindowMessageA   |  (75480b4a)   USER32!MsgWaitForMultipleObjects
Exact matches:
0:002> ln 75460000+00019EBD
(75479ebd)   USER32!RegisterWindowMessageW   |  (75479eea)   USER32!NtUserGetProcessWindowStation
Exact matches:

所以在这里我们实际上发现RegisterClipboardFormat实际上调用了RegisterWindowMessage。

你的第二个问题——如何只在 RegisterClipboardFormat 上放置断点,而不是在 RegisterWindowMessage 上。通常这是不可能的,因为它们共享相同的实现。例如,您的应用程序可能会调用GetProcAddress("RegisterClipboardFormat"),您将很难确定它是否调用了一个函数或另一个函数。但是,如果您知道调用是通过导入的函数进行的,那么您可以这样做。所有导入的函数都在应用程序的导入地址表中声明。如果在导入地址表的条目上放置访问断点,则可以在调用之前中断。这可能是特定于编译器的,但我知道 Visual C++ 将符号名称分配给导入地址表中的条目。在这种情况下,放置断点很容易:

ba r4 MyModule!_imp_RegisterClipboardFormatA
于 2012-05-29T04:21:31.647 回答