第三题分析报告
运行程序,报错:
Runtime Error!R6002
- floating point support not loaded
然后用OD载入,不忽略所有异常,直接运行,发现没有捕捉到异常,说明这个MsgBox不是由于浮点出错导致的。
对MessageBoxA下断,返回后找到代码处理部分:
00420D59 fld qword ptr [425DC0]
00420D5F fstp qword ptr [ebp-8]
00420D62 fld qword ptr [ebp-8]
00420D65 fadd st, st
00420D67 fstp qword ptr [ebp-8]
00420D6A sub esp, 8
00420D6D fld qword ptr [ebp-8]
00420D70 fstp qword ptr [esp]
00420D73 push 00425A34 ; pi * 2 = %f
00420D78 push 40
00420D7A lea edx, dword ptr [ebp-90]
00420D80 push edx
00420D81 call 0040EE02
00420D86 add esp, 14
00420D89 push 40
00420D8B push 00425A4C ; testfloag
00420D90 lea eax, dword ptr [ebp-90]
00420D96 push eax
00420D97 mov ecx, dword ptr [ebp-94]
00420D9D call 00405C75
在420D81处会弹出错误窗口,跟进:
……
0040EE7E push edi
0040EE7F lea eax, dword ptr [ebp+14]
0040EE82 push eax
0040EE83 push ebx
0040EE84 push dword ptr [ebp+10]
0040EE87 lea eax, dword ptr [ebp-20]
0040EE8A push eax
0040EE8B call 00413871
继续跟进40EE8B处的CALL,发现是一个格式化字符串的代码,当扫描到%f时来到:
00413DEC |push eax
00413DED |push dword ptr [ebp-6C]
00413DF0 |movsx eax, dl
00413DF3 |push dword ptr [ebp-18]
00413DF6 |mov dword ptr [ebp-28], ebx
00413DF9 |push eax
00413DFA |push dword ptr [ebp-20]
00413DFD |lea eax, dword ptr [ebp-78]
00413E00 |push esi
00413E01 |push eax
00413E02 |push dword ptr [42A0C8]
00413E08 |call 00412D4C ; Call Float OEP DecodePointer
00413E0D |pop ecx
00413E0E |call eax ; TestFloa.0041AE1F
这里先在00413E08处的CALL里用DecodePointer函数对[42A0C8]的值解码出一个地址,然后在413E0E处CALL这个地址。
在MSDN里搜索DecodePointer,解释是:每个进程都会产生一个随机的dword值,用户可以先用这个随机值用EncodePointer对数据进行加密,在需要时再用DecodePointer解密。
在OD里跟进这个API想了解加密方式,无解。
在google里搜索EncodePointer与DecodePointer,有解释为:EncodePointer对待加密的数据仅进行XOR,调用DecodePointer时再次对数据进行XOR还原。
在OD载入时,发现[0042A0C8]=0041AE1F,刚好与DecodePointer解码出来的值相等,因此只需要修改[0042A0C8]初始时的值为正确的地址,即可使程序正常运行。
自己做一个C控制台程序mytestFloat.cpp,写入代码:
// mytestFloat.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
float f=3.14159;
printf("PI = %f",f);
return 0;
}
生成release程序后用OD调试:
00401000 /$ DD05 F0204000 fld qword ptr [4020F0]
00401006 |. 83EC 08 sub esp, 8 ; /<%f>
00401009 |. DD1C24 fstp qword ptr [esp] ; |
0040100C |. 68 E4204000 push 004020E4 ; |format = "PI = %f"
00401011 |. FF15 9C204000 call dword ptr [<&MSVCR80.printf>; \printf
00401017 |. 83C4 0C add esp, 0C
0040101A |. 33C0 xor eax, eax
0040101C \. C3 retn
跟进00401011的CALL:
781422F3 >/$ 6A 0C push 0C
781422F5 |. 68 38501B78 push 781B5038
781422FA |. E8 7967FFFF call 78138A78
781422FF |. 33C0 xor eax, eax
78142301 |. 33F6 xor esi, esi
78142303 |. 3975 08 cmp dword ptr [ebp+8], esi
78142306 |. 0F95C0 setne al
78142309 |. 3BC6 cmp eax, esi
7814230B |. 75 1D jnz short 7814232A
7814230D |. E8 A01FFFFF call _errno
78142312 |. C700 16000000 mov dword ptr [eax], 16
78142318 |. 56 push esi
78142319 |. 56 push esi
7814231A |. 56 push esi
7814231B |. 56 push esi
7814231C |. 56 push esi
7814231D |. E8 3E65FFFF call _invalid_parameter
78142322 |. 83C4 14 add esp, 14
78142325 |. 83C8 FF or eax, FFFFFFFF
78142328 |. EB 5F jmp short 78142389
7814232A |> E8 05FDFEFF call __p__iob
7814232F |. 6A 20 push 20
78142331 |. 5B pop ebx
78142332 |. 03C3 add eax, ebx
78142334 |. 50 push eax
78142335 |. 6A 01 push 1
78142337 |. E8 67BFFFFF call 7813E2A3
7814233C |. 59 pop ecx
7814233D |. 59 pop ecx
7814233E |. 8975 FC mov dword ptr [ebp-4], esi
78142341 |. E8 EEFCFEFF call __p__iob
78142346 |. 03C3 add eax, ebx
78142348 |. 50 push eax
78142349 |. E8 2FEEFFFF call 7814117D
7814234E |. 59 pop ecx
7814234F |. 8BF8 mov edi, eax
78142351 |. 8D45 0C lea eax, dword ptr [ebp+C]
78142354 |. 50 push eax
78142355 |. 56 push esi
78142356 |. FF75 08 push dword ptr [ebp+8]
78142359 |. E8 D6FCFEFF call __p__iob
7814235E |. 03C3 add eax, ebx
78142360 |. 50 push eax
78142361 |. E8 8DF0FFFF call 781413F3
再次跟进78142361处的call 781413F3,会发现里面的代码与目标程序testFloat.exe中的格式化字符串的代码00413871处几乎完全相同!
在这里做大胆猜测:testFloat.exe把printf格式化字符串的代码全部都编译到自己的程序体里了。对比发现,目标程序对printf代码进行了修改,用DecodePointer对浮点处理过程的入口进行了处理。
测试程序中对浮点处理的调用为:
781419F7 |push eax ; /Arg7
781419F8 |push dword ptr [ebp-78] ; |Arg6
781419FB |movsx eax, dl ; |
781419FE |push dword ptr [ebp-20] ; |Arg5
78141A01 |mov dword ptr [ebp-2C], edi ; |
78141A04 |push eax ; |Arg4
78141A05 |push dword ptr [ebp-68] ; |Arg3
78141A08 |lea eax, dword ptr [ebp-80] ; |
78141A0B |push ebx ; |Arg2
78141A0C |push eax ; |Arg1
78141A0D |call 78149BC9 ; \MSVCR80.78149BC9
进入78141A0D处的CALL:
78149BC9 /$ 55 push ebp
78149BCA |. 8BEC mov ebp, esp
78149BCC |. 8B45 14 mov eax, dword ptr [ebp+14]
78149BCF |. 83F8 65 cmp eax, 65 ; Switch (cases 41..66)
78149BD2 |. 74 5F je short 78149C33
78149BD4 |. 83F8 45 cmp eax, 45
78149BD7 |. 74 5A je short 78149C33
78149BD9 |. 83F8 66 cmp eax, 66
78149BDC |. 75 19 jnz short 78149BF7
78149BDE |. FF75 20 push dword ptr [ebp+20] ; Case 66 ('f') of switch 78149BCF
78149BE1 |. FF75 18 push dword ptr [ebp+18]
78149BE4 |. FF75 10 push dword ptr [ebp+10]
78149BE7 |. FF75 0C push dword ptr [ebp+C]
78149BEA |. FF75 08 push dword ptr [ebp+8]
78149BED |. E8 0BFEFFFF call 781499FD
78149BF2 |. 83C4 14 add esp, 14
78149BF5 |. 5D pop ebp
78149BF6 |. C3 retn
观察这一段代码的二进制值,发现使用的都是相对地址,在testFloat.exe中搜索这一部分二进制代码558BEC8B451483F865745F83F845745A83F8667519,来到这里:
00418D69 /$ 55 push ebp ; format string for float
00418D6A |. 8BEC mov ebp, esp ; (initial cpu selection)
00418D6C |. 8B45 14 mov eax, dword ptr [ebp+14]
00418D6F |. 83F8 65 cmp eax, 65 ; Switch (cases 41..66)
00418D72 |. 74 5F je short 00418DD3
00418D74 |. 83F8 45 cmp eax, 45
00418D77 |. 74 5A je short 00418DD3
00418D79 |. 83F8 66 cmp eax, 66
00418D7C |. 75 19 jnz short 00418D97
00418D7E |. FF75 20 push dword ptr [ebp+20] ; Case 66 ('f') of switch 00418D6F
00418D81 |. FF75 18 push dword ptr [ebp+18]
00418D84 |. FF75 10 push dword ptr [ebp+10]
00418D87 |. FF75 0C push dword ptr [ebp+C]
00418D8A |. FF75 08 push dword ptr [ebp+8]
00418D8D |. E8 26FEFFFF call 00418BB8
00418D92 |. 83C4 14 add esp, 14
00418D95 |. 5D pop ebp
00418D96 |. C3 retn
能找到浮点处理过程的代码入口00418D69,说明编译程序时把这段代码已经编译进去了,但是DecodePointer是对固定[0042A0C8]处的数据进行解码,而[0042A0C8]=0041AE1F存的不是浮点处理代码入口,而是报“floating point support not loaded”错误的代码入口。
现在就已经找到解决办法了:只需要修改程序初始时[0042A0C8]的值为浮点处理过程的入口00418D69,就可以解决这个问题了。
0042A0C8的物理偏移为2A0C8,用16进制工具修改2A0C8处的值为:
2A0C8:1F AE 41 00==>69 8D 41 00
保存后运行,点击Crach按钮,弹出“PI * 2 = 6.283180”对话框,成功!
为避免暗桩,在16进制工具中搜索“1F AE 41 00”,发现从2A0B0到2A0D8全部都是这个值,全部改成“69 8D 41 00”,再次测试,成功!
由于条件有限,只能用手机上网,无法提交附件,只能说一下文件修改方法了:
修改testFloat.exe二进制代码,从2A0B0到2A0D8全部都改成“69 8D 41 00”。
PS:最后弹出的MsgBox中的标题写成“testFloag”了。。。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!