如何强制使用 int $0x80 而不是 sysenter 进行系统调用检测
Posted
技术标签:
【中文标题】如何强制使用 int $0x80 而不是 sysenter 进行系统调用检测【英文标题】:how to force use of int $0x80 instead of sysenter for syscall detection 【发布时间】:2016-03-27 21:53:43 【问题描述】:我正在尝试完成将 ELF 二进制文件转换为虚拟机的项目,以提供类似于http://dune.scs.stanford.edu/ 的进程自己的执行环境。许多论文都说“我们检测到系统调用......”但没有提供检测的细节,除了这篇论文的代码检测到 vmx 非根环 0 中的系统调用。(因为进程将在这个环中运行)。但是由于他的论文中缺乏文档和提示,我没有能力掌握他的方法。 相关代码如下
/*
* macro to switch to G0 fs.base
*
* NOTE: clobbers %rax, %rdx, and %rcx
*/
.macro SET_G0_FS_BASE
movq $0, %gs:IN_USERMODE
movq %gs:KFS_BASE, %rax
movq %gs:UFS_BASE, %rdx
cmp %rax, %rdx
je 1f
#if USE_RDWRGSFS
wrfsbase %rax
#else
movq %rax, %rdx
shrq $32, %rdx
movl $MSR_FS_BASE, %ecx
wrmsr
#endif /* USE_RDWRGSFS */
1:
.endm
__dune_syscall:
/* handle system calls from G0 */
testq $1, %gs:IN_USERMODE
jnz 1f
pushq %r11
popfq
vmcall
jmp *%rcx
1:
/* first switch to the kernel stack */
movq %rsp, %gs:TMP
movq %gs:TRAP_STACK, %rsp
/* now push the trap frame onto the stack */
subq $TF_END, %rsp
movq %rcx, RIP(%rsp)
movq %r11, RFLAGS(%rsp)
movq %r10, RCX(%rsp) /* fixup to standard 64-bit calling ABI */
SAVE_REGS 0, 1
movq %gs:TMP, %rax
movq %rax, RSP(%rsp)
/* then restore the CPL0 FS base address */
SET_G0_FS_BASE
/* then finally re-enable interrupts and jump to the handler */
sti
movq %rsp, %rdi /* argument 0 */
lea dune_syscall_handler, %rax
call *%rax
/* next restore the CPL3 FS base address */
SET_G3_FS_BASE
/* then pop the trap frame off the stack */
RESTORE_REGS 0, 1
movq RCX(%rsp), %r10
movq RFLAGS(%rsp), %r11
movq RIP(%rsp), %rcx
/* switch to the user stack and return to ring 3 */
movq RSP(%rsp), %rsp
sysretq
.globl __dune_syscall_end
__dune_syscall_end:
nop
我的问题如下
1) 上面的代码是如何工作的?任何解释、指针或参考都会有所帮助
2) 在这种情况下检测系统调用的任何其他方法是可能的吗?我认为使用vdso
进行调整将是另一种解决方案。我能想到的是强制 vmx 非 root 中的系统调用使用int 80h
并挂钩此中断。请分享对此黑客的任何建议。
【问题讨论】:
我还没有阅读整个问题,但是构建内核以在vdso
中导出int 0x80
存根而不是sysenter
存根应该对glibc 完全透明。您是否研究过 strace(1)
用于跟踪系统调用的机制?我不确定它在后台是如何工作的,但我知道它是基于ptrace(2)
系统调用,它让gdb
控制另一个单步进程。还有ltrace(1)
,它使用共享库黑客来跟踪所有函数调用到共享库。
【参考方案1】:
我不会向你解释这段代码(需要更多,但我不能,因为 git 存储库仍然不可用)
但是在非 root 的 vmx 中检测系统调用依赖于一些技巧,您可以在此 paper,第 6 页和第 7 页中找到。 基本上,检测
syscall/sysret:您必须禁用 EFER 中的 CSE 位,以便任何使用 syscall/sysret 的尝试都会导致您将拦截的无效操作码异常 sysenter/sysexit:您必须将 SYSENTER_CS_MSR 保存在虚拟机管理程序中的某个位置,然后将其加载为空值,这样对 sysenter/sysexit 的任何使用都会导致您将捕获的一般保护异常【讨论】:
以上是关于如何强制使用 int $0x80 而不是 sysenter 进行系统调用检测的主要内容,如果未能解决你的问题,请参考以下文章
我们如何强制 ForEach 使用 UUID 而不是 (id: \.self)?
execve缓冲区溢出成功完成后的CPU执行流程? ..int 0x80成功完成之后?
汇编编译的可执行文件在 Windows 上的 Ubuntu 上使用 INT 0x80 Linux 子系统不产生输出
MySQL 中的 CASE 强制列数据类型为 BIGINT 而不是 INT
我可以强制 NSExpression 和 expressionValue 以某种方式假设 Doubles 而不是 Ints 吗?