Chinaunix首页 | 论坛 | 博客
  • 博客访问: 287703
  • 博文数量: 56
  • 博客积分: 3025
  • 博客等级: 中校
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-06 17:28
个人简介

Honesty and diligence should be your eternal mates.

文章分类

全部博文(56)

文章存档

2012年(1)

2011年(27)

2010年(20)

2008年(8)

分类: LINUX

2010-12-06 19:31:32

/*以苏师姐给的程序说明*/

一、步骤概览:

编写系统调用服务例程——>添加系统调用号——>修改系统调用表——>重新编译内核并测试新添加的系统调用。

   如果重新编译内核的话需要很长的时间,我们可以将系统调用服务例程作为模块加载进内核。当然,这样做的代价是复杂化了第二和第三步。

二、实现过程:

1、编写模块程序(包含前三步):

#include
#include
#include
#include

#define SYS_CALL_TABLE_ADDRESS 0xc0594150 //这个是系统调用表的地址,可通过
                                      grep sys_call_table /proc/kallsyms
                                            命令查看。 

#define NUM 223                           //宏定义系统调用号

int orig_cr0;                             //用于保存初始的CR0寄存器的值
unsigned long *sys_call_table_my = 0;     //存放系统调用表起始地址
static int (*anything_saved)(void);       //定义一个函数指针,用于保存223号系统调用在系统调用表中的内容

/*由于控制寄存器CR0的第16若置位,则表示禁止系统进程写只有只读权限的页面(sys_call_table),所以我们给sys_call_table添加内容的话就必须将CR0的第16位清零,在模块卸载的时候给还原*/

static int clear_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret;

asm volatile ("movl %%cr0, %%eax":"=a"(cr0)); //汇编代码,用于取出                                                          CR0寄存器的值
ret = cr0;
cr0 &= 0xfffeffff;                            
asm volatile ("movl %%eax, %%cr0": :"a"(cr0));//汇编代码,将修改后的                                                        CR0值写入CR0寄存器
return ret;               //返回初始的CR0值
}

/*改回原CR0寄存器的值*/

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

/*系统调用服务例程,打印当前进程的PID和进程名,返回当前进程的PID*/

asmlinkage long sys_mycall(void)
{
printk("I am mycall, current->pid: %d,and current->comm:%s\n", current->pid, current->comm);
return current->pid;
}

static int __init call_init(void)
{
sys_call_table_my = (unsigned long*)(SYS_CALL_TABLE_ADDRESS);
printk("call_init...\n");

anything_saved = (int (*)(void))(sys_call_table_my[NUM]);
orig_cr0 = clear_cr0();
sys_call_table_my[NUM] = (unsigned long) &sys_mycall;
setback_cr0(orig_cr0);

return 0;

}

static void __exit call_exit(void)
{
printk("call exit...\n");
orig_cr0 = clear_cr0();
sys_call_table_my[NUM] = (unsigned long)anything_saved;
setback_cr0(orig_cr0);
}

MODULE_LICENSE("GPL");
module_init(call_init);
module_exit(call_exit);

2、用户态下的验证程序:

#include
#include

int main()
{
unsigned long x = 0;
x = syscall(223);   //用户态下的程序可以调用该函数直接访问系统调用
printf("Hello,%ld\n", x);
return 0;
}


阅读(3792) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

Dalwin2012-12-02 10:19:46

在这居然能看到师哥哈哈