程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 利用gcc自帶的功能-fstack-protector檢測棧溢出及其實現,fstackprotector

利用gcc自帶的功能-fstack-protector檢測棧溢出及其實現,fstackprotector

編輯:關於C語言

利用gcc自帶的功能-fstack-protector檢測棧溢出及其實現,fstackprotector


  最近又遇到了一個崩潰,棧回溯非常怪異。

/lib/i386-linux-gnu/libc.so.6(gsignal+0x4f) [0xb2b751df]
/lib/i386-linux-gnu/libc.so.6(abort+0x175) [0xb2b78825]
/lib/i386-linux-gnu/libc.so.6(+0x6b39a) [0xb2bb239a]
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45) [0xb2c4b0e5]
/lib/i386-linux-gnu/libc.so.6(+0x102eba) [0xb2c49eba]
/ramdisk/xxxxxx() [0x8467639]
/ramdisk/xxxxxx() [0x849a802]
/ramdisk/xxxxxx() [0x84b75da]
/ramdisk/xxxxxx(xxxxxxxxxxxx+0x444) [0x84b9224]

  其中的xxxxx是公司的模塊和函數,故隱藏,對接下去的分析沒有影響。

  一開始,因為沒有接觸過__fortify_fail這個函數,另外加上因為有一部分棧回溯沒有對應的符號,我以為是數組溢出把棧信息破壞了。但實際上想想不對,如果是棧信息被破壞了,不出意外的話,應該是回溯不到某些很有序的函數的,這些函數我沒上。

  後來同事無意的一句話,說__fortify_fail是內存檢測,我才百度了一下這個__fortify_fail函數,那麼這個函數是什麼情況下會被調用的呢?

一。gcc編譯選項-fstack-protector和-fstack-protector-all

  正是我在前面猜測的錯誤原因,牛人Stack Guard 就想出了保護棧信息的方式,在ebp和ip等信息的地址下面放一個保護數,如果棧溢出,那麼這個8位數會被修改,就會導致函數進入棧溢出錯誤處理函數,也就是導致了上面的棧。

二。比較加選項前後的反匯編代碼

  源碼:

#include <stdio.h>
int main()
{
        char a;
        int i;
        memcpy(&a,"ss",2);
        printf("1\n");
        memcpy(&i,"sssss",4);
        printf("2\n");
     return 0;
}

  使用gdb調試該程序,首先查看a和i的地址,

(gdb) p &a
$1 = 0xbffff69b "\b\364\037\374\267\220\204\004\b"
(gdb) p &i
$2 = (int *) 0xbffff694

  顯然變量a的地址要高,更接近棧頂。可以證明i的溢出並不一定能被檢測到,而a的檢測一定會被檢測到。

  看下匯編代碼的對比。

  movw $0x7373那句話就是往a裡面拷貝ss,所以整個程序前後的差異在於插入兩段代碼,這兩段的代碼就是用來檢測局部變量。

  運行溢出時的棧

#0  0xb7fdd424 in __kernel_vsyscall ()
#1  0xb7e4f1ef in raise () from /lib/i386-linux-gnu/libc.so.6
#2  0xb7e52835 in abort () from /lib/i386-linux-gnu/libc.so.6
#3  0xb7e8a2fa in ?? () from /lib/i386-linux-gnu/libc.so.6
#4  0xb7f20dd5 in __fortify_fail () from /lib/i386-linux-gnu/libc.so.6
#5  0xb7f20d8a in __stack_chk_fail () from /lib/i386-linux-gnu/libc.so.6
#6  0x08048485 in main ()

  與本文最前面的錯誤是一致的

三。走讀代碼修改錯誤。

 

四。總結

  當然這個舉措並不能夠完全的抑制棧溢出,如果跳過了保護數,那麼還是檢測不到棧溢出的,並且對其他的局部變量溢出沒有保護。當然每個變量都保護會大大增加程序復雜度。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved