APP下载

ARMv8 ROP shellcode复杂控制流构造

2019-05-16赵利军董莎莎

计算机应用与软件 2019年5期
关键词:寄存器指令架构

赵利军 董莎莎

(陆军工程大学军事理论创新与作战实验中心 江苏 徐州 221000)

0 引 言

ARM架构处理器在嵌入式领域占有绝对的领先优势,其市场占有率逐年保持持续增长状态。2011年ARM公司发布新一代处理器架构-ARMv8[1]。ARMv8处理器64位处理能力进一步扩大了其在高性能低功耗领域的地位。ARMv8新型体系架构即将在网络设备、智能移动设备和高端服务器等领域得以大规模部署。随着ARMv8架构的持续发展,其上的安全问题也必将越来越受到研究者关注。2010年Davi等[2]在前人研究基础上提出了ARM架构上的JOP(jump-oriented programming)攻击。ARM架构上的JOP攻击使用以BLX Rm指令结尾的gadget。

2014年,南京大学的邢骁等[5]在前人的研究基础之上提出了一种新的攻击技术——自动构造增强型ROP攻击(BIOP)。该技术使用JMP指令或CALL指令结尾的短指令序列构造攻击。相比于以前的工作,BIOP不引入新的特征,能有效避免针对ROP攻击和JOP攻击的防御技术。同年,南京大学的Chao Yang等[6]提出了一种基于长指令序列的ROP攻击技术(A-R攻击),成功地避开了Ping Chen的检测方法。2015年杨超[7]在此基础上提出了一种自动化ROP攻击工具,该工具可以自动填充与连接方案,保证图灵完备的情况下降低其集合之间的依赖性,保证修正后的gadget可以满足自动化构建的需要。2015年林志添[9]提出了一种不完全依赖栈的ROP攻击技术,该方法将gadgets地址、运算数据存放在堆中,通过一些类似于KeyFrame整形溢出的漏洞方式劫持程序流来运行gadgets从而完成恶意计算的攻击技术。2018年,彭建山等[12]针对可用gadget数量少、实现难度大等问题,提出了一种基于多路径分发的ROP框架构造方法。基于3种类型的gadget模块构造了一个gadget循环执行的框架,框架内可以使用丰富的常规gadget,从而形成一条完整、高效的ROP攻击链,并通过实验证明不仅能够完成复杂的ROP功能,而且特征足够小,能够绕过主流ROP检测工具的检测。

ROP构造功能代码的难点是实现条件转移逻辑。通过深入分析条件转移机器指令的执行上下文发现,对这些指令的传统认知存在一定的局限性。事实上,在已有代码中存在少量的条件转移指令,它们的两个分支的开始部分都是可复用的代码片段(称为gadgets),而且这两个gadgets会从不同的内存单元中取得下一个gadget的地址。因此,以这些条件转移指令开始的代码片段可以帮助ROP实现条件转移逻辑。把这种代码片段称为if-gadget。袁平海等[10]通过实验证明在Linux和Windows系统if-gadget普遍存在,即使在代码量很小的日常可执行程序中也存在,并且引入if-gadget后,构造复杂的ROP shellcode代码要比用传统方法容易得多。

ARMv7指令集中的每条指令都具有条件执行功能的特殊性,这使得ARMv7架构的条件跳转gadget的构造非常简单。图1显示了相等条件执行{if(v1==v2)·:jump T1,else jump T2}的gadget实例,其中gadget_4就是一个典型的if-gadget。gadget_3的CMP指令可以通过比较R3和R4寄存器中值进行标志位的改变。然后从栈中将gadget_4的首地址加载到寄存器LR,程序跳转到gadget_4执行。gadget_4的第一条指令BX.eq r5为条件执行指令,POP{r2,lr}指令将栈中的gadget_5的首地址加载到LR寄存器,然后程序跳转到gadget_5继续执行,成功地实现了跳转。

图1 ARMv7架构条件跳转gadget构造实例

从图1中可以看出,ARMv7架构下通过条件跳转gadget(gadget_4)很好地实现了条件跳转。然而ARMv8是ARM公司最新发布的首款支持64位指令集的处理器架构,其引入了一个全新的64位指令集——A64。与ARMv7架构相比,其在指令集、地址长度、通用寄存器和工作模式等方面存在较大区别,简要对比如表1所示。

