拦截 系统调用 老是不成功

littlehedgehog 2008-11-10 09:28:17
获取sys_call_table这些都是成功的,但是就是替换系统后一直不成功,比如说这么一个简单的替换都成问题:


static asmlinkage long hijack_mkdir(const char *pathname, int mode)
{
printk("%s\n",pathname);
return orig_mkdir(pathname, mode);
}


orig_mkdir是原系统调用,这个也能确定是对的,通过dmesg查看printk输出pathname信息是对的,但是orig_mkdir调用却说是pathname错误的文件地址,返回14(EFAULT 14 /* Bad address */) ,不知道各位能不能给点提示。
环境ubuntu 8.04 kernel 2.6.24

...全文
162 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
littlehedgehog 2008-11-11
  • 打赏
  • 举报
回复
当时我也没想到 这里仅仅是定义了一个函数指针,并不是定义函数,也需要加上asmlinkage,确实没想到

这里反汇编出来看看,如下 这里是源代码


asmlinkage long hijack_mkdir(const char *pathname, int mode)
{
return orig_mkdir(pathname, mode);
}


如果这里我 定义了
static asmlinkage long (*orig_mkdir)(const char *pathname, int mode);  
也就是asmlinkage 加上了

反汇编出来结果是

00000000 <hijack_mkdir>:
0: 8b 0d 08 00 00 00 mov 0x8,%ecx
6: ff e1 jmp *%ecx
8: 90 nop
9: 8d b4 26 00 00 00 00 lea 0x0(%esi),%esi

gcc 做了优化,直接跳转到orig_mkdir指针指向的地址,也就是原mkdir的地址,这里没有压栈任何参数,不会应想到sys_mkdir调用


如果没有定义asmlinkage,如下

00000000 <hijack_mkdir>:
0: 8b 54 24 08 mov 0x8(%esp),%edx
4: 8b 44 24 04 mov 0x4(%esp),%eax
8: ff 15 08 00 00 00 call *0x8
e: f3 c3 repz ret


这里不知道为什么要重新设置edx,应该是为了传参数,gcc误以为这样可以优化调用过程,不过这里压栈了一个eip,而sys_mkdir又是采取的从栈中得参数,导致错误。


记下来,方便后面同学了
zkuang82 2008-11-11
  • 打赏
  • 举报
回复
不客气,其实我也是想知道答案而已。^_^
littlehedgehog 2008-11-11
  • 打赏
  • 举报
回复
好了,问题解决了,就是asmlinkage问题,上面那个是正确的代码,我郁闷

就是改 static asmlinkage long (*orig_mkdir)(const char *pathname, int mode); 注意加上asmlinkage,因为这个定义了这个函数是asmlinkage,表示要从堆栈取出参数

不过我觉得 这里调用也应该加上 return (asmlinkage)orig_mkdir(pathname, mode); 这里也加上asmlinkage,规范点儿,但是其实实际意义不大

另外感谢这位大哥了,呵呵



littlehedgehog 2008-11-11
  • 打赏
  • 举报
回复
难得兄弟这么热心,呵呵,我把代码贴出来,有位chinaunix朋友给我说是因为高版本内核中sys_call_tabel改为只读了,但是这里我在函数里面直接return 0,不调用任何参数那系统就没有问题,所以我也怀疑是参数调用问题,不过还好系统一直没有崩掉。

对了,asmlinkage表示从栈里面取数据,你确实说反了,没关系给了我一个思路

说明一下

1.这里我为了防止系统瘫痪,虽然是在虚拟机实验,但是也不想重启电脑,我加了个定时器,到时就替换回来原调用。
2. 虚拟机一直截获call_table出问题,主机可以的,所以这里我有个host宏。

代码没加注释 不好意思


#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <asm/unistd.h>
#include <asm/errno.h>

//#define HOST

MODULE_LICENSE("Dual BSD/GPL");

static void **hijack_sys_call_table;
static int (*orig_open)(const char *filename, int flags, int mode);
static asmlinkage long (*orig_mkdir)(const char *pathname, int mode);

static struct timer_list deamon_timer;

