linux hook 初探

下面是一段代码可以实现系统调用的替换  linux 内部的系统调用 sys_mkdir :(code.c)

   系统调用作为一个数组放在一个系统调用表sys_call_table之中, 由于sys_call_table在不同主机上的地址是不一样的。我们的直接赋值的办法是行不通的。那么我们就需要通过其他方式获取了。


   具体的获取思路如下:每一个系统调用都是通过int 0x80中断进入核心,中断描述符表把中断服务程序和中断向量对应起来。对于系统调用来说,

操作系统会调用 system_call中断服务程序。system_call函数在系统调用表中根据系统调用号找到并调用相应的系统调用服务例程。

idtr寄存器指向 中断描述符表 的起始地址,用sidt[asm ("sidt %0" : "=m" (idtr));]指令得到中断描述符表起始地址,从这条指令中得到的指针可以获得int 0x80中断服描述符

所在位置,然后计算出system_call函数的地址反编译一下system_call函数可以看到在system_call函数内,是用call sys_call_table指令来调用系统调用函数的。

因此,只要找到system_call里 的call sys_call_table(,eax,4)指令的机器指令就可以获得系统调用表的入口地址了。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/unistd.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("gudujain");
MODULE_DESCRIPTION("Different from others, this module automatically locate the entry of sys_call_table !");

unsigned long 	*sys_call_table=NULL;
typedef	asmlinkage int (*type_orig_mkdir)(const char *,int);
type_orig_mkdir		orig_mkdir;

typedef	struct _idt
{
   unsigned short offset_low,segment_sel;
   unsigned char  reserved,flags;
   unsigned short offset_high;
}idt;

unsigned long *getscTable()
{
	unsigned char 	idtr[6],*shell,*sort;
       	idt 		*pidt;
       	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));         //通过sidt指令获取中断描述符表寄存器的地址,这里面包含有idt表的首地址

       /* get the address of system_call */
       pidt		= (idt *)(*(unsigned long*)&idtr[2]+8*0x80);
                                                 //通过idtr里面的idt的首地址+偏移获取0x80中断处理程序的地址,
       offset_low 	= pidt->offset_low;
       offset_high 	= pidt->offset_high;
       system_call	= (offset_high<<16)|offset_low;      //通过这项idt找到system_call的函数地址

       shell		= (char *)system_call;	 ///执行 int 0x80 之后到这个地址开始执行。
       sort		= "\xff\x14\x85";
       ///  shell 指向的地址包含如下指令:
       ///  0xc0106bf2 <system_call+42>: jne 0xc0106c48 <tracesys>
       ///  0xc0106bf4 <system_call+44>: call *0xc01e0f18(,%eax,4) 
       ///  0xc0106bfb <system_call+51>: mov %eax,0x18(%esp,1)
       ///  0xc0106bff <system_call+55>: nop
       ///  其中地址 0xc0106bf4 处指令   <system_call+44>:机器码是: 0x188514ff  (little endian)

       /* get the address of sys_call_table */
       for(i=0;i<(100-2);i++)
            if( (shell[i]==sort[0]) && (shell[i+1]==sort[1]) && (shell[i+2]==sort[2]) )
                     break;

       p		= &shell[i];
       p		+= 3;
       sct		= *(unsigned long*)p;

       return (unsigned long*)(sct);
}

asmlinkage int hacked_mkdir(const char * pathname, int mode)
{
       printk("PID %d called sys_mkdir !\n",current->pid);
       return orig_mkdir(pathname,mode);
}

static int __init find_init(void)
{
       	sys_call_table 		= getscTable();
      	printk("the sys_call_table address is:%x\n",sys_call_table);
       	orig_mkdir		=(type_orig_mkdir)sys_call_table[__NR_mkdir];
       	sys_call_table[__NR_mkdir]=(unsigned long)hacked_mkdir;
       	return 0;
}

static void __exit find_cleanup(void)
{
       sys_call_table[__NR_mkdir]=(unsigned long)orig_mkdir;
}

module_init(find_init);
module_exit(find_cleanup);

加载编译得到的内核模块  code.ko:

#insmod code.ko

测试是否成功:









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值