#include<linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include<linux/fs.h>
#include <linux/sched.h>
#define __NR_mycall 338
MODULE_LICENSE("GPL");
static int (*anything_saved)(void);
asmlinkage int sys_mycall()
{
printk("hello world\n");
return 100;
}
// 中断描述符表寄存器结构
struct {
unsigned short limit;
unsigned int base;
} __attribute__((packed)) idtr;
// 中断描述符表结构
struct {
unsigned short off1;
unsigned short sel;
unsigned char none, flags;
unsigned short off2;
} __attribute__((packed)) idt;
// 查找sys_call_table的地址
void change_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;
// 通过sidt指令获取中断描述符表寄存器的地址,这里面包含有idt表的首地址
asm("sidt %0":"=m"(idtr));
printk(KERN_ALERT "in addr of idtr: %x\n", &idtr);
// 通过idtr里面的idt的首地址+偏移获取0x80中断处理程序的地址,由于idt中的每个门是64位,所以要乘以8,系统调用是0x80项,所以偏移为8*0x80。
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
//通过这项idt找到system_call的函数地址
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "in addr of idt 0x80: %x\n", sys_call_off);
// 从0x80中断服务例程中搜索sys_call_table的地址,即通过找到第一个call指令的机器码8514ff来获取sys_call_table
p=sys_call_off;
for (i=0; i<100; i++)
{
if (p =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{
sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "in addr of sys_call_table: %x\n", sys_call_table);
//备份系统调用表中修改的那一项
anything_saved = (int(*)(void))(sys_call_table_address[__NR_mycall]);
//将这一项替换成自己的函数
sys_call_table_address[__NR_mycall] = (unsigned long)sys_mycall;
return ;
}
}
}
void undo_sys_call_table(void)
{
unsigned int sys_call_off;
unsigned int sys_call_table;
char* p;
int i;
// 获取中断描述符表寄存器的地址
asm("sidt %0":"=m"(idtr));
printk("out addr of idtr: %x\n", &idtr);
// 获取0x80中断处理程序的地址
memcpy(&idt, idtr.base+8*0x80, sizeof(idt));
sys_call_off=((idt.off2<<16)|idt.off1);
printk(KERN_ALERT "out 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 =='\xff' && p[i+1]=='\x14' && p[i+2]=='\x85')
{
sys_call_table=*(unsigned int*)(p+i+3);
unsigned int* sys_call_table_address = &sys_call_table;
printk(KERN_ALERT "out addr of sys_call_table: %x\n", sys_call_table);
//将系统调用表中这项还原回来
sys_call_table_address[__NR_mycall] = (unsigned long)anything_saved;
return ;
}
}
}
int __init init_addsyscall(void)
{
//模块被insmod后就调用这个函数修改sys_call_table
change_sys_call_table();
return 0;
}
void __exit exit_addsyscall(void)
{
//模块被rmmod后就还原sys_call_table
undo_sys_call_table();
}
module_init(init_addsyscall);
module_exit(exit_addsyscall);
下面是我的调用程序:
#include <linux/time.h>
#include <linux/unistd.h>
#include <stdio.h>
#define __NR_mycall 338
int main()
{
printf("%d\n",syscall(__NR_mycall));
return 0;
}
被这个问题弄晕了

