基于二级片内硬件堆栈的后向CFI 验证方法研究,第二章

随着计算机技术的发展,针对计算机系统的恶意攻击越来越多,造成了巨大的经济损失。面向返回导向编程等恶意攻击方式通过修改堆栈中程序返回地址劫持控制流,达到恶意攻击的目的。后向控制流完整性即返回地址的完整性验证,是一种保护函数返回地址的有效手段。
本文提出了一种基于二级硬件堆栈的后向程序控制流完整性验证方法,并在国产玄铁E906 RISC-V处理器中进行了实现和分析。基于现有针对返回地址的攻击方式和后向CFI的实现方法,建立了恶意攻击威胁模型,确定了设计的安全边界;设计了二级硬件堆栈结构,可通过专用片上硬件缓冲区自动暂存新入栈返回地址,并将缓存区中旧返回地址送入传统内存堆栈;提出了二级硬件堆栈的两种具体实现方法,即延迟验证和批处理验证,分别实现对内存堆栈中返回地址的细粒度逐个验证,和基于消息验证码的多返回地址的批处理验证;在国产玄铁E906 RISC-V处理器中分别实现了两种验证方法,采用公认的基准测试程序分别对两种实现进行功能仿真和FPGA验证,并针对不同缓冲区尺寸进行了安全性和系统开销分析。
实验结果表明,本文提出的二级片内硬件堆栈能够实现对后向程序控制流的监控和验证;在返回地址缓冲区大小为2个机器字时,延迟验证和批处理验证带来的性能开销分别不高于2.94%和4.20%;返回地址缓冲区大小为4时,延迟验证和批处理验证带来的性能开销均不高于0.72%;通过Xilinx Vivado工具评估延迟验证和批处理验证实现在返回地址缓冲区大小为4时分别带来了4.7%和4.1%的硬件资源开销。

系统源代码 QQ 3270516346 wx wwwicer

第2章 RISC-V程序执行中后向CFI实现

2.1 RISC-V中子函数返回地址的处理

2.1.1 RISC-V指令集

RISC-V是一种新兴的开源指令集架构,2010年由加州大学伯克利分校首次发布。它的出现是建立在现有体系结构(如 x86、ARM、MIPS 等)经过长期发展所暴露出的种种问题之上,如缺乏开放性、版本迭代积累了许多历史遗留问题等。RISC-V 的出现和其迅速发展是必然的,顺应现代信息系统设计需求和体系结构发展趋势[10]。
RISC-V的指令集的组织方式采用模块化的方法,主要包括基础指令集以及若干可选的扩展指令集。RISC-V 的基础指令集是能够为操作系统、编译器、汇编器等提供实现必要功能的最小指令的集合,RISC-V共有五种基础的指令集,其中RV32I和RV64I是最主要的两种,分别对应32位环境和64位环境。RV32I和RV64I都有32个通用整数寄存器,具有规整的指令编码、简洁的存储器访问指令以及高效的分支跳转指令。同时为了能够在嵌入式等领域使用RISC-V时减少内存的占用,RISC-V还定义了可选的16位压缩指令集,并且每一个压缩指令都可以找到其对应的非压缩指令,在减少代码体积的同时极大地减少了编译的负担以及指令集的复杂度[11]。这些特点使得RISC-V具有优于其他架构的特点并能根据需要应用于各个领域。2.1.2小结将以32位RISC-V处理器为例,简要概括RISC-V在执行程序时对子函数的返回地址如何处理。

2.1.2 子函数返回地址的处理

在SoC的系统存储器中都有一块区域为堆栈,堆栈只能在一端( 称为栈顶)进行读取和写入,主要用于暂存中间数据和地址,保存现场数据。RISC-V中一般使用x2通用寄存器作为堆栈栈顶指针。
在程序进入子函数时会调用“jal”等转移类指令使程序跳转到子函数,同时将下一条指令的地址作为返回地址保存在相应的寄存器中,RISC-V中默认将返回地址保存在x1通用寄存器中。在进入到子函数后首先进行现场保护,使用存储器存储指令将返回地址等保存到存储器的堆栈区域。在子函数将要返回时要进行恢复现场,通过调用存储器读取指令将堆栈中的返回地址加载到x1等通用寄存器中,最后调用“ret”等返回指令将返回地址赋值给PC程序计数器使处理器继续在主函数中运行。在保存现场和恢复现场中对返回地址的操作是由编译器编译生成指令完成的,使用高级语言编写程序时直接调用子函数即可。
如下是一个简单的C语言程序:
在这里插入图片描述
图2.1 C语言中printf调用程序

该程序编译后的汇编程序中,调用“printf”子函数的指令为:

                    	jal	x1,21  <printf>

该指令使程序跳转到“printf”函数并将返回地址保存到x1寄存器中。在进入“printf”函数后首先进行现场保护:
在这里插入图片描述
图2.2 printf函数保护现场汇编程序

printf函数在现场保护时通过“sw x1,28(x2)”指令将返回地址保存到堆栈。在函数返回时的汇编程序如下:
在这里插入图片描述
图2.3 printf函数恢复现场汇编程序

