我读了一些关于堆栈缓冲区溢出的文章,比如这篇,并学习了攻击者如何通过覆盖函数指针来利用堆栈缓冲区溢出漏洞。然后我编写了一个小程序来演示一个攻击:
#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()被成功调用了,但我不知道为什么它会运行两次。然后我使用GDB(见下文)进行了调试。(我只知道一些关于GDB的基本指令 ╮( ̄▽ ̄)╭)
我搜索了一些关键词,如“__libc_csu_fini()”,但没有找到一个清晰的方法来帮助我理解程序的执行路径。我对编译器和进程内部结构了解太少了,所以我认为我可能需要找一些详细描述这些东西的书籍或文章。有什么建议吗?谢谢!
GDB记录如下:
(gdb) list 7 printf("在fun1中,buffer= %s\n", buffer); 8 } 9 10 void fun2(void) { 11 printf("你好,fun2!\n"); 12 } 13 14 int main(int argc, char* argv[]) 15 { 16 printf("fun2的地址:%p\n", fun2); (gdb) 17 fun1("abcdefghijklmnopqrstuv\x52\x84\x04\x08"); 18 return 0; 19 } (gdb) break 16 断点1已在文件hello.c的第16行设置。 (gdb) run 正在启动程序:/home/yuliang/test/hello Breakpoint 1, main (argc=1, argv=0xbffff394) at hello.c:16 16 printf("fun2的地址:%p\n", fun2); 缺少单独的调试信息,使用:debuginfo-install glibc-2.13-2.i686 (gdb) step fun2的地址:0x8048452 17 fun1("abcdefghijklmnopqrstuv\x52\x84\x04\x08"); (gdb) fun1(input=0x804859a "abcdefghijklmnopqrstuvR\204\004\b") at hello.c:6 6 strcpy(buffer, input); (gdb) 7 printf("在fun1中,buffer= %s\n", buffer); (gdb) 在fun1中,buffer= abcdefghijklmnopqrstuvR� 8 } (gdb) fun2() at hello.c:10 10 void fun2(void) { (gdb) 11 printf("你好,fun2!\n"); (gdb) 你好,fun2! 12 } (gdb) 0x08048500 in __libc_csu_fini() (gdb) 一直单步执行,直到从没有行号信息的函数__libc_csu_fini返回。 fun2() at hello.c:10 10 void fun2(void) { (gdb) 11 printf("你好,fun2!\n"); (gdb) 你好,fun2! 12 } (gdb) 无法访问地址0x76757477的内存。 (gdb) 一直单步执行,直到从没有行号信息的函数__libc_csu_init返回。 0x009aae36 in __libc_start_main() from /lib/libc.so.6 (gdb) 一直单步执行,直到从没有行号信息的函数__libc_start_main返回。 程序以0241代码退出。 (gdb)