static struct {
unsigned short limit;
unsigned int base;
} __attribute__((packed)) idtr;

static struct {
unsigned short off_low;
unsigned short sel;
unsigned char none, flags;
unsigned short off_high;
} __attribute__((packed)) idt;



static asmlinkage long hijack_mkdir(const char *pathname, int mode)
{
printk("%s,%d\n",pathname,mode);
return (asmlinkage)orig_mkdir(pathname, mode);
}

static int get_sys_call_table(void)
{
unsigned int sys_call_off;
char* p;
int i;
// 获取中断描述符表寄存器的地址
asm("sidt %0":"=m"(idtr));
printk("addr of idtr: %x\n", &idtr);

// 获取0x80中断处理程序的地址
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
sys_call_off=((idt.off_high<<16)|idt.off_low);
printk("addr of idt 0x80: %x\n", sys_call_off);

// 从0x80中断服务例程中搜索sys_call_table的地址
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p[i]=='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{
hijack_sys_call_table=(void **)(*(unsigned int*)(p+i+3));
printk("addr of sys_call_table: %x\n", hijack_sys_call_table);
return 0;
}
}
return -1;
}

static void deamon_timer_handler(unsigned long arg)
{
printk("time out\n");
hijack_sys_call_table[__NR_mkdir]=orig_mkdir;
del_timer(&deamon_timer);
}

static void deamon_timer_init(struct timer_list *timer)
{
init_timer(timer);
timer->function=deamon_timer_handler;
timer->data=0;
timer->expires=jiffies+HZ*20;
add_timer(timer);
}

static int hijack_init()
{
printk("init module\n");
#ifdef HOST
if(get_sys_call_table() == -1)
{
printk("check sys_call_table failed!\n");
return -1;
}
#else
hijack_sys_call_table = (void **)0xc0325500;
#endif
printk("now initialize timer\n");
deamon_timer_init(&deamon_timer);

orig_mkdir=hijack_sys_call_table[__NR_mkdir];
hijack_sys_call_table[__NR_mkdir]=hijack_mkdir;

return 0;
}

static void hijack_exit()
{
printk("bye hijack\n");
hijack_sys_call_table[__NR_mkdir]=orig_mkdir;
return ;
}

module_init(hijack_init);
module_exit(hijack_exit);




这里兄弟帮我看看,我觉得确实像栈参数问题,比如有个要维持栈平衡





zkuang82 2008-11-11
  • 打赏
  • 举报
回复
不好意思,似乎说反了。asmlinkage要求编译器不要在寄存器中找参数,一定要到栈中。
能不能把你实验的结果说一下,如果你不用asmlinkage声明你orig_mkdir,你的实验成功吗?
zkuang82 2008-11-11
  • 打赏
  • 举报
回复
这个接口应该不会有问题,估计有问题的是orig_mkdir。
如果你直接用orig_mkdir,那么他的参数是压栈的。但如果它声明成asmlikage的话,那么它就到寄存器去找参数了。只是猜测而已。因为这并不是从user space到kernel space的入口点,真正的入口在sysenter_entry,它应该会处理参数传递的问题。但你的实验不成功,让人觉得asmlinkage这个关键字有问题。
littlehedgehog 2008-11-11
  • 打赏
  • 举报
回复
补充下,如果我直接用

static asmlinkage long hijack_mkdir(const char *pathname, int mode)
{
return 0 ;
}


这样不会出问题,每次创建不成功,系统也没有故障
littlehedgehog 2008-11-10
  • 打赏
  • 举报
回复
sys_mkdir确实是asmlinkage,这个问题我确实还没考虑到,我先来试试
zkuang82 2008-11-10
  • 打赏
  • 举报
回复
会不会跟这个关键字有关:asmlinkage?我说的是orig_mkdir,他应该也是asmlinkage的吧。
系统掉用对参数的传递方式有要求,用什么寄存器之类的,具体的我不记得了。所以如果orig_mkdir也用这样的关键字,会不会出问题?如果orig_mkdir的确用了asmlinkage方式,试试去掉。

4,436

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