06 溢位攻擊原理之彙編分析
阿新 • • 發佈:2019-02-16
如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裡檢視)