任务2:ASLR、DEP与栈保护

一、任务内容

①查阅资料,了解地址空间布局随机化(Address Space Layout Randomization,ASLR)的原理和作用。

②在Windows操作系统中,基于VC 6编写、编译包含简单自定义函数func( )调用的控制台小程序,利用反编译结果或调试跟踪分析func( )的调用与地址;基于VS C++编译上述同一代码,并分析func( )的调用与地址变化。

③在Linux操作系统中,查看、开启、关闭ASLR。(Windows操作系统中也可以进行相关操作,但不建议在Windows中进行)

④基于gcc编译器,开启、关闭数据执行保护(Data Execution Prevention,DEP)和栈保护,利用反编译结果或调试跟踪,分析开启和关闭编译选项前后编译结果的差异

二、任务目的

了解内存安全,了解基于内存破坏的缓冲区溢出等攻击的防范方法。

三、实验内容

3.1 查阅资料

查阅资料,了解地址空间布局随机化(Address Space Layout Randomization,ASLR)的原理和作用

原理:

在Windows下, ASLR主要表现在三个方面:映像基址随机化、堆栈基址随机化和PEB/TEB随机化。

1)映像基址随机化

当可执行文件或动态链接库文件被映射到内存时, 系统会对其虚拟地址进行随机化。

由于主要是对各模块载入内存的基地址进行随机化处理, 所以叫映像基址随机化。微软Windows系列操作系统的内存随机化使系统每次初始化过程中, 随机分配各个模块的基地址, 所以同一个模块在系统重启后, 其基地址是不同的。

2)堆栈基址随机化

程序在启动时, 系统会随机选择堆栈的基址, 从而导致内存中的各种变量地址发生变化。程序每次启动后, 其所占用的堆栈地址可能完全不同。与映像基址随机化在系统初始化的过程中随机加载不同, 堆栈基址随机化是在程序每次启动时实施的。

3)PEB/TEB随机化

进程环境块(Process Environment Block, PEB)和线程环境块(Thread Environment Block, TEB)随机化在Windows XP时代就已经引入系统中, 但是发展到Windows 8系统, PEB/TEB的随机化仍然做得不是很好。

作用:

地址空间配置随机加载利用随机方式配置数据地址空间,使某些敏感数据(例如操作系统内核)配置到一个恶意程序无法事先获知的地址,令攻击者难以进行攻击。

3.2 对比VC6和VSC++func( )的调用与地址变化

在Windows操作系统中,基于VC 6编写、编译包含简单自定义函数func( )调用的控制台小程序,利用反编译结果或调试跟踪分析func( )的调用与地址;基于VS C++编译上述同一代码,并分析func( )的调用与地址变化。

3.2.1 代码

#include<stdio.h>int sum(int x,int y)
{return x + y;
}int main()
{sum(1, 2);return 0;
}

3.2.2 VC6.0调试过程

首先是VC6.0下的实验过程,利用调试工具单步调试。

在程序的执行当中,当调用sum函数对数字1和数字2进行处理的时候,将数字2和1依次压入栈中,这个时候堆栈中esp的值已经减8。

接下来调用了call,这时进行了两步操作,先将call后面的地址push进堆栈,然后再jmp到call所调用的地址。然后因为编译器的原因在call的时候还会有一个jmp来中转到后面的处理函数,因为jmp不影响堆栈,可以忽略掉它,这里是跳转到了sum函数的处理位置。

此时的堆栈是没有发生变化的,现在开始到了函数调用的关键阶段了。

首先先将ebp的值push到堆栈中,因为用到了ebp寻址的方式,所以这里用这种方式来保存ebp中原本的值,然后将esp的值赋给ebp,用ebp寻址来代替esp寻址,因为esp的值一直在不断的发生变化,使用esp寻址会带来很大的计算负担,此时esp与ebp都指向了同一块地址,其中的内容是原来的ebp的值。然后让esp减去了0c0h位,开始提升堆栈了,为程序的运行开辟缓冲区,因为一个单元是四个字节,c0也就是往上提了48个bit。

后面又进行了一系列的push操作,也是为了方便在后续使用这些寄存器的时候保证它们初始的值不丢失,与前面保存ebp的值是一样的方式。然后接下来的四步操作只有一个目的,那就是将中间的48bits全部值为CC,CC在调试的时候相当于断点。

lea是交换地址中的值,给eax和ecx赋值是为rep的执行做准备的,stos是将eax中的值赋给edi,rep是执行后面的指令ecx次。

