歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux下的棧溢出案例分析-GDB調試操練

摘要:
本文主要演示Linux平台下的棧溢出,首先根據理論對示例代碼進行溢出攻擊;結果是溢出攻擊成立,但是與設想的有差別;然後采用GDB調試工具對發生的意外,進行深入的分析。

Linux下用GDB調試可加載模塊 http://www.linuxidc.com/Linux/2013-01/77969.htm

Fedora 16 x64 構建vim+vimGDB+GDB C/C++調試環境 http://www.linuxidc.com/Linux/2012-08/69081.htm

GDB調試程序用法 http://www.linuxidc.com/Linux/2013-06/86044.htm

GDB+GDBserver無源碼調試Android 動態鏈接庫的技巧 http://www.linuxidc.com/Linux/2013-06/85936.htm

使用hello-gl2建立ndk-GDB環境(有源碼和無源碼調試環境) http://www.linuxidc.com/Linux/2013-06/85935.htm

在Ubuntu上用GDB調試printf源碼 http://www.linuxidc.com/Linux/2013-03/80346.htm

Linux下用GDB調試可加載模塊 http://www.linuxidc.com/Linux/2013-01/77969.htm

Ubuntu下使用GDB斷點Go程序 http://www.linuxidc.com/Linux/2012-06/62941.htm

測試的平台:
1.  Ubuntu 9;  gcc 4.4.1;  Gdb 7.0-ubuntu
2.  Ubuntu系統安裝在VirtualBox 3.2.8虛擬機上;

示例代碼如下:

#include<string.h>
void overflow(char* arg)
{
 char buf[12];
 strcpy(buf, arg);
}

int main(int argc, char *argv[])
{
 if(argc > 1)
  overflow(argv[1]);
 return 0;
}

如果按照一般的方式編譯:
gcc –o stackoverflow stackoverflow.c
linux系統能夠探測到程序中的stack  overflow,從而終止程序,如下圖所示:

那有沒有辦法讓系統不探測到stack overflow,此處可以在編譯時,禁用堆棧保護,具體命令如下:
gcc –fno-stack-protector –o stackoverflow stackoverflow.c
然後采用gdb調試stackoverflow,

這裡的輸出跟設想的存在很大的差別,因為設想中的函數棧如下:

前面的12個字節填充buf,然後接下來的4個字節填充ebp,最後的4個字節填充RET地址,那麼照理說,這裡的eip應該是0x65656565,那為什麼此處是0x61616161,剛好是aaaa的值呢?

根據單步調試的結果,發現eip變為0x61616161是在main函數退出後達到的,按照設想應該是在overflow退出時,eip變為0x65656565。

為什麼overflow退出後還能回到main函數?可能的原因:輸入的字符串沒有覆蓋掉ret地址,但是字符串卻意外地將main的返回地址給覆蓋掉了?

但就算是覆蓋,為什麼覆蓋的值沒有采用e的值,而是采用的a的值?要知道a是在字符串的起始處?這點的確讓人奇怪。

1. 我們還是采用一步步調試的方式來觀察問題所在,先看下gcc編譯後的反匯編代碼:
使用到的命令:
set disassembly-flavor intel  //將匯編設定為intel風格;
disassemble main  //反匯編main函數;

Main函數:

1. push ebp
2. mvo ebp, esp
3. and esp, 0xfffffff0
4. sub esp, 0x10
5. cmp DWORD PTR [ebp+0x8], 0x1
6. jle  0x804841d <main+31>
7. mov eax, DWORD PTR [ebp+0xc]
8. add eax, 0x4
9. mov eax, DWORD PTR [eax]
10. mov DWORD PTR [esp], eax
11. call 0x80483e4 <overflow>
12. mov eax, 0x0
13. leave
14. ret

然後再來看下,overflow的反匯編代碼,命令:disassemble overflow
Overflow函數:

1. push ebp
2. mov ebp, esp
3. sub esp, 0x28
4. mov  eax, DWORD PTR[ebp+0x8]
5. mov  DWORD PTR[esp+0x4], eax
6. lea  eax, [ebp-0x14]
7. mov  DWORD  PTR [esp], eax
8. call  0x804831c <strcpy@plt>
9. leave
10. ret

我們單步調試上述的指令,關注其中esp值的變化。總圖如下,後面是對其中每一步的分析:

在完成main.1後,命令p $esp後,esp的值變為:Esp = 0xbffff438
Main.3後,esp的值變為0xbffff430,估計是用於對齊;
Main.4後,esp的值為0xbffff420;
Main.7-10,這裡主要將argv[]的arg[1]字符串的首地址取出來,並且將其放置在esp中,此時esp的值為0xbffff420;

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-10/107768p2.htm

Copyright © Linux教程網 All Rights Reserved