一种基于关键地址动态保护的栈溢出自动防御方法与流程

文档序号:34243043发布日期:2023-05-25 01:10阅读:67来源:国知局
一种基于关键地址动态保护的栈溢出自动防御方法与流程

本发明涉及软件安全,尤其涉及一种基于关键地址动态保护的栈溢出自动防御方法。


背景技术:

1、栈是一种非常重要的数据结构,在程序运行时用于保存函数的传入参数、局部变量以及函数的返回地址;在函数调用执行时,如果不对传入的参数或者局部变量进行长度校验,这些变量的值可能会覆盖函数的返回地址,导致程序崩溃,如果传入的参数是精心构造的shellcode,程序还可能出现rce等严重的漏洞;现有技术对防御栈溢出的方式主要有:1、防止返回地址被篡改,典型的有__stack_chk_guard;2、让栈上的数据不允许被当成代码执行,典型的有dep,用于防御return2shellcode攻击;3、防止函数返回时跳转到其它可执行的代码,比如libc等库函数,典型的有aslr。

2、对于__stack_chk_guard的方式:编译器在编译代码、生成二进制机器码的时候,会让esp在申请函数的栈空间时多申请4~8字节的空间(业界通常称之为__stack_chk_guard或canary)。函数执行时,会随机生成4~8字节的随机数存放在这个空间。待函数执行完毕,即将返回时,再检查上述随机数的值是否改变。如果更改,说明局部变量空间在赋值的时候已经越界,发生了栈溢出,需要终止当前程序的执行,并抛出异常,整个栈空间示意图如图1所示。但是这种方式需要编译器在编译代码的时候对所有函数在头尾进行静态插桩,会增加函数执行的代码,降低程序整体的执行效率,甚至可能在短时间内耗光操作系统分配的栈空间,在大量函数嵌套调用、递归的场景下会更甚;而且每次函数调用都需要在栈上额外分配4~8字节的空间,额外耗费栈空间,只能防御用户态的程序,对函数内部局部变量赋值时,任然可以绕过canary随机数所存放的地址,只覆盖函数返回值所在的内存空间,也就是ebp+4所在的空间,致使__stack_chk_guard的防御机制完全失效。

3、对于dep的方式:如图2所示,其为了防止栈溢出被恶意利用,将栈内存的属性设置为不可执行,这样即使人为将shellcode通过局部变量赋值的方式写入栈空间,在执行ret语句后成功跳转到了shellcode的起始位置,但这段shellcode仍然会被cpu认为是数据而不是代码,不予执行,从而杜绝了栈上的rce漏洞。这种方式通过更改栈内存的属性为不可执行,让栈上的shellcode无法执行,确实达到了return2shellcode的目的。但其并未保护函数返回地址不被篡改,所以仍然能够通过局部变量改变函数的返回地址,跳转到诸如libc等库函数处运行,达到return2libc的目的,所以dep并未从根本上解决栈溢出的问题。

4、对于aslr的方式:如图3所示,通过对内核和用户程序的地址做随机分配,致使代码段每次加载的虚拟地址都不同,代码段内部诸如libc等库函数的入口地址也会改变,部分增加了攻击者准确获取到代码段、库函数基址和偏移位置的成本。虽说每次加载时都会随机分配虚拟地址空间,但这也仅仅改变了代码段、库函数加载的基址,而libc内部函数相对基址的偏移并未改变,如果能获取到某个函数绝对的虚拟地址,就可以通过绝对地址减去偏移得到libc函数库的基址,进而通过基址+偏移的方式得到其他库函数的入口地址。而函数的绝对虚拟地址是可以通过got表获取的获得目标函数的绝对地址后,直接写入(局部变量n+12)的地址,同样可以触发栈溢出漏洞,达到return2libc的目的。

5、需要说明的是,在上述背景技术部分公开的信息只用于加强对本公开的背景的理解,因此可以包括不构成对本领域普通技术人员已知的现有技术的信息。


技术实现思路

1、本发明的目的在于克服现有技术的缺点,提供了一种基于关键地址动态保护的栈溢出自动防御方法,解决了现有防御栈溢出技术存在的不足。

2、本发明的目的通过以下技术方案来实现:一种基于关键地址动态保护的栈溢出自动防御方法,所述栈溢出自动防御方法包括:

3、callee函数执行完毕后,执行第一指令使得在callee函数内部将原caller的ebp寄存器植入栈保护,再执行第二指令让callee的ebp寄存器值指向栈底,使得callee函数内部执行时正确寻址传入参数和局部变量,并在第二指令的下一条指令处插桩防止函数的返回地址被后续执行的局部变量赋值代码篡改,并通过内存管理器进行检测;

4、执行第三指令恢复caller函数的栈空间,保证caller函数在栈内对局部变量的寻址,然后在返回指令处插桩,将存放返回地址的栈内存属性改为第二状态后,再执行返回指令跳转回caller函数继续执行,保证callee返回caller函数的顺利续接。

5、所述在第二指令的下一条指令处插桩防止函数的返回地址被后续执行的局部变量赋值代码篡改,并通过内存管理器进行检测包括:

6、在第二指令的下一条指令处插桩,将ebp+4处的内存属性改为第一状态,然后跳转回原函数继续执行,一旦有局部变量赋值的指令对ebp+4的内存块进行修改时,内存管理器立即检测到该非法操作,并发出中断通知cpu处理异常,停止整个原程序执行,使得后续任何局部变量的赋值指令都无法更改该内存块的内存地址数值,保护callee执行完毕后返回地址的准确性。

7、所述第一状态为只读状态,第二状态为可读可写状态,将存放返回地址的占内存数据改为可读可写状态后再释放,避免其它函数正常使用此处占内存时因为不可写而报错。

8、所述栈溢出自动防御方法还包括插桩位置自动化寻址步骤,所述插桩位置自动化寻址步骤包括:

9、在用户态或者内核态中获取需要从用户接收数据,并且与用户频繁交互的交互函数,通过解析文件头的方式获取到交互函数的入口地址和函数名;

10、计算获取到交互函数入口地址相对libc库函数基址的偏移,并从偏移开始依序检索,直到查找到第一个第二指令为止,计算插桩需要的绝对虚拟地址,并在第二指令的下一个字节的位置进行动态插桩。

11、所述计算插桩需要的绝对虚拟地址具体包括以下内容:

12、通过指令检索交互函数入口地址相对于libc库函数的偏移offset,通过top指令随机选取一个用户态进程的pid,并查看该进程中libc库函数在虚拟内存的地址映射,得到libc库函数的基址,通过偏移offset和libc库函数基址得到交互函数在内存中的绝对虚拟地址。

13、所述插桩的框架选择包括:

14、对于linux 3.18以上和android 9.0以上的高版本操作系统,内核默认自带ebpf框架,直接用于关键函数的首尾插桩做功能扩展;

15、对于低版本的linux/android操作系统,使用内核默认自带的kprobe/uprobe对关键函数的首尾插桩做功能扩展;

16、对于windows和ios的操作系统,使用frida成熟的hook框架关键函数的首尾插桩做功能扩展。

17、本发明具有以下优点:一种基于关键地址动态保护的栈溢出自动防御方法,限制了函数返回地址的栈内存属性为只读,任何攻击方法都无法篡改函数返回地址,成功防御return2shellcode的攻击方式,且在函数结束后执行retn指令时,只会跳转到既定的caller函数地址,成功防御return2libc的攻击方式。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1