我讀了一些關於堆棧緩衝區溢出的文章,如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