表1 ARMv8架构与ARMv7架构对比表

通过对ARMv8架构指令系统的学习总结[1-5],发现总共有5类跳转指令可以影响程序的控制流。其可以分成三大类:条件跳转分支指令、非条件直接跳转分支指令和非条件间接跳转分支指令。AArch64中条件跳转指令的汇编格式如下:B.cond label,其编码格式如图2所示,其中imm19为跳转目标地址的偏移量。

图2 AArch64条件跳转指令编码格式

从图2中可以看出,ARMv8架构条件接跳转指令的目标地址已经被编码到指令格式中,其目的地址无法再进行修改。因此,ARMv7架构基于间接条件跳转指令构造条件跳转gadget的方法在ARMv8架构中已经不再适用,尽管通过多个gadget的重复使用也可达成上述功能,但将浪费大量的内存空间。基于上述问题,本文提出了ARMv8架构基于CMP指令和CSEL指令构造if-gadget方法,解决了ARMv8架构中缺失if-gadget的问题。最后通过实验证明了本文方法的可行性,与传统的方法相比,本文的方法节省更大的内存开支,提高了执行效率。

1 ARMv8条件跳转gadget的构造方法

ARMv7架构基于间接条件跳转指令构造条件跳转gadget的方法在ARMv8架构中已经不再适用。通过对ARMv8指令集的分析,本文提出了一种利用CSEL指令gadget和CMP指令gadget构造ARMv8 ROP shellcode复杂控制流的方法。实现过程如下:

Step1通过算术或逻辑运算来设置相应的标志位。例如,使用CMP命令来判断两个数是否相等,如果两个数相等ZF为1,否则为0。

Step2CSEL指令可根据标志位来选择相应的源寄存器对目的寄存器进行赋值。例如csel x0,x1,x2,ne中,若ZF为0,x1赋给x0;若ZF为1,x2赋给x0。若x2和x1中预置为应转向的相应目标地址,通过下一步可实现相应的条件跳转。

Step3Br X0指令实现跳转。

下面的例子要实现:比较两个64位数V1和V2,相等跳转到LABEL1;不等跳转到LABEL2。其对等的代码逻辑如下:

if (V1==V2)

jump LABEL1;

else

jump LABEL2

该条件跳转控制流gadget总共包含四个gadget,gadget(9)将V1和V2两个操作数读取到寄存器X3和X4中;gadget(10)将LABEL1和LABEL2的地址分别赋给寄存器X0和X1;gadget(11)完成两个操作数X3和X4的比较,如果不相等X0中为LABEL2的地址,否则为LABEL1的地址;gadget(12)实现相应的条件跳转,若V1等于V2,转去执行LABEL1;不等就执行LABEL2。

工作原理如图3所示。首先第一个gadget从当前的栈顶读取两个常数v1和v2,存储到寄存器X3和X4中,然后SP加上0x30,这时栈顶存储的是第2个gadget的首地址。当第1个gadget执行完毕后,会将第2个gadget的首地址读取到X30寄存器中,这时程序将会跳转到第2个gadget处执行,对应图中的1、2、3步。第2个gadget完成和第1个gadget相似的功能,从当前栈顶读取目标地址存储到X0和X1寄存器中,然后程序跳转到第3个gadget执行,对应图中的4、5、6步。第3个gadget对常数v1和v2比较,如果不相等,则目标地址为X1寄存器中的地址,否则目标地址等于X0寄存器中的地址,程序跳转到第4个gadget执行,对应图中的7、8、9步。现在已经将目标地址存储到了寄存器X0中,第4个gadget用br x0指令实现跳转。

图3 条件控制流gadget构造方法

上面的4个gadget完成了相等条件下的跳转,其他类型的条件跳转,如小于、大于、小于等于、大于等于均可使用上述规则进行构造,只需将第3个gadget中的csel指令中的条件域改为相应的条件即可。有了条件跳转,我们就可以实现有限的循环操作。

2 基于if-gadget的复杂控制流实现机制

大部分的shellcode都会涉及到循环结构,循环结构保证了原始shellcode到生成的ARMv8 ROP shellcode间的控制流语义的一致性。虽然通过研究ROP的工作原理可以看出gadget的执行流程是通过控制结构来进行控制的。即使没有if-gadget,可以通过合理地安排控制结构来控制gadget的执行流程,但是这种方法存在一个重大的缺点,它需要多次重复使用相同的数据,这将造成内存空间的极度浪费,而基于if-gadget的构造方法却可以避免这个问题。