在恢复现场时通过调用“lw x1,28(x2)”指令将返回地址加载到x1寄存器中,最后调用ret指令将x1寄存器的值赋给PC,返回主函数。

2.2 面向返回编程攻击

面向返回编程攻击(Return-oriented programming,ROP)可以绕过已经存在的大多数通用防御措施进行控制流攻击,是一种高级的内存攻击技术。ROP通过改变函数的返回地址进行攻击,攻击者不需要注入其他的恶意代码。
在子函数返回时,返回地址从堆栈中弹出,处理器转到返回地址所指的地址执行指令,如果攻击者能够利用漏洞篡改堆栈中的返回地址,那么程序将返回到攻击者修改的返回地址处的指令。ROP攻击就是利用这种原理进行攻,攻击者从内存中找到众多“配件”(一小段以返回地址结尾的汇编代码),使用这些配件的返回地址重写堆栈中原有的返回地址。当第一个配件执行结束时,下一个相应的配件又会继续执行,这些配件按照攻击者的意图依次执行组成配件链,从而完成恶意攻击。这种攻击是图灵完备的,它可以在当前的权限内执行任意操作[11]。
图2.4是面向返回编程攻击的一个实例,攻击者的目标是调用系统调用指令“int 80”。攻击者通过分析二进制程序找到相应的配件gadteg1、gadget2、gadteg3,在程序运行时,利用程序存在的漏洞将堆栈中的返回地址替换成配件的地址add1、add2、add3、add4,程序就会依次运行相应的配件以达到攻击者的目的。程序运行的流程为:
(1)当一个子函数返回时,如果此时ESP指向地址add2,那么gadget2将会加载堆栈中的数据并且程序将会被执行,此时ESP指向addr3.

(2)当gadget2执行最后一条指令ret后,程序跳转到gadget3,加载堆栈中的数据执行gadget3中的程序,ESP移动到addr1处。
(3)当gadget3执行最后一条指令ret时程序跳转到gadget1,加载堆栈中的数据并执行gadget1中的程序,ESP移动到addr4处。
(4)当gadget1执行最后一条指令ret后程序跳转到gadet4处,成功执行系统调用指令“int 80”,完成恶意攻击。

在这里插入图片描述
图2.4 ROP攻击实例

2.3 基于消息验证码的返回地址保护

消息认证码,又称MAC(Message Authentication Code,MAC),是一种认证技术,他是利用密钥以及相应的加解密算法生成一个固定长度的短数据块,并将该数据块附加在消息之后[12]。通过消息认证码,可以检测消息在传递的过程中消息是否被修改以及消息的完整性,确保接收方接收到的消息与发送方发送的消息一致。
如图2.5所示,在使用消息认证码机制传递消息时,通信双方共享密钥K并且使用相同的加密算法。在发送方发送消息时通过相应的MAC算法计算MAC并将MAC同消息一同发送出去,接收方接收到消息以后使用相通的密钥和MAC算法计算消息的MAC码。由于只有通信双方知道密钥,所以只有通信双方才能计算出正确的MAC码,所以当接收方计算出的MAC码与发送方的MAC码相同时,接收方可以相信消息没有被修改。
基于消息认证码保护函数的返回地址已经有许多实现,例如CCFI[3]、RAGuard[4]、ARM指针认证[14]。在程序进入子函数后会将返回地址压入堆栈,此时生成该返回地址的MAC码并将MAC码一起保存到堆栈或者相应的位置,在返回地址被使用前重新生成相应的MAC码并进行验证,如果MAC值不符合则返回地址被篡改。该机制在返回地址被篡改时会产生异常等使恶意程序无法执行,从而保证了系统的安全性。但是由于计算MAC需要较长时间,会花费巨大的性能开销。

在这里插入图片描述
图2.5 消息认证码原理

2.4 本章小结

本章主要分析了攻击者常用的面向返回编程攻击方法,以及基于消息验证码对返回地址进行保护的策略。首先分析了RISC-V指令集,简要介绍了RISC-V指令集的优点,对RSIC-V中子函数返回地址的调用和返回过程进行了详细分析。之后介绍了面向返回编程攻击这种攻击方式,攻击者最常用的劫持程序后向控制流的方法。最后,分析了如今最常用的也是安全性相对较好的程序后向CFI保护方案,基于消息验证码保护程序中子函数的返回地址。

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-30 01:40:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-30 01:40:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-30 01:40:04       87 阅读
  4. Python语言-面向对象

    2024-03-30 01:40:04       96 阅读

热门阅读

  1. 计算机网络(03)

    2024-03-30 01:40:04       47 阅读
  2. 多次面对无法解决的leetcode题目

    2024-03-30 01:40:04       41 阅读
  3. 跨域问题详解(vue工程中的解决办法)

    2024-03-30 01:40:04       46 阅读
  4. MurmurHash3

    2024-03-30 01:40:04       45 阅读
  5. Spring和SpringBoot的区别

    2024-03-30 01:40:04       49 阅读
  6. 11、Spring CLI中Action指南

    2024-03-30 01:40:04       42 阅读
  7. yarn的安装和使用

    2024-03-30 01:40:04       48 阅读