做酷 发表于 2014-05-28 22:54

[求助]获取system_call地址造成系统重启的问题(个人崩溃中)

本帖最后由 做酷 于 2014-05-28 22:55 编辑

最近在学习hook系统调用,但是在获取system_call地址的时候,遇到一个自己无法理解的问题,还请各位帮忙看一看:

一、环境信息
#lsb_release -a
LSB Version:    :core-3.1-ia32:core-3.1-noarch:graphics-3.1-ia32:graphics-3.1-noarch
Distributor ID: RedHatEnterpriseServer
Description:    Red Hat Enterprise Linux Server release 5.2 (Tikanga)
Release:      5.2
Codename:       Tikanga

# uname -a
Linux localhost.localdomain 2.6.18-92.el5xen #1 SMP Tue Apr 29 13:45:57 EDT 2008 i686 i686 i386 GNU/Linux

二、测试代码
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/dirent.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <linux/proc_fs.h>   

struct idt_descriptor
{
    unsigned short off_low;

    unsigned short sel;

    unsigned char none, flags;

    unsigned short off_high;

};   

void *get_system_call(void)
{

        unsigned char idtr;

        unsigned long base;

        struct idt_descriptor desc;   

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

        base = *((unsigned long *) &idtr);

        //中断描述符表的第0x80项是system_call函数的

        memcpy(&desc, (void *) (base + (0x80* 8 )), sizeof(desc));

        return        (void *)base;


/***********************************************************************************

*insmod 模块后
*在此之上的代码执行是没有问题的,可以打印相应的值

*如果将上面的return语句去除,执行下面的语句,都会造成系统直接重启,即任何对desc成员的读取操作都会造成关机重启

*问题就是,struct idt_descriptor desc这个局部变量,为什么可写而不可读,这是什么原因造成的?该如何解决?好像类似的文章都没有提到这种现象

************************************************************************************/
       
        //base=(unsigned long )desc.off_low;
        //return        (void *)base;

        //printk(KERN_EMERG"hight %x\n", desc.off_high);
        //printk(KERN_EMERG"low %x\n", desc.off_low);


        //return ((void *) ((desc.off_high << 16) + desc.off_low));

}


static int __init init_hook(void)
{
    void *system_call;

    system_call = get_system_call();

    printk(KERN_EMERG"Address of system_call: %x\n", (unsigned int)system_call);

    return 0;
}

static void __exit exit_hook(void)
{
}

module_init(init_hook);
module_exit(exit_hook);

MODULE_LICENSE("GPL" ) ;

做酷 发表于 2014-05-28 23:04

void *get_system_call(void)
{
    unsigned char idtr;
    unsigned long base;
    struct idt_descriptor desc={0};
    return        desc.off_high;
}
将函数替换为上述内容,也是可以正常打印的
localhost kernel: Address of system_call: 0

humjb_1983 发表于 2014-05-29 14:00

base = *((unsigned long *) &idtr);
...
//base=(unsigned long )desc.off_low;
base指针两次赋值?

做酷 发表于 2014-05-29 17:50

本帖最后由 做酷 于 2014-05-29 18:31 编辑

回复 3# humjb_1983


   在代码说明里已经说清楚了,base赋值只是为了函数返回测试!
问题的实质是无法对struct idt_descriptor desc这个局部变量的成员进行读取,跟base赋几次值没有关系!

humjb_1983 发表于 2014-05-29 19:18

做酷 发表于 2014-05-29 17:50 static/image/common/back.gif
回复 3# humjb_1983



出问题是第一条没执行,还是第二条没执行?为何确认是读取时出错?

hmsghnh 发表于 2014-05-29 22:25

可能没有下面那段的时候,那个memcpy也被优化掉了?没有实际执行。要查看一下编译出来的汇编看看。
你要看看系统崩溃时的oops打印的错误地址是什么,对应代码的哪一行。

做酷 发表于 2014-05-29 23:53

回复 5# humjb_1983

        unsigned char idtr;

        unsigned long base;

        struct idt_descriptor desc;

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

        base = *((unsigned long *) &idtr);

        //中断描述符表的第0x80项是system_call函数的

        memcpy(&desc, (void *) (base + (0x80*8)), sizeof(desc));

        printk(KERN_EMERG"hight %x\n", desc.off_high);
        printk(KERN_EMERG"low %x\n", desc.off_low);


这样也是重启的!

做酷 发表于 2014-05-29 23:55

回复 6# hmsghnh


   好的,我再看看!

做酷 发表于 2014-05-30 00:18

对各位关注表示感谢!:))

再把几个测试代码贴出来说明一下:

1、
void *get_system_call(void)
{
        unsigned char idtr;
        unsigned long base;
        struct idt_descriptor desc={0};

        return        desc.off_high;
}
结果:localhost kernel: Address of system_call: 0

2、
void *get_system_call(void)
{
        unsigned char idtr;
        unsigned long base;
        struct idt_descriptor desc={0};

        asm ("sidt %0" : "=m" (idtr));
        base = *((unsigned long *) &idtr);
        // 中断描述符表的第0x80项是system_call函数的
        memcpy(&desc, (void *) (base + (0x80* 8 )), sizeof(desc));
        return        (void *)base;
}
结果:localhost kernel: Address of system_call: ff1fc860

3、
void *get_system_call(void)
{
    unsigned char idtr;
    unsigned long base;
    struct idt_descriptor desc={0};

    asm ("sidt %0" : "=m" (idtr));
    base = *((unsigned long *) &idtr);

    // 中断描述符表的第0x80项是system_call函数的
    memcpy(&desc, (void *) (base + (0x80* 8 )), sizeof(desc));

    return        (void *)desc.off_low;
}
结果:关机重启

humjb_1983 发表于 2014-05-30 09:42

还是需要看看具体错误的指令对应到哪行代码。
页: [1]
查看完整版本: [求助]获取system_call地址造成系统重启的问题(个人崩溃中)