接下来的两步指令忽略,它们是vc编译器添加的调试指令。

因为eax一般是来用作返回值的,所以这里的计算都是跟eax进行计算的,因为直接使用的是return返回,没有涉及到临时变量,所以不会用到缓冲区来存储。

接下来的三步pop,是将之前存储在栈中的元素都恢复到它原来的位置。

此时的堆栈情况就变成了,上面的值还是没有清除的,它们现在已经是垃圾数据的,下一次填充的时候会把它们覆盖掉,这也就造成了可以在其中获取到某些程序不想让人知道的临时变量值。

接下来让esp增加0c0,也就恢复到了提升堆栈之前的位置,此时esp与ebp到了一个位置。

接下来的三步操作依旧可以忽略,它们是vs编译器生成的,用来检测堆栈是否平衡,如果不平衡的话在这里就会产生报错。

最后就是使用pop,将ebp恢复到之前的位置。

最后使用ret回到堆栈中存储的地址,也就是call调用的下一个地址。

但是此时还有个问题,esp并没有回到调用前的位置,所以堆栈还是没有平衡的,如果堆栈不平衡,那在不断的执行的过程中,就会发生堆栈溢出,这里编译器在esp的基础上增加了8。此时堆栈也就恢复到了平衡状态。

3.3.3 VC6.0与VS对比

由于VS调试过程基本与VC一直,故不再赘述。在此总结两次调试:在两次调试中,进入Add()函数前会通过堆栈保存进入之前的EBP(基址指针寄存器),在执行完函数后恢复。

而VS与VC不同之处在于VS是随机基址,VC是固定基址。

即:VC每次程序执行的EBP都一样

而VS每次程序执行的起始EBP不一样!

在Project1的属性页中也表明了这一点:

3.3 Linux&ASLR

在Linux操作系统中,查看、开启、关闭ASLR。(Windows操作系统中也可以进行相关操作,但不建议在Windows中进行)

Linux中查看ASLR是否打开,输出2表示打开:

cat /proc/sys/kernel/randomize_va_space

关闭ASLR,切换至root用户,输入命令:

echo 0 > /proc/sys/kernel/randomize_va_space

开启ASLR,切换至root用户,输入命令:

echo 2 > /proc/sys/kernel/randomize_va_space

3.4 比较有无DEP编译结果差异

基于gcc编译器,开启、关闭数据执行保护(Data Execution Prevention,DEP)和栈保护,利用反编译结果或调试跟踪,分析开启和关闭编译选项前后编译结果的差异。

用于测试的是一段有off by one漏洞的c语言代码

#include <stdio.h>
#include <string.h>
void foo(char* arg);
void bar(char* arg);
void foo(char* arg) {bar(arg); /* [1] */
}
void bar(char* arg) {char buf[256];strcpy(buf, arg); /* [2] */
}
int main(int argc, char *argv[]) {if(strlen(argv[1])>256) { /* [3] */printf("Attempted Buffer Overflown");fflush(stdout);return -1;}foo(argv[1]); /* [4] */return 0;
}

首先是关闭数据执行保护和栈保护后:

