现在的位置: 首页 > 综合 > 正文

linux内核系统调用hook

2013年09月14日 ⁄ 综合 ⁄ 共 2855字 ⁄ 字号 评论关闭

我以前利用0x80中断程序找到system_call然后找到 sys_call_table的方法,现在试下hook系统调用sys_mkdir来阻止创建目录小试牛刀。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
MODULE_LICENSE("Dual BSD/GPL");

#define _DEBUG
#ifdef _DEBUG
#define kprintk(fmt,args...) printk(KERN_DEBUG fmt,##args)
#define kprintf(fmt,args...) printf(fmt,##args)
#define kperror(str) perror(str)
#else
#define kprintk
#define kprintf
#define kperror
#endif


long g_old_sys_mkdir=0;
long * g_sys_call_table=NULL;
long g_oldcr0=0;

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

// 中断描述符表结构
struct _idt_descriptor
{
unsigned short offset_low;
unsigned short sel;
unsigned char none, flags;
unsigned short offset_high;
} __attribute__((packed));

unsigned int close_cr(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 open_cr(unsigned int oldval)
{
asm volatile ("movl %%eax, %%cr0"
:
: "a"(oldval)
);
}

long * get_sys_call_table(void)
{

struct _idt_descriptor * idt;
struct _idtr idtr;
unsigned int sys_call_off;
int sys_call_table=0;
unsigned char* p;
int i;

asm("sidt %0":"=m"(idtr));
printk("addr of idtr: 0x%x\n", (unsigned int)&idtr);
idt=(struct _idt_descriptor *)(idtr.base+8*0x80);
sys_call_off=((unsigned int )(idt->offset_high<<16)|(unsigned int )idt->offset_low);
printk("addr of idt 0x80: 0x%x\n", sys_call_off);
p=(unsigned char *)sys_call_off;
for (i=0; i<100; i++)
{
if (p[i]==0xff && p[i+1]==0x14 && p[i+2]==0x85)
{
sys_call_table=*(int*)((int)p+i+3);
kprintk("addr of sys_call_table: 0x%x\n", sys_call_table);
return (long*)sys_call_table;
}
}
return 0;
}


//asmlinkage long my_sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count)

asmlinkage long my_sys_mkdir(const char __user *pathname, int mode)
{

kprintk("can't' mkidr ^ ^\n");
return -1;
}


void start_hook(void)
{
g_sys_call_table=get_sys_call_table();

if(!g_sys_call_table)
{
kprintk("get sys_call_table error");
return;
}
//检测获取到的地址是不是正确的
if (g_sys_call_table[__NR_close] != (unsigned long)sys_close)

kprintk("Incorrect sys_call_table address.\n");
return ;
}
g_old_sys_mkdir=g_sys_call_table[__NR_mkdir];
//hoot it
g_oldcr0=close_cr();
g_sys_call_table[__NR_mkdir]=my_sys_mkdir;
open_cr(g_oldcr0);
kprintk("new %08x %08x\n",(unsigned int)my_sys_mkdir,(unsigned int)g_sys_call_table[__NR_mkdir]);

}

int raider_init(void)
{
kprintk("raider init\n");
start_hook();
return 0;
}

void raider_exit(void)
{
kprintk("raider exit");
if(g_sys_call_table && g_old_sys_mkdir)
{
g_oldcr0=close_cr();
g_sys_call_table[__NR_mkdir]=g_old_sys_mkdir;
kprintk("restore %08x\n",(unsigned int)g_sys_call_table[__NR_mkdir]);
open_cr(g_oldcr0);
}
}


module_init(raider_init);
module_exit(raider_exit);

代码在2.6.28下测试通过。

可见,只要得到sys_call_table后,就能轻易的做很多手段,其实和windows下修改ssdt没有本质区别只是网上关于linux的实现大部分内核版本比较老,有的都不用改cr0的,所以我很奇怪,也许以前的内核版本可行吧.

其实通往内核的接口还有一个sysenter_entry,通过它也可以得到sys_call_table的,只是这个接口同样没有导出,要得到也得用特殊办法了.

抱歉!评论已关闭.