上午提交答案,心里总不踏实,有跟了一个晚上,感觉上午提交有点草率了,在提交一份,心里有个底哈
1,从 00420D81 |. E8 7CE0FEFF call <__snwprintf 0040ee02 f>; \_snwprintf
出错的地方F7跟进去,来到
0040EE7E |> \57 push edi
0040EE7F |. 8D45 14 lea eax, dword ptr [ebp+14]
0040EE82 |. 50 push eax
0040EE83 |. 53 push ebx
0040EE84 |. FF75 10 push dword ptr [ebp+10]
0040EE87 |. 8D45 E0 lea eax, dword ptr [ebp-20]
0040EE8A |. 50 push eax
0040EE8B |. E8 E1490000 call <__woutput_l 00413871 f > //到这里
继续跟进到
00413DEC |. 50 |push eax
00413DED |. FF75 94 |push dword ptr [ebp-6C]
00413DF0 |. 0FBEC2 |movsx eax, dl
00413DF3 |. FF75 E8 |push dword ptr [ebp-18]
00413DF6 |. 895D D8 |mov dword ptr [ebp-28], ebx
00413DF9 |. 50 |push eax
00413DFA |. FF75 E0 |push dword ptr [ebp-20]
00413DFD |. 8D45 88 |lea eax, dword ptr [ebp-78]
00413E00 |. 56 |push esi
00413E01 |. 50 |push eax
00413E02 |. FF35 C8A04200 |push dword ptr [42A0C8] ; <TestFloa.__fptrap 0041ae1f f libcmt:crt0fp.obj>
00413E08 |. E8 3FEFFFFF |call <__decode_pointer 00412d4c f >
00413E0D |. 59 |pop ecx
00413E0E |. FFD0 |call eax //在里出错
查了下__decode_pointer 函数,作用是对[42A0C8] 里的地址 进行解密,然后返回给 eax,最后call 到这个解密的地址,所以,判断,出错应该是 这个解密的地址的问题,然后 对42A0C8,下一个 硬件写入断点,重新运行程序,来到:
00415CEC >/$ 56 push esi
00415CED |. 57 push edi
00415CEE |. 33FF xor edi, edi
00415CF0 |> 8DB7 B0A04200 /lea esi, dword ptr [edi+42A0B0]
00415CF6 |. FF36 |push dword ptr [esi]
00415CF8 |. E8 D8CFFFFF |call <__encode_pointer 00412cd5 f >
00415CFD |. 83C7 04 |add edi, 4
00415D00 |. 83FF 28 |cmp edi, 28
00415D03 |. 59 |pop ecx
00415D04 |. 8906 |mov dword ptr [esi], eax //在这里断下
00415D06 |.^ 72 E8 \jb short 00415CF0
00415D08 |. 5F pop edi
00415D09 |. 5E pop esi
00415D0A \. C3 retn
在00415D04 断下,这里说下这个call的作用,循环得到 [edi+42A0B0] 地址,然后用__encode_pointer 进行加密,这里__encode_pointer 和 __decode_pointer 是对应的
一个加,一个解,显然这个 地址是有问题的, 于是,返回上一层来到0040F640:
0040F618 >/$ 833D 5C404200>cmp dword ptr [42405C], 0 0040F61F |. 74 1A je short 0040F63B // 这里判断__fpmath 是否等于零
0040F621 |. 68 5C404200 push 0042405C
0040F626 |. E8 65670000 call <__IsNonwritableInCurrentImage 00415d90 >
0040F62B |. 85C0 test eax, eax
0040F62D |. 59 pop ecx
0040F62E |. 74 0B je short 0040F63B //这里通过__IsNonwritableInCurrentImage 函数检查0042405C所在的区段 是否为只读
0040F630 |. FF7424 04 push dword ptr [esp+4]
0040F634 |. FF15 5C404200 call dword ptr [42405C] ; <TestFloa.__fpmath 00411e26 f libcmt:fpinit.obj> //只读执行
0040F63A |. 59 pop ecx
0040F63B |> E8 AC660000 call <__initp_misc_cfltcvt_tab 00415cec f >
0040F640 |. 68 98244200 push 00422498 //返回到这
0040F645 |. 68 7C244200 push 0042247C
0040F64A |. E8 36FFFFFF call <__initterm_e 0040f585 f >
0040F64F |. 85C0 test eax, eax
为了说明问题,把call前面的代码都贴上,这个是 _cinit 函数的代码,为了看着舒服,找到他的原代码:
int __cdecl _cinit (
int initFloatingPrecision
)
{
int initret;
/*
* initialize floating point package, if present
*/
#ifdef CRTDLL
_fpmath(initFloatingPrecision);
#else /* CRTDLL */
if (_FPinit != NULL &&
_IsNonwritableInCurrentImage((PBYTE)&_FPinit))
{
(*_FPinit)(initFloatingPrecision);
}
_initp_misc_cfltcvt_tab();
#endif /* CRTDLL */
到这里已经很显然了,应该是0042405C所在的区段 只读条件不成立,导致浮点指针包未能初始化,最后导致错误,为了证实,用LordPE 看了下,0042405C所在.rdata 区段为C0000040,可写,导致错误
2,解决方法
根据_cinit 代码,让#ifdef CRTDLL 条件满足,这个不熟悉,猜应该是个dll吧,可以在vc工程里 导入CRTDLL,或者用LordPE 修改.rdata 为只读40000040就可以了,这里也可以修改成60000040 能读能执行 即可 ,或者加个什么壳 ,能改变它的区段的都可以,这里我测试了论坛上大大说的upx壳,成功.
3,最后发个我用LordPE 修改的TestFloat.exe