1. 结果
00413DFD 8D45 88 lea eax,dword ptr ss:[ebp-78]
00413E00 56 push esi
00413E01 50 push eax
00413E02 FF35 C8A04200 push dword ptr ds:[42A0C8]
00413E08 E8 3FEFFFFF call <TestFloa.__decode_pointer 0>
00413E0D 59 pop ecx
00413E0E FFD0 call eax
_decode_pointer对42A0C8解码后,call eax, 进入_amsg_exit 后crash了
问题出在42A0C8, 看它的上下文
0042A0A8 6E 40 73 74 64 40 40 00 04 43 17 9B 04 43 17 9B
0042A0B8 04 43 17 9B 04 43 17 9B 04 43 17 9B 04 43 17 9B
0042A0C8 04 43 17 9B 04 43 17 9B 04 43 17 9B 04 43 17 9B
发现都是9B174304(每次是不同的固定值), 直觉告诉我, 这个加码的表有问题
2. 自己写程序
我自己写了一个浮点的程序, 在相同的位置,也找到了同样的表,但是我的程序表中的每个dword值是不同的, 为什么不同呢, 我对它们下写断点的, 在初始化的时候,看到了
类似
00431DC0 test._cfltcvt_init 55 push ebp
00431DC1 8BEC mov ebp,esp
00431DC3 C705 E8F14900 0BF>mov dword ptr ds:[_cfltcvt_tab],test.0042F90B
00431DCD C705 ECF14900 E0F>mov dword ptr ds:[49F1EC],test.0042F6E0
00431DD7 C705 F0F14900 BA0>mov dword ptr ds:[49F1F0],test.004303BA
00431DE1 C705 F4F14900 51F>mov dword ptr ds:[49F1F4],test.0042FE51
00431DEB C705 F8F14900 99F>mov dword ptr ds:[49F1F8],test.0042FC99
00431DF5 C705 FCF14900 0BF>mov dword ptr ds:[49F1FC],test.0042F90B
00431DFF C705 00F24900 9AF>mov dword ptr ds:[49F200],test.0042F19A
00431E09 C705 04F24900 830>mov dword ptr ds:[49F204],test.00430383
00431E13 C705 08F24900 B9F>mov dword ptr ds:[49F208],test.0042F5B9
00431E1D C705 0CF24900 DF0>mov dword ptr ds:[49F20C],test.004301DF
00431E27 5D pop ebp ; 0012FF4C
00431E28 C3 retn
这样的函数, 很明显,题目中的程序没有调这样的函数
3.比较分析
经过一层层对照的分析, 发现了这个关键点
0040F621 68 5C404200 push TestFloa.0042405C
0040F626 E8 65670000 call <TestFloa.__IsNonwritableInCurrentImage >
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>
题目中的程序_IsNonwritableInCurrentImage返回后,je跳转满足了,因此没有进入fpmath函数, 而我自己写的程序je没有满足,执行了fpmath函数
4.起因
知道为什么了,于是就看_IsNonwritableInCurrentImage函数了
关键就是这里了
00415DE9 E8 52FFFFFF call <TestFloa.__FindPESection 004>
00415DEE 83C4 08 add esp,8
00415DF1 85C0 test eax,eax
00415DF3 74 3B je short TestFloa.00415E30
00415DF5 8B40 24 mov eax,dword ptr ds:[eax+24]
00415DF8 C1E8 1F shr eax,1F
00415DFB F7D0 not eax
00415DFD 83E0 01 and eax,1
这里是取出.rdata段的属性,然后检查0xC0000000位,于是发现题目中这个位是1, 我自己写的程序,这个位是0
5. 结论
从这个题目中, 大概的结论是
程序初始化的时候,会通过_FPinit的对象来找到它所在的段,一般是.rdata段,然后去查这个段的属性, 如果标记为不可写,那么去执行fpmath函数来进行一些浮点运算的初始化,如果可写,那么不执行那个函数。而那个函数所做的初始化,正好是我们_snwprintf中所用到的