__libc_csu_init函数的通用gadget

时间:2021-05-26 05:43:37
 .text: ; =============== S U B R O U T I N E =======================================
.text:
.text:
.text: public __libc_csu_init
.text: __libc_csu_init proc near ; DATA XREF: _start+16o
.text: push r15
.text: mov r15d, edi
.text: push r14
.text: mov r14, rsi
.text:000000000040084A push r13
.text:000000000040084C mov r13, rdx
.text:000000000040084F push r12
.text: lea r12, __frame_dummy_init_array_entry
.text: push rbp
.text: lea rbp, __do_global_dtors_aux_fini_array_entry
.text: push rbx
.text: sub rbp, r12
.text: xor ebx, ebx
.text: sar rbp,
.text:000000000040086A sub rsp,
.text:000000000040086E call _init_proc
.text: test rbp, rbp
.text: jz short loc_400896
.text: nop dword ptr [rax+rax+00000000h]
.text:
.text: loc_400880: ; CODE XREF: __libc_csu_init+54j
27 .text:0000000000400880 mov rdx, r13
28 .text:0000000000400883 mov rsi, r14
29 .text:0000000000400886 mov edi, r15d
30 .text:0000000000400889 call qword ptr [r12+rbx*8]
31 .text:000000000040088D add rbx, 1
32 .text:0000000000400891 cmp rbx, rbp
33 .text:0000000000400894 jnz short loc_400880
.text:
.text: loc_400896: ; CODE XREF: __libc_csu_init+36j
.text: add rsp,
37 .text:000000000040089A pop rbx
38 .text:000000000040089B pop rbp
39 .text:000000000040089C pop r12
40 .text:000000000040089E pop r13
41 .text:00000000004008A0 pop r14
42 .text:00000000004008A2 pop r15
.text:00000000004008A4 retn
.text:00000000004008A4 __libc_csu_init endp
.text:00000000004008A4
.text:00000000004008A4 ; ---------------------------------------------------------------------------

x64中的前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9中

r13   =rdx=arg3

r14   =rsi=arg2

r15d=edi=arg1

r12= call address

这段gadgets用于在X64下进行rop,根本原因是X64使用寄存器传参无法直接用栈进行rop。具体用法如下:

分为两部分使用

1.执行gad1

.text:000000000040089A                 pop     rbx  必须为0
.text:000000000040089B                 pop     rbp  必须为1
.text:000000000040089C                 pop     r12  call!!!!
.text:000000000040089E                 pop     r13  arg3
.text:00000000004008A0                 pop     r14  arg2
.text:00000000004008A2                 pop     r15  arg1
.text:00000000004008A4                 retn  ——> to gad2

2.再执行gad2

.text:0000000000400880                 mov     rdx, r13
.text:0000000000400883                 mov     rsi, r14
.text:0000000000400886                 mov     edi, r15d
.text:0000000000400889                 call    qword ptr [r12+rbx*8] call!!!
.text:000000000040088D                 add     rbx, 1
.text:0000000000400891                 cmp     rbx, rbp
.text:0000000000400894                 jnz     short loc_400880
.text:0000000000400896                 add     rsp, 8
.text:000000000040089A                 pop     rbx
.text:000000000040089B                 pop     rbp
.text:000000000040089C                 pop     r12
.text:000000000040089E                 pop     r13
.text:00000000004008A0                 pop     r14
.text:00000000004008A2                 pop     r15
.text:00000000004008A4                 retn ——> 构造一些垫板(7*8=56byte)就返回了

此外还有一个老司机才知道的x64 gadgets,就是 pop rdi,ret的gadgets。这个gadgets还是在这里,但是是由opcode错位产生的。

如上的例子中4008A2、4008A4两句的字节码如下

0x41 0x5f 0xc3

意思是pop r15,ret,但是恰好pop rdi,ret的opcode如下

0x5f 0xc3

因此如果我们指向0x4008A3就可以获得pop rdi,ret的opcode,从而对于单参数函数可以直接获得执行

与此类似的,还有0x4008A1处的 pop rsi,pop r15,ret

那么这个有什么用呢?我们知道x64传参顺序是rdi,rsi,rdx,rcx。

所以rsi是第二个参数,我们可以在rop中配合pop rdi,ret来使用pop rsi,pop r15,ret,这样就可以轻松的调用2个参数的函数。

综上,我们介绍了x64下利用通用gadgets调用一个参数、两个参数、三个参数函数的方法。