(gdb) disassemble main
Dump of assembler code for function main:0x00000000000007a3 <+0>:    push   %rbp0x00000000000007a4 <+1>:  mov    %rsp,%rbp0x00000000000007a7 <+4>: sub    $0x10,%rsp0x00000000000007ab <+8>:    mov    %edi,-0x4(%rbp)0x00000000000007ae <+11>:  mov    %rsi,-0x10(%rbp)0x00000000000007b2 <+15>: mov    -0x10(%rbp),%rax0x00000000000007b6 <+19>: add    $0x8,%rax0x00000000000007ba <+23>:    mov    (%rax),%rax0x00000000000007bd <+26>:  mov    %rax,%rdi0x00000000000007c0 <+29>:    callq  0x620 <strlen@plt>0x00000000000007c5 <+34>:    cmp    $0x100,%rax0x00000000000007cb <+40>:  jbe    0x7ef <main+76>0x00000000000007cd <+42>:   lea    0xc0(%rip),%rdi        # 0x8940x00000000000007d4 <+49>:   callq  0x610 <puts@plt>0x00000000000007d9 <+54>:  mov    0x200830(%rip),%rax        # 0x201010 <stdout@@GLIBC_2.2.5>0x00000000000007e0 <+61>:  mov    %rax,%rdi0x00000000000007e3 <+64>:    callq  0x630 <fflush@plt>0x00000000000007e8 <+69>:    mov    $0xffffffff,%eax0x00000000000007ed <+74>: jmp    0x807 <main+100>0x00000000000007ef <+76>:  mov    -0x10(%rbp),%rax0x00000000000007f3 <+80>: add    $0x8,%rax
---Type <return> to continue, or q <return> to quit---return0x00000000000007f7 <+84>:    mov    (%rax),%rax0x00000000000007fa <+87>:  mov    %rax,%rdi0x00000000000007fd <+90>:    callq  0x75a <foo>0x0000000000000802 <+95>:    mov    $0x0,%eax0x0000000000000807 <+100>:   leaveq 0x0000000000000808 <+101>:    retq
End of assembler dump.
(gdb) disassemble foo
Dump of assembler code for function foo:0x000000000000075a <+0>: push   %rbp0x000000000000075b <+1>:  mov    %rsp,%rbp0x000000000000075e <+4>: sub    $0x10,%rsp0x0000000000000762 <+8>:    mov    %rdi,-0x8(%rbp)0x0000000000000766 <+12>:  mov    -0x8(%rbp),%rax0x000000000000076a <+16>:  mov    %rax,%rdi0x000000000000076d <+19>:    callq  0x775 <bar>0x0000000000000772 <+24>:    nop0x0000000000000773 <+25>: leaveq 0x0000000000000774 <+26>: retq
End of assembler dump.
(gdb) disassemble bar
Dump of assembler code for function bar:0x0000000000000775 <+0>: push   %rbp0x0000000000000776 <+1>:  mov    %rsp,%rbp0x0000000000000779 <+4>: sub    $0x110,%rsp0x0000000000000780 <+11>:  mov    %rdi,-0x108(%rbp)0x0000000000000787 <+18>:    mov    -0x108(%rbp),%rdx0x000000000000078e <+25>:    lea    -0x100(%rbp),%rax0x0000000000000795 <+32>:    mov    %rdx,%rsi0x0000000000000798 <+35>:    mov    %rax,%rdi0x000000000000079b <+38>:    callq  0x600 <strcpy@plt>0x00000000000007a0 <+43>:    nop0x00000000000007a1 <+44>: leaveq 0x00000000000007a2 <+45>: retq
End of assembler dump.

然后是开启数据执行保护和栈保护后:

(gdb) disassemble main
Dump of assembler code for function main:0x0000000000000836 <+0>:    push   %rbp0x0000000000000837 <+1>:  mov    %rsp,%rbp0x000000000000083a <+4>: sub    $0x10,%rsp0x000000000000083e <+8>:    mov    %edi,-0x4(%rbp)0x0000000000000841 <+11>:  mov    %rsi,-0x10(%rbp)0x0000000000000845 <+15>: mov    -0x10(%rbp),%rax0x0000000000000849 <+19>: add    $0x8,%rax0x000000000000084d <+23>:    mov    (%rax),%rax0x0000000000000850 <+26>:  mov    %rax,%rdi0x0000000000000853 <+29>:    callq  0x680 <strlen@plt>0x0000000000000858 <+34>:    cmp    $0x100,%rax0x000000000000085e <+40>:  jbe    0x882 <main+76>0x0000000000000860 <+42>:   lea    0xbd(%rip),%rdi        # 0x9240x0000000000000867 <+49>:   callq  0x670 <puts@plt>0x000000000000086c <+54>:  mov    0x20079d(%rip),%rax        # 0x201010 <stdout@@GLIBC_2.2.5>0x0000000000000873 <+61>:  mov    %rax,%rdi0x0000000000000876 <+64>:    callq  0x6a0 <fflush@plt>0x000000000000087b <+69>:    mov    $0xffffffff,%eax0x0000000000000880 <+74>: jmp    0x89a <main+100>0x0000000000000882 <+76>:  mov    -0x10(%rbp),%rax0x0000000000000886 <+80>: add    $0x8,%rax
---Type <return> to continue, or q <return> to quit---return0x000000000000088a <+84>:    mov    (%rax),%rax0x000000000000088d <+87>:  mov    %rax,%rdi0x0000000000000890 <+90>:    callq  0x7ca <foo>0x0000000000000895 <+95>:    mov    $0x0,%eax0x000000000000089a <+100>:   leaveq 0x000000000000089b <+101>:    retq
End of assembler dump.
(gdb) disassemble foo
Dump of assembler code for function foo:0x00000000000007ca <+0>: push   %rbp0x00000000000007cb <+1>:  mov    %rsp,%rbp0x00000000000007ce <+4>: sub    $0x10,%rsp0x00000000000007d2 <+8>:    mov    %rdi,-0x8(%rbp)0x00000000000007d6 <+12>:  mov    -0x8(%rbp),%rax0x00000000000007da <+16>:  mov    %rax,%rdi0x00000000000007dd <+19>:    callq  0x7e5 <bar>0x00000000000007e2 <+24>:    nop0x00000000000007e3 <+25>: leaveq 0x00000000000007e4 <+26>: retq
End of assembler dump.
(gdb) disassemble bar
Dump of assembler code for function bar:0x00000000000007e5 <+0>: push   %rbp0x00000000000007e6 <+1>:  mov    %rsp,%rbp0x00000000000007e9 <+4>: sub    $0x120,%rsp0x00000000000007f0 <+11>:  mov    %rdi,-0x118(%rbp)0x00000000000007f7 <+18>:    mov    %fs:0x28,%rax0x0000000000000800 <+27>:    mov    %rax,-0x8(%rbp)0x0000000000000804 <+31>:  xor    %eax,%eax0x0000000000000806 <+33>:    mov    -0x118(%rbp),%rdx0x000000000000080d <+40>:    lea    -0x110(%rbp),%rax0x0000000000000814 <+47>:    mov    %rdx,%rsi0x0000000000000817 <+50>:    mov    %rax,%rdi0x000000000000081a <+53>:    callq  0x660 <strcpy@plt>0x000000000000081f <+58>:    nop0x0000000000000820 <+59>: mov    -0x8(%rbp),%rax0x0000000000000824 <+63>:  xor    %fs:0x28,%rax0x000000000000082d <+72>:    je     0x834 <bar+79>0x000000000000082f <+74>:    callq  0x690 <__stack_chk_fail@plt>0x0000000000000834 <+79>:  leaveq 0x0000000000000835 <+80>: retq
End of assembler dump.

