免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 833 | 回复: 0
打印 上一主题 下一主题

截获系统调用之改进版 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-11 21:00 |只看该作者 |倒序浏览
   从网上看到有介绍截获系统调用的文章,于是自己下载下来编译执行了一下。
但是发现这些例子都有缺点:像sys_execve(struct pt_regs regs)这样的系统调用,
截获后若要它仍然完成原有的功能需要调用do_execve()函数,但是这个函数是内核不导
出,很麻烦。另外,即算是截获函数实现了它的功能,错误还是难免出现。
    于是就想怎么样截获后又能不留痕迹地实现原有功能。一个好的想法是直接在截获函数中
直接调用sys_execve().然而想到信号处理时如果中断了系统调用则可以重新执行,那么
能不能通过类似的方法执行系统调用呢?一个想法:替换之前将要替换的系统调用保存在其他
中断向量中,然后在替换函数中调整内核堆栈,让系统重新以另一个调用号调用保存的系统调用。
经过近两天的编码调试,终于如愿以偿。先说明一下关键之处,然后是代码。
关键之处:   
1.将原来的系统调用函数保存在向量__NR_save=17中,这里用17有两个原因
    1) 在文件syscall_table.S中,向量17的函数是sys_ni_syscall,这是一个没有使用的
        调用号。
       .long sys_ni_syscall    /* old break syscall holder */
    2) 一开始我用 319,因为NR_syscalls=318
        #define NR_syscalls 318
         大于NR_syscalls的调用号自然没人用,然而这样做不行。因为在entry.S中
        system_call:
            ...
            cmpl $(nr_syscalls), %eax
            jae syscall_badsys   
             . ...
        若调用号大于NR_syscalls,根本不会执行调用函数
2.    信号处理中重新执行中断的调用是这样做的:
       case -ERESTARTNOINTR:
          regs->eax = regs->orig_eax;
          regs->eip -= 2;
    于是我就想这样做
           pr.eip-=2;
    然而老是出错,后来查看汇编后的代码发现,减2操作是在寄存器中实现的,内核堆栈
    根本没有改变。于是改用汇编:
     __asm__("sub $0x2,%0" : "=m" (pr.eip));
3.   将内核堆栈中regs.eax改为__NR_save,然而这一步不能通过在函数中赋值改变
    因为在entry.S中调用完函数后,内核将寄存器eax值存入regs.eax中
         system_call:
            ...
            call *sys_call_table(,%eax,4)
            movl %eax,EAX(%esp)             # store the return value        
              . ...  
    我们知道寄存器eax存的是函数返回值,于是我将替换函数返回_NR_save,让内核自动
    将其保存在regs.eax。
以下是代码:
#include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xunil@bmy and hhj");
MODULE_DESCRIPTION("Different from others, this module automatically locate the entry of sys_call_table !");
unsigned long *sys_call_table=NULL;
//asmlinkage
int (*orig_exec)(struct pt_regs);
int __NR_save=17;
struct _idt
{
unsigned short offset_low,segment_sel;
unsigned char reserved,flags;
unsigned short offset_high;
};
unsigned long *getscTable(void)
{
unsigned char idtr[6],*shell,*sort;
struct _idt *idt;
unsigned long system_call,sct;
unsigned short offset_low,offset_high;
char *p;
int i;
/* get the interrupt descriptor table */
__asm__("sidt %0" : "=m" (idtr));
/* get the address of system_call */
idt=(struct _idt*)(*(unsigned long*)&idtr[2]+8*0x80);
offset_low = idt->offset_low;
offset_high = idt->offset_high;
system_call=(offset_highpid);
    return __NR_save;
}
static int __init find_init(void){
sys_call_table = getscTable();
printk("here 1\n");
orig_exec=(int(*)(struct pt_regs))(sys_call_table[__NR_execve]);
printk("here 2,%d\n",__NR_save);
sys_call_table[__NR_execve]=(long)hacked_exec;
sys_call_table[__NR_save]=(long)orig_exec;
return 0;
}
static void __exit find_cleanup(void){
sys_call_table[__NR_execve]=(unsigned long)orig_exec;
}
module_init(find_init);
module_exit(find_cleanup);

               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/36646/showart_319467.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP