• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
黄金狮子
博客园    首页    新随笔    联系   管理    订阅  订阅

如何通过offset地址确定引起崩溃的代码行

如何通过offset地址确定引起崩溃的代码行 (转)
2009-04-21 09:19

简介
    当release版本的程序交付给用户使用后,如果应用程序崩溃了,怎么样通过windows提示的offset地址来定位源程序中对应的出错代码呢?这篇文章就来讨论这个问题。

建立调试环境
1.(VC 6)依次选择FileàNewàProjects,在列表中选择“MFC AppWizard(EXE)”在“Project Name”中输入“Crash_Test”作为项目名,“OK”进入下一步。在“MFC Appwizard – Step 1”对话框中选择“Dialog Based”单选框。“Finish”完成工程的建立,F7编译无误。
2.(VC 6)双击确定按钮,提示加入(重写)“OnOK”函数,OK,进入“CCrash_TestDlg::OnOK()”函数。
3.我们将在OnOK函数中构造一些能够引起程序崩溃的错误代码:
void CCrash_TestDlg::OnOK() 
{ 
AfxGetApp()->GetMainWnd()->SetWindowText(_T("Crash")); 
int* pTest = NULL; 
*pTest = 0; // 为空指针赋值,程序将崩溃
CDialog::OnOK(); 
} 
加入“AfxGetApp()->GetMainWnd()->SetWindowText(_T("Crash"));”的目的是使崩溃地址和“OnOK”的地址有一定偏移,使演示更具一般性。
4.(VC 6)首先设置Release编译(在BuildàSet as configuration中选择Win32 Release)。依次选择ProjectàSettings,选择“C/C++”tab页,Category中选择“Listing Files”,然后在“Listing file type”中选择“Assembly, Machine Code, and Source”,OK。这个选项将为每个源文件(*.cpp)生成机器码、汇编码和源代码的对应表,可以在“Release”目录下找到和查看这些文件。
5.(VC 6)依次选择ProjectàSettings,选择“Link”tab页,Category中选择“Debug”,
钩选“Generate map file”,OK。这个选项将生成编译后的函数地址和函数名的对应表。

定位错误代码

1.现在运行“Release”目录下的测试程序,当点击“确定”按钮时,程序将崩溃。
Windows XP 会出现“Crash_Test.exe 遇到问题需要关闭。我们对此引起的不便表示抱歉。”…………
云云的对话框,在对话框的下方,单击“请单击此处”的超连接,在“错误签名”中,我们会得到如下信息:
AppName: crash_test.exeAppVer: 1.0.0.1ModName: crash_test.exe 
ModVer: 1.0.0.1Offset: 000014a0 
其中的Offset值就是崩溃的地址啦,现在我们根据这个地址来定位源程序中出错的代码行。
2.用记事本打开“Release”目录下的,“Crash_Test.map”文件,在文件中会看到类似下面的内容:
0001:00000470?OnQueryDragIcon@CCrash_TestDlg@@IAEPAUHICON__@@XZ 00401470 fCrash_TestDlg.obj 
0001:00000480?OnOK@CCrash_TestDlg@@MAEXXZ 00401480 fCrash_TestDlg.obj 
0001:000004c0?BeginModalState@CWnd@@UAEXXZ 004014c0 f i Crash_TestDlg.obj 
0001:000004d0?EndModalState@CWnd@@UAEXXZ 004014d0 f i Crash_TestDlg.obj 
画线的部分就是各个函数编译运行后在内存中的相对地址 (高位部分是基地址,就不参与计算啦,基地址可能因机器不同而异,但相对地址都是一样的。) ,因为“Offset”指示的崩溃地址为“14a0”,
1480(OnOK地址) < 14a0(出错地址) < 14c0(BeginModalState地址),很显然,14a0的地址是在OnOK函数的地址范围内的,也就是说OnOK就是引起崩溃的函数。接下来再来确定出错的具体代码行。
3.因为OnOK是在“Crash_TestDlg.cpp”中实现的,因此,我们打开对应的“Crash_TestDlg.cod”文件,其中有如下代码:
?OnOK@CCrash_TestDlg@@MAEXXZ PROC NEAR; CCrash_TestDlg::OnOK, COMDAT
; 173: {
0000056pushesi 
000018b f1movesi, ecx 
… …
; 175: int* pTest = NULL; 
; 176: *pTest = 0; 
; 177: CDialog::OnOK();
0001e8b cemovecx, esi 
00020c7 05 00 00 00 
00 00 00 00 00movDWORD PTR ds:0, 0 
0002ae8 00 00 00 00call?OnOK@CDialog@@MAEXXZ; CDialog::OnOK 
0002f5epopesi
; 178: } 
… …
    很明显,这些就是OnOK函数的汇编表示和机器码表示,画线的地址就是函数中各个语句的相对(相对于函数首地址)地址。
    在步骤1中,我们已经得到,Offset为14a0,OnOK的函数首地址为0480,现在,我们用14a0-1480就得到20(注意,这里都是16进制运算),可见,出错的代码行为:
00020c7 05 00 00 00 00 00 00 00 00movDWORD PTR ds:0, 0
对应上面注释的:
; 176: *pTest = 0;

posted @ 2010-09-20 15:43  黄金狮子  阅读(528)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3