if-gadget是循环结构的基础,本文将会基于ARMv8 if-gadget给出ARMv8 ROP shellcode中循环结构的构造方法。由于循环体需要多次使用相同的数据,所以必须寻找一个gadget对SP指针进行调整以致gadget链可以多次使用同一块数据。本文使用下面的3个gadget来构建ARMv8 ROP shellcode中的循环结构:

0x7fb7f86240EB0A009Fcmp x4,x10

0x7fb7f86244 9A811042 csel x2, x2, x1, ne

0x7fb7f86248 A8C17BFD ldp x29,x30,[sp],#0x10

0x7fb7f8624c D65F03C0 ret

gadget(13)

0x7fb7f2caf4 D10043BF sub sp,x29,#0x10

0x7fb7f2caf8 A9417BFD ldp x29,x30,[sp,#0x10]

0x7fb7f2cafc 910083FF add sp,sp,#0x20

0x7fb7f2cb00 D65F03C0 ret

gadget(14)

0x7fb7f53458 D61F0040 br x2

gadget(15)

其实现原理如图4所示。当循环体执行完核心功能后跳转到gadget(13)执行。gadget(13)、gadget(14)和gadget(15)为ARMv8架构基于跳转跳转gadget的ROP shellcode中的循环结构的构造方法。gadget(13)中的第一条指令”cmp x4,x10”通过比较X1寄存器和X10寄存器的大小影响相应的标志位,第二条指令”csel x2,x2,x1,ne”根据标志位设置寄存器X2的值,如果X4中的值不等于X10寄存器中的值,寄存器X2中保存循环体中第一个gadget的首地址。gadget(14)用于实现栈指针的调整,第一条指令将X29寄存器的值赋值给SP,而X29寄存器中的值是通过gadget(13)中的倒数第二条指令进行设置的,为了可以准确地使SP指向循环体指向的数据结构,必须准确安排X29寄存器中的值。本文中gadget(14)执行完毕后,栈指针位于SP1位置,而循环体的数据的开始地址位于SP3位置,通过对gadget(14)的分析,gadget(13)应将X29寄存器中的值设置为SP2+0x10所得的值,这样当gadget(14)执行完毕后,栈指针将位于SP3位置。如果条件成立,gadget(15)将会使程序跳转到循环体继续执行,至此实现了ARMv8 ROP shellcode中循环结构。

图4 ARMv8 ROP shellcode中循环结构的实现原理

3 实验结果分析与测试

本节将通过完成∑i的运算实例证明ARMv8架构基于CMP指令和CSEL指令构造的if-gadget方法完成复杂ARMv8 ROP shellcode的可行性。并通过实验证明与传统方法相比,本文的方法节省了大量的内存空间。

3.1 gadget链

本例gadget链所用的7个gadget来自libc.so.6或ld-linux-aarch64.so.1库文件。gadget(16)用于从内存加载数据到寄存器X10;gadget(2)从内存中连续读取4个数据依次放入寄存器X1、X2、X3和X4;gadget(17)将X3和X4相加,结果保存到寄存器X3中;gadget(18)完成X4寄存器的加1操作;gadget(13)和gadget(14)用于实现循环,gadget(13)中的第一条指令”cmp x4,x10”通过比较X1寄存器和X10寄存器的大小影响相应的标志位;第二条指令”csel x2,x2,x1,ne”根据标志位设置寄存器X2的值,如果X4中的值不等于X10寄存器中的值,寄存器X2中保存gadget(17)的首地址,如果X4中的值等于X10寄存器中的值,寄存器X2中保存gadget(14)的首地址;第三条指令“ldp x29,x30,[sp],#0x10”将从gadget的CS中加载gadget(14)函数的入口地址到X30中,最后的RET指令将转去执行gadget(17);gadget(14)用于实现栈指针的调整,第一条指令将X29寄存器的值赋值给SP,第二条指令从内存SP+0x10的位置读取两个数据放入寄存器X29和X30,之后使用RET指令跳转待gadget(15)执行;gadget(15)实现跳转。

0x7fb7f4a5c4F84087EAldr x10,[sp],#8

0x7fb7f4a5c8 F84087FE ldr x30,[sp],#8

0x7fb7f4a5cc D65F03C0 ret

gadget(16)

0x7fb7fe835c A8C10BE1 ldp x1,x2,[sp],#0x10

0x7fb7fe8360 A1C113E3 ldp x3,x4,[sp],#0x10

0x7fb7fe8364 A8C27BFD ldp x29,x30,[sp],#0x20

0x7fb7fe8368 D65F03C0 ret

gadget(2)

0x7fb7f6ba7c 8B040063 add x3,x3,x4

0x7fb7f6ba80 A8C17BFD ldp x29,x30,[sp],#0x10

0x7fb7f6ba84 D65F03C0 ret

gadget(17)

0x7fb7f8a4c8 91000484 add x4,x4,#0x1

0x7fb7f8a4cc A8C17BFD ldp x29,x30,[sp],#0x10

0x7fb7f8a4d0 D65F03C0 ret

gadget(18)

0x7fb7f86240 EB0A009F cmp x4,x10

0x7fb7f86244 9A811042 csel x2,x2,x1,ne

0x7fb7f86248 A8C17BFD ldp x29,x30,[sp],#0x10

0x7fb7f8624c D65F03C0 ret

gadget(13)

0x7fb7f2caf4 D10043BF sub sp,x29,#0x10

0x7fb7f2caf8 A9417BFD ldp x29,x30,[sp,#0x10]

0x7fb7f2cafc 910083FF add sp,sp,#0x20

0x7fb7f2cb00 D65F03C0 ret

gadget(14)

0x7fb7f53458 D61F0040 br x2

gadget(15)

3.2 结果对比分析

本例中取n=3,基于if-gadget和无条件跳转gadget的原理如图5所示。图的左侧给出ARMv8 ROP的内存安排和内存地址的后12位,图的右侧的虚线代表指令序列的执行顺序。

(a) 基于条件跳转gadget

(b) 无条件跳转gadget图5 不同情况跳转gadget的ROP工作原理图

可以看出,尽管通过无条件跳转gadget也可完成相同的功能,但是与本文提出的基于条件跳转gadget的方法相比,其需要不断地重复使用gadget(13)、gadget(17)和gadget(18),造成了内存空间的冗余。当n=3时,基于if-gadget和无条件跳转gadget对应的控制结构如图6所示。基于if-gadget的方法生成了128字节大小的控制结构,无条件跳转gadget的方法生成了240字节大小的控制结构,造成了112字节的空间浪费。而且随着n的增大,无条件跳转gadget的方法的控制结构也将越来越大,浪费的内存空间也将越来越多。表2给出了n=4,5,6,7时的情形,可以看出,当n接近无穷大时,本文的方法可以节省大量的内存空间,从而提高执行效率。

图6 ARMv8 ROP shellcode

方法基于if-gadget无条件跳转gadget浪费的内存空间大小/Byten=4128304176n=5128368240n=6128432304n=7128496368

4 结 语

ARMv7架构基于条件跳转指令构造条件跳转gadget的方法在ARMv8架构中已经不再适用,而大多数的shellcode存在循环结构,条件跳转gadget是ROP shellcode中循环结构构造的基础。基于上述问题,本文首先提出一种在ARMv8平台利用CSEL指令和CMP指令gadget构造条件跳转gadget的方法。然后基于条件跳转gadget后给出了ARMv8 ROP shellcode中循环结构的构造方法,并通过一个实例证明了本文的方法在ARMv8架构上的可行性。给出了ARMv8 ROP shellcode中循环结构的使用方法和包含循环结构的ARMv8 ROP控制结构的生成过程,并通过与无条件跳转gadget方法相比,本文的方法减小了ARMv8 ROP控制结构的大小,节省了内存空间。

猜你喜欢

寄存器指令架构
基于FPGA的RNN硬件加速架构
功能架构在电子电气架构开发中的应用和实践
基于 Verilog HDL 的多周期 CPU 设计与实现
《单一形状固定循环指令G90车外圆仿真》教案设计
Lite寄存器模型的设计与实现
构建富有活力和效率的社会治理架构
常用电子测速法在某数字信号处理器中的应用*
关于ARM+FPGA组建PLC高速指令控制器的研究
移位寄存器及算术运算应用
VoLTE时代智能网架构演进研究