首页
社区
课程
招聘
[原创]第一阶段第三题答案_by_windsun
发表于: 2008-10-9 14:33 4085

[原创]第一阶段第三题答案_by_windsun

2008-10-9 14:33
4085
分析过程

一、错误原因分析
程序出错提示为“C Run-Time Error R6002. floating-point support not loaded”,根据MSDN的说法,以下是导致该错误的原因:
The necessary floating-point library was not linked.
To fix by checking the following possible causes
1.        The program was compiled or linked with an option, such as /FPi87, that requires a coprocessor, but the program was run on a machine that did not have a coprocessor installed.
2.        A format string for a printf_s or scanf_s function contained a floating-point format specification and the program did not contain any floating-point values or variables.
3.        The compiler minimizes a program's size by loading floating-point support only when necessary. The compiler cannot detect floating-point format specifications in format strings, so it does not load the necessary floating-point routines.
4.        Use a floating-point argument to correspond to the floating-point format specification, or perform a floating-point assignment elsewhere in the program. This causes floating-point support to be loaded.
5.        In a mixed-language program, a C library was specified before a FORTRAN library when the program was linked. Relink and specify the C library last.

首先用IDA启动程序,在CWnd__OnCommand设断点,能断下来,依次进入该函数的调用,最后定位到当执行到下列代码段时出错,
.text:00420D59                 fld     ds:dbl_425DC0
.text:00420D5F                 fstp    qword ptr [ebp-8]
.text:00420D62                 fld     qword ptr [ebp-8]
.text:00420D65                 fadd    st, st
.text:00420D67                 fstp    qword ptr [ebp-8]
.text:00420D6A                 sub     esp, 8
.text:00420D6D                 fld     qword ptr [ebp-8]
.text:00420D70                 fstp    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    ;出错行.text:00420D86                 add     esp, 14h
.text:00420D89                 push    40h
而当跳过出错的行时程序没有出现Run-Time Error,但提示的对话框中的字符串是错误的,看来该函数必须执行,而该函数是静态链接的时从msvcrt .lib库中“COPY”过来的,因此函数本身是没有错误的,那么出错的根本原因是程序在进行链接的时候,认为程序中不需要对浮点数进行格式化处理,因此没有将进行浮点数处理的C运行时库一同链接进入本程序,例如__fpmath函数就是其中一个。因此,如果在程序中碰到进行浮点数格式化处理的时候,就会因找不到与浮点数格式化处理的C运行时库函数而出现R6002错误。
用如下的一个C程序可以演示该错误:
#include "stdio.h"
double pi=3.14159;
wchar_t mybuf[40];
void floatCrash()
{
  double pi2;
  wchar_t* Text;
  Text = mybuf;
  __asm
  {
    fld     pi
    fstp    [ebp-8]
    fld     [ebp-8]
    fadd    st, st
    fstp    [ebp-8]
    fld     [ebp-8]
    fstp    [esp]
  }
  _snwprintf(Text, 0x40u, L"PI * 2 = %f");
}
void  main(void)
{  
   floatCrash();
}
上面程序运行时会出现同样的R6002.错误。
注意上面的内联汇编实际上完成的pi×2的功能,因为该程序没有直接进行浮点数的操作,因此cl编译器主观的认为程序中没有与浮点数格式化字符串相关的操作,因此LINK程序就没有将与浮点数格式化处理的C运行时库函数一同链接进入目标程序,导致运行时出现R6002错误,这或许是MS公司VC的一个BUG。
如果将double pi2;
改为double pi2=0.0;
这程序不会出现R6002.错误,原因是该语句进行了浮点数的赋值操作,LINK程序就会将与浮点数格式化处理的C运行时库函数一同链接进入目标程序。

二、程序修复方法
        因为程序是静态链接了msvcrt .lib库的_snwprintf函数,但该函数是不能调用的,那么我们可以从msvcrt .dll中来调用该函数,应该就没有问题了。方法是:
1、        增加msvcrt .dll中的输入函数_snwprintf,相应的输入表项位于0x286e0
000286e0h: 6D 73 76 63 72 74 2E 64 6C 6C 00 00 00 5F 73 6E ; msvcrt.dll..._sn
000286f0h: 77 70 72 69 6E 74 66 00 0B B0 03 00 00 00 00 00 ; wprintf..?.....
00028700h: EB 86 02 00 00 00 00 00 EB 86 02 00 00 00 00 00 ; 雴......雴......
2、        同时将输入表目录从0x27d00移到0x28710,大小从0xb4增加到0xc8
3、        对如下指令进行修改
修改前:
.text:00420D81                 call    __snwprintf    ;出错行
.text:00420D86                 add     esp, 14h
修改后:
.text:00420D81                 call    ds:_snwprintf
.text:00420D87                 nop
.text:00420D88                 nop
add     esp, 14h是恢复堆栈的操作,由于后面的CALL多一个字节,因此该指令被NOP掉了,但分析可知,该函数返回时有
mov     esp, ebp和pop     ebp的操作,因此不会破坏程序的执行。
4、        程序的大小和节数目没有改变,好像没有这个要求,呵呵!
5、        因为都是手动修改的,没有提交PATCH程序,提交的修改后的TestFloat.exe。
最后程序运行结果为:

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
2
分析错误,请重新考虑!!
2008-10-14 15:26
0
雪    币: 221
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
虽然跟标准答案不一样,但也不会连一分都没有吧,至少有个正确的对话框出来了
2008-10-14 21:47
0
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
4
没,不是一分都没,像你这种情况的,需要商量后在订分!!不好意思,不是没分数!!!
2008-10-15 19:34
0
雪    币: 221
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
看来这题还是没分,白做了
2008-11-14 08:33
0
雪    币: 2134
活跃值: (14)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
6
这题等kangaroo给你解答
2008-11-17 00:36
0
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
7
0040F621     68 5C404200       push TestFloa.0042405C
0040F626     E8 65670000       call <TestFloa.__IsNonwritableInCurrentImage >  这个call是关键点
0040F62B     85C0              test eax,eax
0040F62D     59                pop ecx                                       ; TestFloa.0040EBD8
0040F62E     74 0B             je short TestFloa.0040F63B 这个为关键跳转
0040F630     FF7424 04         push dword ptr ss:[esp+4]
0040F634     FF15 5C404200     call dword ptr ds:[42405C]                    ; <TestFloa.__fpmath                   00411e26 f   libcmt:fpinit.obj>

如果只分析到关键点,并不做修复乘以0.3,做了修复乘以1
2008-11-17 09:09
0
游客
登录 | 注册 方可回帖
返回
//