2012-03-02 74 views
3

我收到Dr.Watson信息的最终用户的崩溃报告,我想用它们来找出崩溃发生的位置(即在哪一行码)。使用'CS:EIP处的字节'来找出崩溃发生的位置

我不能仅仅从崩溃报告中使用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的基础偏移量在哪里?

+0

EIP通过签名更改?我很确定它没有。 (Authenticode签名,我假设 - “Exe”和“EIP”建议Win/86) – MSalters 2012-03-02 13:40:38

+0

你是对的。我刚刚检查过它。前者基本保持不变,一开始只有一点变化。无论如何,我只是不能很好地重新创建exe,只能使用EIP。也许我没有完全相同的来源,我不知道。我认为使用CS:EIP中的字节要好得多,因为即使在源代码发生实质性更改时它仍然可以工作,只要崩溃周围的代码保持不变即可。 – sashoalm 2012-03-02 15:00:16

回答

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 
2

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

1

或者,如果您只是使用基本工具,则可以使用Visual Studio或平台SDK中的dumpbin(也称作link /dump /all)。它可以给你一个十六进制转储和/或所有重定位应用的反汇编,并且还会选择PDB向你的列表添加符号名称。也就是说,由于冲突,DLL可能已在加载时重定位到不同的地址,但您使用dumpbin /headers来找出DLL的默认基准偏移量。

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

+0

感谢您的回答。我也获得了EIP,但发送给最终用户的版本是数字签名的,签名过程会更改偏移量,所以我无法使用它。 – sashoalm 2012-03-02 10:25:56

+0

令人惊讶。如果签名过程更改了偏移量,那么这意味着您需要在测试之前对其进行签名,否则您不会测试您发布的完全相同的代码,这对我来说听起来是错误的。我想这意味着你没有可用的PDB的发布二进制文件:-( – Rup 2012-03-02 10:43:21

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); 
1

所有你需要做的就是把你的PE文件(.dll和.exe文件)和PDB文件的符号服务器,然后在你的符号服务器以及微软的符号服务器指向调试器(WinDbg的或VS)。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-underused-awesomeness/

要重申:这应该只是工作。在许多不同的公司工作时,我查看了来自客户机器的数百次崩溃转储,并且由于符号服务器和源服务器,我毫不费力地获得机器代码,函数名称,源代码,局部变量等。

+0

我的答案假设你有一个崩溃转储(小型转储)文件。如果你不这样做,那么第一步应该是得到一个。 – 2014-11-24 18:49:00