# 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)/