06 溢出攻击原理之汇编分析

来源:互联网 发布:数据采集仪 编辑:程序博客网 时间:2024/05/17 01:50

如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    83d4:       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 endin func ...   //func函数执行的输出Segmentation fault

溢出攻击实现原理:
如上面的代码, buf数组足够大, 接收用户输入时如果不判断长度, 就可以把要执行的指令存入buf数组, 最后通过数组的越界访问,把栈里存放的原lr寄存器的内容改成buf数组的首地址, 那么buf数组里存放的指令就可以执行了.
而已当main函数是管理员执行时, 那么在buf数组里存放的指令执行就具有管理员的权限了, 手机的root用的就是这种方法

防止溢出攻击的方法:
1). 接用户输时判断数据长度, 防止数组越界访问

2). 尽量在堆里分配空间

3). gcc 编译时加上-fstack-protection选项(man gcc里查看)

原创粉丝点击