1. 程式人生 > >06 溢位攻擊原理之彙編分析

06 溢位攻擊原理之彙編分析

如c程式的程式碼:

test.c:
  1
  2 #include <stdio.h>
  3 
  4 int main(void)
  5 {
  6     int buf[10];
  7 
  8     printf("end\n"); //用於讓編譯器對lr暫存器壓棧
  9     return 0;
 10 }

反彙編後得到的程式碼:

000083cc <main>:
    83cc:       e92d4800        push    {fp, lr}
    83d0:       e28db004        add     fp, sp, #4
    83
d4: e24dd028 sub sp, sp, #40 // int buf[10]的空間 83d8: e59f0010 ldr r0, [pc, #16] ; 83f0 <main+0x24> 83dc: ebffffb7 bl 82c0 <_init+0x20> 83e0: e3a03000 mov r3, #0 83e4: e1a00003 mov r0, r3 83e8: e24bd004 sub
sp, fp, #4 83ec: e8bd8800 pop {fp, pc}
main函式執行時棧裡的內容:
  [lr暫存器原內容]
  [fp暫存器原內容]
  [ buf[9]     ]  // &buf[9], 棧的地址從高往低,陣列元素的地址是從低往高.
    ...
  [ buf[0]     ]  // &buf[0]
通過陣列超界訪問,可以改變棧裡存放的lr暫存器原內容,可以改為想執行的程式碼的地址.
實驗程式碼:
      1 
      2 #include <stdio.h>
      3
4 void func() 5 { 6 printf("in func ...\n"); 7 } 8 int main(void) 9 { 10 int buf[10]; 11 int i = 11; 12 13 buf[i] = (int)func; 14 buf[i+1] = (int)func; //這裡不是執行,只是把func函式的地址存放在棧裡的lr暫存器原內容的位置 15 16 printf("end\n"); //用於讓編譯器對lr暫存器壓棧 17 return 0; //當函式執行結束,pop {fp, pc}; 從棧裡的lr暫存器內容的位置上讀出內容,並根據讀出的返回地址來跳轉, 所以func函式就有機會執行了 18 } 編譯後執行的輸出: ^_^ /mnt/codes/03asm_deep # ./a.out end in func ... //func函式執行的輸出 Segmentation fault

溢位攻擊實現原理:
如上面的程式碼, buf陣列足夠大, 接收使用者輸入時如果不判斷長度, 就可以把要執行的指令存入buf陣列, 最後通過陣列的越界訪問,把棧裡存放的原lr暫存器的內容改成buf陣列的首地址, 那麼buf數組裡存放的指令就可以執行了.
而已當main函式是管理員執行時, 那麼在buf數組裡存放的指令執行就具有管理員的許可權了, 手機的root用的就是這種方法

防止溢位攻擊的方法:
1). 接使用者輸時判斷資料長度, 防止陣列越界訪問

2). 儘量在堆裡分配空間

3). gcc 編譯時加上-fstack-protection選項(man gcc裡檢視)