二、利用溢出覆盖,改变程序流程及其简单应用
1、地址覆盖
同样的还是第一章开头的那个程序,让我们改成为一个有缓冲溢出问题的程序.
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void overflow(void)
{
char buf[10];
strcpy(buf,"aaaaaaaaaab1234");//<=-----改这里在原来的十个'a'后再加"b1234"
}//end overflow
int main(void)
{
overflow();
return 0;
}//end main
重新编译,在strcpy处设置断点,然后无错运行到断点处,切换到汇编代码窗口
00401020 55 push ebp
00401021 8B EC mov ebp,esp
00401023 83 EC 4C sub esp,4Ch
00401026 53 push ebx
00401027 56 push esi
00401028 57 push edi
00401029 8D 7D B4 lea edi,[ebp-4Ch]
0040102C B9 13 00 00 00 mov ecx,13h
00401031 B8 CC CC CC CC mov eax,0CCCCCCCCh
00401036 F3 AB rep stos dword ptr [edi]
7: char buf[10];
8: strcpy(buf,"aaaaaaaaaab1234");//<=-----让程序停在这里
00401038 68 1C F0 41 00 push offset string "aaaaaaaaaab1234" (0041f01c)
0040103D 8D 45 F4 lea eax,[ebp-0Ch]
00401040 50 push eax
00401041 E8 6A 00 00 00 call strcpy (004010b0)
00401046 83 C4 08 add esp,8
9: }//end overflow
00401049 5F pop edi
0040104A 5E pop esi
0040104B 5B pop ebx
0040104C 83 C4 4C add esp,4Ch
0040104F 3B EC cmp ebp,esp
00401051 E8 4A 01 00 00 call __chkesp (004011a0)
00401056 8B E5 mov esp,ebp
00401058 5D pop ebp
00401059 C3 ret
在watch窗口加入ebp和buf,并在memory窗口输入"buf"看一下strcpy函数执行以前的堆栈情况,选择"Long Hex Format",可以看到当前的堆栈情况如下:
0012FEE0 CCCCCCCC
.
.
.
.
0012FF20 CCCCCCCC //<=----buf的起始地址(再次强调,不同机器上运行时这里的值可能会不一样),12字节可用
0012FF24 CCCCCCCC
0012FF28 CCCCCCCC
0012FF2C 0012FF80 //<=----老的ebp,是由函数开始处的push ebp指令填入的
0012FF30 0040108D //<=----函数返回地址即main函数中call overflow指令的下指令地址
也可以表示为:
[64个保留字节(填充为0xcc)]
[buf(12个可用字节,当前全部填充为0xcc)]
[老的ebp(当前为0x0012FF80)]
[函数返回地址(当前为0x0040108D)]
按F10直至执行完call strcpy再看一下memory窗口红色的部分,选择"Byte Format",从buf的起始地址开始被填入了十个0x61('a'),一个0x62('b'),0x31('1'),0x32('2'),0x33 ('3'),0x34('4'),以及一个0x00,可以看到"老的ebp"已经被我们改变了:
0012FEE0 CCCCCCCC
.
.
.
.
0012FF20 61 61 61 61 aaaa //<=----buf的起始地址,内容已经改变
0012FF24 61 61 61 61 aaaa
0012FF28 61 61 62 31 aab1 //<=----注意!!!!!
0012FF2C 32 33 34 00 234. //<=----老的ebp内容已经被改变
0012FF30 8D 10 40 00 ..@. //<=----函数返回地址未变
看一下我刚才让你注意的地方,'b'和'1'将buf的12个可用字节的最后两个字节填充了,而后面的'2','3','4'和0x00做为一个 dword覆盖(修改)了ebp的值,再下面一个dword就是函数返回地址,再按F10执行,程序可以正常返回main(因为我们没有修改返回地址值),看到了这里改变函数返回地址成另外一个任意的值(让程序流程跳到另一地址空间)我想已经不是什么难事了吧!
可能初学缓冲溢出的朋友会问“这管什么用呢?”,不要着急下面我们就看看这样的技术究竟可以做什么!