可以看出二者的main函数和foo函数编译结果都是一样的,最明显的差别在于bar函数,即可能发生off by one溢出的地方。目标缓冲区长度为256,因此长度为256字节的源字符串可能导致任意代码执行。

我们可以看到gcc生成了一些附加代码,通过对数组大小的判断替换strcpy函数,达到防止缓冲区溢出的作用。

四、总结

操作系统提供了许多安全机制来尝试降低或阻止缓冲区溢出攻击带来的安全风险,包括DEP、ASLR等。

首先是栈保护,栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。

gcc在4.2版本中添加了-fstack-protector和-fstack-protector-all编译参数以支持栈保护功能,4.9新增了-fstack-protector-strong编译参数让保护的范围更广。

然后是DEP(Data Execution Prevention,数据执行保护),DEP的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

还有ASLR(address space layout randomization,内存地址随机化机制),一种针对缓冲区溢出的 安全保护技术,通过对堆、 栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。有以下三种情况

0 - 表示关闭进程地址空间随机化。

1 - 表示将mmap的基址,stack和vdso页面随机化。

2 - 表示在1的基础上增加栈(heap)的随机化。

ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。

参考链接:

https://www.cnblogs.com/zhang293/p/9046651.html

https://www.anquanke.com/post/id/85540

https://blog.csdn.net/shui_zhi_lian/article/details/46473103

https://blog.csdn.net/li2327234939/article/details/50878677

https://wenwen.sogou.com/z/q761064173.htm

https://www.cnblogs.com/findumars/p/10803259.html

https://blog.csdn.net/hyman_c/article/details/52679205

https://blog.csdn.net/GMingZhou/article/details/78118582

https://mp.weixin.qq.com/s/29kzCbWRlTC4epqZlBOXHQ

https://www.zhihu.com/question/41628882/answer/298607469

https://www.cnblogs.com/yhjoker/p/7533438.html

https://bbs.pediy.com/thread-216954.htm

https://www.jianshu.com/p/71dc588d6b20

