3

我从带有 Dr. Watson 信息的最终用户那里得到崩溃报告,我想用它们来找出崩溃发生的位置(即代码的哪一行)。

我不能只使用崩溃报告中的 EIP,因为我们发布的 exe 是经过数字签名的,这会改变所有的偏移量。然而,崩溃信息也有“CS:EIP 的字节数”,这是从发生崩溃的 EIP 开始的前 16 个字节。它看起来像这样:

Bytes at CS:EIP:
85 c4 14 c3 8b ff 55 8b ec 6a 0a 6a 00 ff 75 08

这 16 个字节在 exe 中只出现一次。我可以仅使用 HEX 查看器在 EXE 中找到它们的偏移量,但是为了在调试期间跳转到那里并查看源代码中的哪一行,我需要在加载 EXE 后知道它们在内存中的偏移量。

加载后扫描程序代码段的最佳方法是什么?我可以添加代码来查找 EXE 的基本偏移量在哪里,然后循环通过它并使用 memcmp 来查找字节模式出现的位置。

另外,我怎样才能找到 EXE 的基本偏移量在哪里?

4

5 回答 5

4

对于同样的问题,我使用了一种非常简单的方法。

首先,我转储我的可执行文件以查找代码段的物理(文件中)偏移量。

然后我从二进制中这些“魔术”字节所在的内存地址中减去它。

然后我在调试器下运行程序,只需将此偏移量添加到代码段的虚拟地址即可。

       .text name
  10EE8E virtual size
    1000 virtual address (00401000 to 0050FE8D)
  10F000 size of raw data

 --> 400 file pointer to raw data (00000400 to 0010F3FF) <--

       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         Execute Read
于 2012-03-02T10:50:19.723 回答
2

如果您使用ollydbg 之类的东西,您可以在其运行时扫描它们的进程内存,并在您查看找到的点时让它向您报告文件:行和源代码(只要 pdb 正确链接)。如果您静态打开文件,它还允许您查看虚拟化地址。

于 2012-03-02T10:02:46.797 回答
1

或者,如果您只是使用基本工具,则可以使用Visual Studio 或平台 SDK 中的dumpbin(aka link /dump /all)。它可以为您提供十六进制转储和/或应用了所有重定位的反汇编,并且还将选择 PDB 以将符号名称添加到您的列表中。这一切都表明 DLL 可能在加载时由于冲突而被重新定位到不同的地址,但您可以使用它dumpbin /headers来找出 DLL 的默认基本偏移量。

不过,Watson 博士不是给你 EIP 值,而不仅仅是那里的字节吗?我已经有一段时间没有使用它了。一个更好的解决方案是注册WinQual - 然后最终用户可以将他们的故障转储上传到 Microsoft,您可以从那里收集它们,然后您可以获得实际的小型转储和堆转储来查看。

于 2012-03-02T10:12:08.643 回答
1

您所要做的就是将您的 PE 文件(.dll 和 .exe)和 PDB 文件放在符号服务器中,然后将调试器(windbg 或 VS)指向您的符号服务器和 Microsoft 的符号服务器。PE 文件和 PDB 文件将被自动加载,所有级别的调用堆栈都会显示反汇编,并会找到源文件。

如果你的 PE 文件是签名的,那么你应该把签名的 PE 文件放在你的符号服务器中,尽管如果你把未签名的文件放在你的符号服务器中,那么它们可能会很好地加载(代码字节不受影响),可能会有一些校验和警告。

对于奖励分数,您应该在将 PDB 添加到符号服务器之前运行源索引。这样调试器就可以从版本控制中检索源文件的正确版本——很神奇。这真的没那么难。我在我的爱好共享软件项目上完成了所有这些步骤。

来自我博客的参考: https ://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/ https://randomascii.wordpress.com/2011/11/11/source-indexing-is -未充分利用的真棒/

重申一下:这应该可行。在许多不同的公司工作时,我查看了来自客户机器的数百个故障转储,并且由于符号服务器和源服务器,我可以零努力地获得机器代码、函数名称、源代码、局部变量等。

于 2014-11-24T18:47:32.983 回答
0

我在这里发布了一个我自己发现的可能的解决方案,虽然它不是很优雅。我不确定使用 GetModuleHandle 作为基本偏移量是否正确,但它似乎正在处理我迄今为止尝试过的 2-3 个错误报告。

unsigned char buf[] = { 0x85, 0xc4, 0x14, 0xc3, 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x6a, 0x0a, 0x6a, 0x00, 0xff, 0x75, 0x08  };
HMODULE hModule = GetModuleHandle(NULL);
char* ii;
for (ii = (char*) hModule; memcmp(ii, buf, sizeof(buf)); ii++);

char buf2[1000];
sprintf(buf2, "%p", ii);
MessageBox(0,buf2,0,0);
于 2012-03-02T11:14:46.383 回答