看到这个题目,我以为我没有希望了! 我连MAP文件是什么都不知道`~~~~~~
Google了好久,让我找到了两篇文章,先分享给大家!
第一个是老罗的《仅通过崩溃地址找出源代码的出错行》
原文出处:http://www.luocong.com/articles/show_article.asp?Article_ID=29
第二个是在VC知识库找的名叫《对“仅通过崩溃地址找出源代码的出错行”一文的补充与改进》
地址我忘记了!
我不指望我能在本次比赛里得到什么奖项(就我这水平,想得估计也那个什么……),所以只是抱着能穴道东西的心态来参加的!到目前为止,我虽然没有得到什么分数,但是我学到了很多的东西!
第二题因为学校的事耽搁了,只分析了一半没能参加,这次第三题,不管对错,提交上来,对自己也算有个交代!
盯着MAP文件瞅了半天,终于让我找到了下面这句!
0001:0001fd20 ?OnBnClickedBtnCrash@CTestFloatDlg@@QAEXXZ 00420d20 f TestFloatDlg.obj
哈哈,是不是我运气太好了?我找到了OnBnClickedBtnCrash()这个函数,也就是我们看到的程序里面那个按钮的单击事件的响应程序啊~~~~
别的不说,先看一下代码先:
.text:00420D20 push ebp
.text:00420D21 mov ebp, esp
.text:00420D23 sub esp, 94h
.text:00420D29 mov eax, dword_429DA8
.text:00420D2E xor eax, ebp
.text:00420D30 mov [ebp-0Ch], eax
.text:00420D33 mov [ebp-94h], ecx
.text:00420D39 mov ax, ds:word_425A30
.text:00420D3F mov [ebp-90h], ax
.text:00420D46 push 7Eh
.text:00420D48 push 0
.text:00420D4A lea ecx, [ebp-8Eh]
.text:00420D50 push ecx
.text:00420D51 call _memset ;清空缓冲区[ebp-90h]
.text:00420D56 add esp, 0Ch
.text:00420D59 fld ds:dbl_425DC0 ;把ds:dbl_425DC0中的内容加载到ST0 valid 3.1415900000000000000
.text:00420D5F fstp qword ptr [ebp-8] ;再保存到qword ptr [ebp-8] 里面去
.text:00420D62 fld qword ptr [ebp-8] ;再加载到ST0里去
.text:00420D65 fadd st, st ;将它们相加 ST0 valid 6.2831800000000000000
.text:00420D67 fstp qword ptr [ebp-8] ;再保存到qword ptr [ebp-8] 里面去
.text:00420D6A sub esp, 8
.text:00420D6D fld qword ptr [ebp-8]
.text:00420D70 fstp qword ptr [esp] ;再保存到qword ptr [esp] 里面去
.text:00420D73 push offset aPi2F ; "PI * 2 = %f"
.text:00420D78 push 40h
.text:00420D7A lea edx, [ebp-90h]
.text:00420D80 push edx
.text:00420D81 call __snwprintf ;把aPi2F中的内容赋值到[ebp-90h]中去
.text:00420D86 add esp, 14h
.text:00420D89 push 40h
.text:00420D8B push offset aTestfloag ; "TestFloag"
.text:00420D90 lea eax, [ebp-90h]
.text:00420D96 push eax
.text:00420D97 mov ecx, [ebp-94h]
.text:00420D9D call sub_405C75 ;查MAP文件得知,这个函数是:MessageBoxW@CWnd@@QAEHPB_W0I@Z
.text:00420DA2 mov ecx, [ebp-0Ch]
.text:00420DA5 xor ecx, ebp
.text:00420DA7 call sub_40ECBD
.text:00420DAC mov esp, ebp
.text:00420DAE pop ebp
.text:00420DAF retn
好了,我把注释也给加上了,到这里这个程序的功能我们就都清楚了:显示PI * 2 = 6.2831800000000000000!
虽然它的具体实现是有问题的,我不知道作者把结果放大ESP里是怎么个用法,但是我认为常规方法应该把算出来的浮点型的结果进行类型转换,弄成字符串型的,然后再进行赋值等操作等等!
但是不是我们要考虑的重点!
这次题目要求我们分析出异常的原因,我们分析一下它吧:
这个程序做了浮点运算,我们用OD跟一下,在走:
.text:00420D59 fld ds:dbl_425DC0 ;把ds:dbl_425DC0中的内容加载到ST0 valid 3.1415900000000000000
.text:00420D5F fstp qword ptr [ebp-8] ;再保存到qword ptr [ebp-8] 里面去
.text:00420D62 fld qword ptr [ebp-8] ;再加载到ST0里去
.text:00420D65 fadd st, st ;将它们相加 ST0 valid 6.2831800000000000000
.text:00420D67 fstp qword ptr [ebp-8] ;再保存到qword ptr [ebp-8] 里面去
.text:00420D6A sub esp, 8
.text:00420D6D fld qword ptr [ebp-8]
.text:00420D70 fstp qword ptr [esp] ;再保存到qword ptr [esp] 里面去
这些代码的时候都没有出过问题,而且,F8单步跟的结果都是正确的!
问题出在
__snwprintf函数这里!而这个函数是字符串操作函数,不存在浮点类型运算!!!
那我们就可以得出结论了:问题就出在
%f上了!
用
%f会被误认为是浮点型所以在执行
__snwprintf() 函数的时候要出问题,提示不支持家在浮点数库!
我给出的解决方法是:把小写的
%f 改写成大写的
%F 即远地址调用字符串!
要去吃饭了,我就不写测试程序了(关键是不知道怎么写~)!我把给定的程序修改一下,再贴个图,发出来吧~~~~
希望我的分析是正确的!如果不对还望各位大大批评指正!
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!