基础知识

相关函数:longjmp, siglongjmp, setjmp 表头文件:#include 函数定义:int sigsetjmp(sigjmp_buf env, int savesigs) 函数说明:sigsetjmp()会保存目前堆栈环境,然后将目前的地址作一个记号, 而在程序其他地方调用siglongjmp()时便会直接跳到这个记号位置,然后还原堆栈,继续程序的执行。 参数env为用来保存目前堆栈环境,一般声明为全局变量 参数savesigs若为非0则代表搁置的信号集合也会一块保存 当sigsetjmp()返回0时代表已经做好记号上,若返回非0则代表由siglongjmp()跳转回来。 返回:若直接调用则为0,若从siglongjmp调用返回则为非0

RF 恢复(第16 位)。控制处理器对指令断点的响应。置1 则暂时禁用指令断点产生调试异常(#DE),但是其它异常情况仍可以产生异常。置0 则指令断点产生调试异常。RF 标志的主要功能是许可从调试异常(调试断点引发的)后面的那个指令开始继续执行。调试软件必须在用IRETD 指令返回到被中断程序之前,将栈中的EFLAGES 映象中的该位置为1,以阻止指令断点产生另外的调试异常。在返回并成功执行断点指令之后,处理器会自动清零该位,从而许可继续产生指令断点故障。中文手册上写的已经很明白了。再解释一下,调试中断会在执行指令前触发,但从中断返回的时候,如果不置RF的话,会再次进入调试中断,RF就是为了防止重复进入调试中断而使用的。这个寄存器与硬断点一起使用(也就是调试寄存器)。

漏洞分析

MOV SS 和POP SS指令对SS进行操作,会导致延迟产生调试异常,POP SS 指令会抑制所有中断(包括 NMI 中断),直到执行下一条指令之后。此操作可以确保依次执行 POP SS 与 MOV ESP, EBP 指令,而不会在中断期间遇到失效的堆栈。不过,使用 LSS 指令才是加载 SS 与 ESP 寄存器的首选方法。

调试异常不会因为开启EFLAGS.IF标志位而被停止

如果MOV SS 或 POP SS指令后面跟类似SYSCALL, SYSENTER, INT 3等指令,则控制权限将转移到CPL < 3,此时调试异常则会在CPL < 3的权限下被处理。

在SS被加载时就会产生#DB异常

在Windows,macOS会导致提权,对于FreeBSD和Linux kernel会导致崩溃

IF(bit 9) [Interrupt enable flag] 该标志用于控制处理器对可屏蔽中断请求(maskable interrupt requests)的响应。置1以响应可屏蔽中断,反之则禁止可屏蔽中断。

INT 01:单步中断,由T命令产生。
它的特征是将陷阱标志位TF置位,这样当程序运行时,会在每一条指令的后面产生一个单步中断,从而中止指令的继续执行

#DB :调试异常

xor​ ​eax, eax ; Recognize pending interrupts
inc​ rdi      ; Recognize pending interrupts
mov​ bx, 50h  ; Recognize pending interrupts
mov​ ss, bx   ; INTR/NMI and certain #DB held
mov​ esp, eax ; Recognize pending interrupts in architectural order after instruction executes

; GSBASE would ideally first be primed with
WRGSBASE in a 64 bit code segment
; Hardware breakpoint (DR0) set to memory
address where stack is, e.g. 0x401000.
call​ SetThreadContext
; Lets imagine that 0x401000 contains a valid SS
selector.
mov​ esp, 401000h
pop​ ss
int​ 3

call​ SetThreadContext
mov​ esp, 401000h
pop​ ss
syscall

白皮书的相关描述:

Instruction breakpoints are the highest priority debug exceptions. They are serviced before any other exceptions
detected during the decoding or execution of an instruction. However, if an instruction breakpoint is placed on an
instruction located immediately after a POP SS/MOV SS instruction, the breakpoint will be suppressed as if
EFLAGS.RF were 1 (see the next paragraph and Section 6.8.3, “Masking Exceptions and Interrupts When
Switching Stacks,” of the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A).

运行结果

	SS = 0x2b, &SS = 0x0x6041a8
	PR_SET_PTRACER_ANY succeeded
	Set up a watchpoint
	DR0 = 6041a8, DR1 = 400f36, DR7 = 7000a
[RUN]	Read from watched memory (should get SIGTRAP)
	Got SIGTRAP with RIP=400d68, EFLAGS.RF=0
[RUN]	MOV SS; INT3
	Got SIGTRAP with RIP=400d7d, EFLAGS.RF=0
[RUN]	MOV SS; INT 3
	Got SIGTRAP with RIP=400d8f, EFLAGS.RF=0
[RUN]	MOV SS; CS CS INT3
	Got SIGTRAP with RIP=400da2, EFLAGS.RF=0
[RUN]	MOV SS; CSx14 INT3
	Got SIGTRAP with RIP=400dc1, EFLAGS.RF=0
[RUN]	MOV SS; INT 4
	Got SIGSEGV with RIP=400de7
[RUN]	MOV SS; ICEBP
	Got SIGTRAP with RIP=400e1f, EFLAGS.RF=0
[RUN]	MOV SS; CLI
	Got SIGSEGV with RIP=400e56
[RUN]	MOV SS; #PF
	Got SIGSEGV with RIP=400e8e
[RUN]	MOV SS; INT 1
	Got SIGSEGV with RIP=400ed1
[RUN]	MOV SS; SYSCALL
[RUN]	MOV SS; breakpointed NOP
	Got SIGTRAP with RIP=400f37, EFLAGS.RF=0
[RUN]	MOV SS; SYSENTER
	Got SIGSEGV with RIP=6ad2ac89
[RUN]	MOV SS; INT $0x80
[OK]	I aten't dead

参考链接

https://www.triplefault.io/2018/05/spurious-db-exceptions-with-pop-ss.html

http://everdox.net/popss.pdf

https://marc.info/?l=linux-kernel&m=152580052406931

https://software.intel.com/en-us/articles/intel-sdm

http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User%27s%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/vc245.htm

异常表:http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User%27s%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/ra_mode_except.htm

pop ss用于反调试:https://www.symantec.com/connect/articles/windows-anti-debug-reference