我读了一些关于堆栈缓冲区溢出的文章,如this之一,并且学习了攻击者如何通过覆盖函数指针来利用堆栈缓冲区溢出错误。然后我写了一个小程序来演示一次攻击:堆栈缓冲区溢出导致的奇怪执行路径
#include <stdio.h>
#include <string.h>
void fun1 (char * input) {
char buffer[10];
strcpy(buffer, input);
printf("In fun1, buffer= %s\n", buffer);
}
void fun2 (void) {
printf ("HELLO fun2!\n");
}
int main (int argc, char * argv[])
{
printf ("Address of fun2: %p\n", fun2);
fun1("abcdefghijklmnopqrstuv\x52\x84\x04\x08");
return 0;
}
该程序在Fedora 14 x86下使用GCC 4.5.1编译。下面是输出:
$ ./exp01
FUN2地址:0x8048452
在FUN1,缓冲= abcdefghijklmnopqrstuvR
HELLO FUN2!
HELLO fun2!
我们可以看到fun2()被成功调用,但我不知道它为什么会跑两次。然后我GDBed它(见下文)。 (我只知道关于GDB的一些基本指令(¯▽¯))
我搜索了一些关键词,比如“__libc_csu_fini()”,但没有找到明确的方法可以帮助我理解程序的执行路径。我对编译器和进程的内部结构知之甚少,所以我认为我可能不得不找到一些书或文章来详细描述这些东西。任何建议?谢谢!
GDB记录:
(GDB)列表
7的printf( “以FUN1,缓冲液=%S \ n” 个,缓冲液);
8}
10空隙FUN2(无效){
11的printf(“HELLO FUN2!\ n “);
12}
14 INT主(INT的argc,字符* argv的[])
15 {
16的printf(” FUN2的地址:%p \ n “个,FUN2);
(GDB)
17 FUN1(” abcdefghijklmnopqrstuv \ x52 \ x84 \ x04 \ x08“);
18 return 0;
19}
(GDB)16断裂
在0x804846f断点1:文件hello.c,线16
(GDB)运行
启动程序:/家庭/渔梁/测试/你好
断点1,主(的argc = 1,的argv = 0xbffff394)在hello.c中:16
16 printf(“Fun2的地址:%p \ n”,fun2);
缺少单独debuginfos,使用:debuginfo软安装的glibc-2.13-2.i686
(GDB)步骤
FUN2的地址:0x8048452
17 FUN1(“abcdefghijklmnopqrstuv \ X52 \ X84 \ x04 \ x08“);
(GDB)
FUN1(输入= 0x804859a “abcdefghijklmnopqrstuvR \ 204 \ 004 \ B”)在的hello.c:6
6的strcpy(缓冲器,输入);
(GDB)
7的printf( “以FUN1,缓冲液=%S \ n” 个,缓冲液);
(GDB)
在FUN1,缓冲液= abcdefghijklmnopqrstuvR
8}
(GDB)
在hello.c的FUN2():10
10空隙fun2(void){
(gdb)
11 printf(“HELLO fun2!\ n”);
(GDB)
HELLO FUN2
12}
(GDB)
在__libc_csu_fini 0x08048500()
(GDB)
!单步直到退出函数__libc_csu_fini,
没有行号信息。
在hello.c的FUN2():10
10空隙FUN2(无效){
(GDB)
11的printf( “!HELLO FUN2 \ n”);
(gdb)
HELLO fun2!
12}
(GDB)
在地址0x76757477
(GDB)
单步执行,直到从功能__libc_csu_init退出,
它没有行不能访问内存号码信息。
在__libc_start_main从/lib/libc.so.6
(GDB)
单步,直到从功能__libc_start_main退出,不具有行号信息
0x009aae36()。
程序与代码0241.
(GDB)退出
Smashing the stack for fun and profit当您在FUN1没有的printf运行的程序将在程序执行两次呢? – Azrael3000 2012-03-02 10:00:14
您需要使用机器代码调试器来浏览这些东西---查找gdb nexti,stepi和disas命令。在C模式下的调试器会变得非常困惑,因为它依赖于有效的栈帧来知道哪里正在执行什么,当然它们不再是了,因为你刚才改变了它们。 – 2012-03-02 11:14:03
谢谢你的回复@ Azrael3000。我在fun2中注释掉printf。它回到main()中的printf中,并进入死循环。但fun2()的地址现在是0x804843e。如果我调用fun1(“abcdefghijklmnopqrstuv x3e x84 x04 x08”)而不是fun1(“abcdefghijklmnopqrstuv x52 x84 x04 x08”),fun2仍然运行两次。 – Gnailuy 2012-03-02 11:18:34