本篇文章主要借鉴自:https://n132.github.io/2019/05/10/2019-05-08-Startctf2019-Heap-master/#setcontext 。
一个很好用的函数。
目录
setcontext
#include <ucontext.h>
int setcontext(const ucontext_t *ucp);
其作用是用户上下文的设置,所以我们在可以小范围控制执行流已知libc_base但不足以完成我们的目标时可以先跳setcontext+53来扩大控制范围。
感觉非常好用,可以直接控制大部分寄存器和执行流。
<setcontext>: push rdi
<setcontext+1>: lea rsi,[rdi+0x128]
<setcontext+8>: xor edx,edx
<setcontext+10>: mov edi,0x2
<setcontext+15>: mov r10d,0x8
<setcontext+21>: mov eax,0xe
<setcontext+26>: syscall
<setcontext+28>: pop rdi
<setcontext+29>: cmp rax,0xfffffffffffff001
<setcontext+35>: jae 0x7ffff7a7d520 <setcontext+128>
<setcontext+37>: mov rcx,QWORD PTR [rdi+0xe0]
<setcontext+44>: fldenv [rcx]
<setcontext+46>: ldmxcsr DWORD PTR [rdi+0x1c0]
<setcontext+53>: mov rsp,QWORD PTR [rdi+0xa0]
<setcontext+60>: mov rbx,QWORD PTR [rdi+0x80]
<setcontext+67>: mov rbp,QWORD PTR [rdi+0x78]
<setcontext+71>: mov r12,QWORD PTR [rdi+0x48]
<setcontext+75>: mov r13,QWORD PTR [rdi+0x50]
<setcontext+79>: mov r14,QWORD PTR [rdi+0x58]
<setcontext+83>: mov r15,QWORD PTR [rdi+0x60]
<setcontext+87>: mov rcx,QWORD PTR [rdi+0xa8]
<setcontext+94>: push rcx
<setcontext+95>: mov rsi,QWORD PTR [rdi+0x70]
<setcontext+99>: mov rdx,QWORD PTR [rdi+0x88]
<setcontext+106>: mov rcx,QWORD PTR [rdi+0x98]
<setcontext+113>: mov r8,QWORD PTR [rdi+0x28]
<setcontext+117>: mov r9,QWORD PTR [rdi+0x30]
<setcontext+121>: mov rdi,QWORD PTR [rdi+0x68]
<setcontext+125>: xor eax,eax
<setcontext+127>: ret
<setcontext+128>: mov rcx,QWORD PTR [rip+0x356951] # 0x7ffff7dd3e78
<setcontext+135>: neg eax
<setcontext+137>: mov DWORD PTR fs:[rcx],eax
<setcontext+140>: or rax,0xffffffffffffffff
<setcontext+144>: ret
setcontext_53
至于为什么要跳到 setcontext+53
这个位置。因为fldenv [rcx]
指令会造成程序执行的时候直接crash,所以要避开这个指令。
注意:要构造好rsp的值,因为有 push rcx 指令,如果rsp指向的内存不可访问,则会crash。
构造ucontext_t
可以直接使用 pwntools 的 SigreturnFrame()
来构造ucontext_t
结构体。
类似于下面这种形式:
# 指定机器的运行模式
context.arch = "amd64"
# 设置寄存器
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0
frame.rdx = 0
注意:[rdi+0xa8](被弹到rcx的那个地址)对应的是 frame 框架的 rip 。
也就是说,frame.rip
就是我们执行完setcontext
后执行的地址。而 frame.rsp
的值就是我们执行完
frame.rip
后,要执行的值,也就是说我们可以连续控制。
利用思路
一般是用来执行mprotect
函数,后注入shellcode。也可以直接用来构造ROP链。