# ret2csu
# 原理
- 64 位程序中,函数的前 6 个参数是通过寄存器传递的,但是大多数时候我们很难找到每个寄存器对应的 gadges。这时候,我们可以利用 x64 下的__libc_csu_init 中的 gadgets。
- 这个函数是用来对 libc 进行初始化操作的,而一般的程序都会调用 libc 函数,所以这个函数一定会存在。
# 下面借用别人在 IDA 摘出来的__libc_csu_init 函数的汇编指令
.text:00000000004011B0 ; void _libc_csu_init(void)
.text:00000000004011B0 public __libc_csu_init
.text:00000000004011B0 __libc_csu_init proc near ; DATA XREF: _start+16↑o
.text:00000000004011B0 ; __unwind {
.text:00000000004011B0 push r15
.text:00000000004011B2 mov r15, rdx
.text:00000000004011B5 push r14
.text:00000000004011B7 mov r14, rsi
.text:00000000004011BA push r13
.text:00000000004011BC mov r13d, edi
.text:00000000004011BF push r12
.text:00000000004011C1 lea r12, __frame_dummy_init_array_entry
.text:00000000004011C8 push rbp
.text:00000000004011C9 lea rbp, __do_global_dtors_aux_fini_array_entry
.text:00000000004011D0 push rbx
.text:00000000004011D1 sub rbp, r12
.text:00000000004011D4 sub rsp, 8
.text:00000000004011D8 call _init_proc
.text:00000000004011DD sar rbp, 3
.text:00000000004011E1 jz short loc_4011FE
.text:00000000004011E3 xor ebx, ebx
.text:00000000004011E5 nop dword ptr [rax]
.text:00000000004011E8
gadgets2:
.text:00000000004011E8 loc_4011E8: ; CODE XREF: __libc_csu_init+4C↓j
.text:00000000004011E8 mov rdx, r15
.text:00000000004011EB mov rsi, r14
.text:00000000004011EE mov edi, r13d
.text:00000000004011F1 call qword ptr [r12+rbx*8]
.text:00000000004011F5 add rbx, 1
.text:00000000004011F9 cmp rbp, rbx
.text:00000000004011FC jnz short loc_4011E8
.text:00000000004011FE
gadgets1:
.text:00000000004011FE loc_4011FE: ; CODE XREF: __libc_csu_init+31↑j
.text:00000000004011FE add rsp, 8
.text:0000000000401202 pop rbx
.text:0000000000401203 pop rbp
.text:0000000000401204 pop r12
.text:0000000000401206 pop r13
.text:0000000000401208 pop r14
.text:000000000040120A pop r15
.text:000000000040120C retn
.text:000000000040120C ; } // starts at 4011B0
.text:000000000040120C __libc_csu_init endp
这里搬运之前在 CSDN 上发的文章(汇编代码执行顺序为先 gadgets2, 然后 gadgets1)
pop 命令 会把栈中的值存入相应的寄存器中,那么我们可以通过往栈中写对应的数据来存入寄存器里
cmp rbx, rbp //cpm后的不同的调整指令有着不同的作用,这里 jnz 比较结果相同不跳转,不相同就跳转 | |
jnz short loc_400580 |
最后第二次回到 gadget1 时,此时已经给寄存器赋值完毕只需要回到 ret,此处填充 56 个 padding 字符是因为在地址 0x4011FE 处有 add rsp , 8
这会把 rsp 栈提高 8,所以要填充 8 个字符来站这个位置,后面的 pop rbx ~ pop r15
共有 6 个寄存器,pop 了 6 次,所以总共是 (6+1)*8=56,所以填充 56 个字符即可到 ret 来控制程序执行
例题:https://vvwwvv.cn/2023/05/04/pwn/ 刷题 / 看雪社区 / 看雪社区 pwn8 (64 位构造通用 ROP,ret2csu)/