《深入理解计算机系统》 家庭作业3.38
/* Bomb program that is solved using a buffer overflow attack */#include <stdio.h>;#include <stdlib.h>;#include <ctype.h>;/* 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;}/* $begin getbuf-c */int getbuf(){ char buf[12]; getxs(buf); return 1;}void test(){ int val; printf("Type Hex string:"); val = getbuf(); printf("getbuf returned 0x%x\n", val);}/* $end getbuf-c */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) & 0xFFF); int *space = (int *) alloca(offset); *space = 0; /* So that don't get complaint of unused variable */ test(); return 0;}?题目的要求是,在getbuf函数中也许“显然”地会返回1,通过输入一个数据使这个函数返回0xdeadbeef,就是在test函数中地printf中打印地是0xdeadbeef.
经过了漫长的调试和学习,现在基本将这个题目搞定了。很激动啊,第一次学习溢出攻击第一次深入程序底部去做调整。不过需要注意:具体解题中涉及到的数据分布、汇编码和条件码和机器码和编译器、实际系统环境有关。
This GDB was configured as "i486-linux-gnu".?首先是下载源代码,并做开始实验前的基本工作。下载-->编译-->反编译-->查看反编译代码。
现在我们需要认真的查看汇编代码来看看如何达到目的。
?
从汇编代码中,我们容易发现:test调用了getbuf方法,然后在getbuf里面给%eax赋值为1,并返回并将%eax的值传递给val,最后将val值以16进制打印出来。这个结果不论如何就是0x1.
从上面的分析我们可以看出,如果不改变程序逻辑的话,不论怎样都是会以0x1的形式打印结果的。如果要打印0xdeadbeef,就需要以非正常的顺序执行代码。
有如下思路:
在返回到0x0804856f之前给%eax的最后赋值为0xdeadbeef;
直接修改存储在memory中的val值,然后跳过val的赋值语句直接打印结果;
等等。
我是以第一个思路来解题的,需要明确这些语句和代码必须利用存储在buf中来达到目的。那么我们就需要考虑buf的存储结构和与其相关的敏感数据位置:通过阅读汇编代码我们知道,虽然buf长度为12字节但是系统实际分配了0x10即16个字节,然后在buf和%ebp之间插入了一个%gs:0x14的4字节数据项。整体结构就成为:
?
从图的数据分布情况来看,我们可以大致了解到我们需要做的事情了。有余getxs没有对字符串长度做判断,我们就可以通过加长输入的字符串来覆盖buf上面的一些关键数据值。我们的主要目的是去修改“返回地址”,在修改做成中我们需要覆盖%gs:0x14和%ebp。由于%ebp涉及到caller的帧地址,所以在修改时需要保证这个数据不被改变;至于那个%gs:0x14是干什么的,我现在并不清楚,不过通过测试我发现如果它的数据发生变化就会报错,所以在修改时需要保证这个数据的完整性。
现在我们知道了需要去修改返回地址,那么我们需要返回到哪里、需要到那里去做什么呢?最开始已经说了,需要去修改%eax的值,然后直接跳转到0x0804856f。现在我先将需要做的事情的汇编代码和机器码写出来。
?
上面是一个完整的调试运行并最终出现结果的过程,在认真分析了思路之后很容易达到目的。在这里大家可以看到:从内存中读出的数据是要逆序排列的,而我们键入的机器码确实正常序排列的。
?
?
参考文献 写道【好玩】缓冲区溢出攻击实验?
?
?
?