Linux下劫持系统调用的几种方式.pdf
2009 年第6 期
前置知识:Linux 、C
关键词:编程、系统劫持、系统调用
Linux 下劫持系统调用的几种方式
文/ 图 小小杉
在黑防上看到大量的文章都是在Windows 下针对Hook SSDT 、Shadow SSDT 表来劫持
Native API 等做文章,那么在Linux 系统下,又是怎样的情形呢?实际上,我们同样可以通
过一些手段来劫持系统调用,从而获得内核级特权。Linux 操作系统为了内核安全性考虑,
在用户态和内核态之间增加了所谓的系统调用层,即每次用户需要操作内核下的资源时,必
须借助系统提供的系统调用才能获取。显然,只要我们能够去截获这些系统调用,必然能很
好地进入内核态,即获得内核级特权。
本文首先分析Linux 下系统调用执行流程,然后给出当前劫持系统调用的各种方式,以
及通过劫持系统调用后我们所能做的事情。OK,下面我们来详细分析Linux 下的系统调用
整个实现过程。 线
Linux 下系统调用剖析
在x86 平台下,Linux 借助int 0x80 指令实现用户态向内核态的真正转换。在用户态下
防 处
执行的各种系统调用函数都会对应一个系统调用号,然后将此调用号存放到eax 寄存器中,
作为参数传递给int $0x80 的处理函数system_call()进一步处理。下面还是来看整个系统调用
的流程,再针对流程进行具体分析。 出
客
系统调用流程主要包含以下过程:(1)确定与中断或异常关联的向量i (0≤i≤255);(2 )
读idtr 寄存器指向的IDT 表中的第i 项;(3 )从gdtr 寄存器获得GDT 的基址,并在GDT
黑 明
中查找,以读取 IDT 表项中的选择符所标识的段描述符,此段描述符即指定了中断或异常
处理程序所在段的基址;(4 )确定特权级,将当前的CPL 与段描述符(存放在GDT 中)的
描述符特权级DPL 比较,若CPL 小于DPL 则允许访问;(5 )执行int $0x80 指令,CPU 切
注
换到内核态,将系统调用号存入到%eax 寄存器中,而系统调用的各参数则依次存入 ebx、
ecx 等通用寄存器中。(6 )开始执行 system_call() 函数,将寄存器%eax 压入堆栈,执行
请
SAVE_ALL 宏,即所谓的保护现场,然后检测当前的进程是否具有执行此系统调用的权限,
若是,则会转入call 到sys_call_table()函数中,找到正确的系统调用处理程序,执行相应的
系统调用。现在我们通过源码分析揭开其执行过程,首先看看系统调用的入口函数执行的一
载
段代码: 转
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
{ \
long __res; \
__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
: "=a" (__res) \
: "0" (__NR_##name),"ri" ((long)(arg1)) : "memory"); \
__syscall_return(type,__res); \
}
2009 年第6 期
此宏的定义在内核版本 2.6. 18 下可以从目录\include\asm-i386\unistd.h 下查看到。其中
__NR