gdb 查看是否 栈溢出_ASLR、DEP与栈保护(HFUT-ZRB#x27;s Task)相关推荐

  1. gdb 查看是否 栈溢出_栈溢出基础

    一. 基础知识什么是缓冲区溢出在深入探讨技术之前, 让我们先了解一下缓冲区溢出的实际内容.想象一个非常简单的程序, 要求你输入你的用户名, 然后返回到它在做什么.从视觉上看, 如下所示注意到括号之间的 ...

  2. DEP栈保护ASLR 开启关闭

    判断ASLR是否打开,输出2表示打开 cat /proc/sys/kernel/randomize_va_space  关闭ASLR,切换至root用户,输入命令 echo 0 > /proc/ ...

  3. gdb查看内存地址和栈中的值

    gdb查看指定地址的内存地址的值:examine 简写 x-----使用gdb> help x 来查看使用方式 x/ (n,f,u为可选参数) n: 需要显示的内存单元个数,也就是从当前地址向后 ...

  4. gdb 查看,执行汇编代码

    用gdb 查看汇编代码, 采用disassemble 和 x 命令. nexti, stepi 可以单步指令执行 如下例: -------------------------------------- ...

  5. gdb查看空指针 linux_资深程序员总结:分析Linux进程的6个方法,全都告诉你!

    文章来源:https://mp.weixin.qq.com/s/3u5XH8NGj3bF3Gn81N40gA 作者:LemonCoder 操作系统「进程」是学计算机都要接触的基本概念,抛开那些纯理论的 ...

  6. x/nfu-用gdb查看内存

    用gdb查看内存 2007-12-08 12:43 用gdb查看内存 格式: x /nfu <addr> 说明 x 是 examine 的缩写 n表示要显示的内存单元的个数 f表示显示方式 ...

  7. Linux系统和程序中的DEP和ASLR保护机制

    2014年,OpenSSL加密库中的一个缓冲区溢出漏洞被公开.该缺陷被称为"心脏出血".它使受欢迎的在线服务和软件平台的数亿用户暴露于易受攻击的OpenSSL软件版本中.于是操作系 ...

  8. 计算机系统保护怎么打开,Win7系统开启DEP数据执行保护的具体方法

    大部分用户都不知道数据执行保护 (DEP)有什么作用, DEP数据执行保护有助于防止我们的计算机遭受病毒的侵害,也有助于防止其他安全威胁危害我们的计算机.Win7专业版系统默认没有开启DEP数据执行保 ...

  9. 9.1 DEP机制的保护原理

    溢出攻击的根源在于现代计算机对数据和代码没有明确区分,就目前来看重新去设计计算机体系结构基本上不可能,只能靠向前兼容的修补来减少溢出带来的损害,DEP(数据执行保护,Data Execution Pr ...

最新文章

  1. Excel VBA林木冠幅、分枝胸径字符串的拆解
  2. awstats的安装和配置
  3. 深入理解JS中this关键字
  4. 三、链表(Linked List)(原理)
  5. Semaphore 源码分析
  6. 1.10.Flink DataStreamAPI(API的抽象级别、Data Sources、connectors、Source容错性保证、Sink容错性保证、自定义sink、partition等)
  7. C#多线程使用进度条
  8. whmcs精仿雨云ModuleSky主题模板
  9. android检查可用网络的代码
  10. Centos6.5 安装Vim7.4
  11. (day 41 - 二分查找) 剑指 Offer 53 - I. 在排序数组中查找数字 I
  12. Acwing - 最长公共子序列
  13. TensorFlow by Google过拟合优化 Machine Learning Foundations: Ep #7 - Image augmentation and overfitting
  14. R语言基础期末大作业
  15. Android 7.1 PackageInstaller(应用安装器)增加自动点击安装
  16. 互联网晚报 | 潮州特斯拉事故前视频公布;苹果为iPhone 14提供同机维修;文旅部:跨省旅游经营活动不再与风险区实施联动管理...
  17. C++对我来说简直就是星辰大海,为了避免翻船,我选择从小河沟出发
  18. 云计算中存储基础知识
  19. 多分支条件组合实例:身体质量指数BIM
  20. mysql加入安装策略_MySQL——安装

热门文章

  1. GX works2 中的块的创建与使用方法
  2. html5新增表单控件和表单属性
  3. Java学习笔记17(面向对象十:综合案例)
  4. 疯狂VirtualBox实战讲学录 以及 virtualbox完全学习手册 之我见
  5. Soap、Http、TCP/IP 三个基本的通讯协议有什么区别?
  6. 学习笔记 - 002
  7. mysql表级锁和行级锁_MySQL表级锁和行级锁
  8. Python+matplotlib一笔绘制红色五角星
  9. Python在应用层实现UDP协议的可靠传输
  10. 2000页Python系列PPT分享九:(GUI编程)(122页)