Chinaunix首页 | 论坛 | 博客
  • 博客访问: 153792
  • 博文数量: 32
  • 博客积分: 2053
  • 博客等级: 大尉
  • 技术积分: 382
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-09 12:45
文章分类

全部博文(32)

文章存档

2011年(12)

2010年(20)

分类: LINUX

2010-11-16 20:16:25

感谢
1.godbach大神
2.http://technica.blogbus.com/logs/18945123.html

module代码

syscall.c

#include <linux/sched.h>
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
#define __NR_newhandler 223
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;
unsigned int* syscall_table;
unsigned int old_handler;
unsigned int get_sys_call_table(void)
{
    unsigned int sys_call_off;
    unsigned int sys_call_table;
    char *p;
    int i;
    //获得中断描述符表寄存器地址

    asm("sidt %0":"=m"(idtr));
    printk("add of idtr %x\n", idtr.base);
    //获取0x80中断处理程序的地址

    memcpy(&idt, idtr.base + 8 * 0x80, sizeof(idt));
    sys_call_off = ((idt.off2 << 16) | idt.off1 );
    printk("addr of idt 0x80 %x\n", sys_call_off);
    //从0x80中断处理程序的二进制代码中搜索sys_call_table地址    

    p = sys_call_off;
    for(i = 0; i < 100; i++)
    {
        //0xff 0x14 0x85暂时不明白是什么特殊的汇编代码

        if(p[i] == '\xff' && p[i+1] == '\x14' && p[i+2] == '\x85')
        {
            sys_call_table = *(unsigned int*)(p + i + 3);
            printk("addr of sys_call_table %x\n", sys_call_table);
            return sys_call_table;
        }
    }
    return 0;
}
asmlinkage long sys_newhandler(void)
{
    printk("hello I'm new handler\n");
    return 0;
}
unsigned int clear_and_return_cr0(void)
{
    unsigned int cr0 = 0;
    unsigned int ret;
    asm("movl %%cr0 ,%%eax":"=a"(cr0));
    ret = cr0;
    //清除cr0的WP(Write Protect)标志位

    cr0 &= 0xfffeffff;//第16位为WP

    asm("movl %%eax, %%cr0"::"a"(cr0));
    return ret;
}
void setback_cr0(unsigned int val)
{
    asm("movl %%eax, %%cr0"::"a"(val));
}
static int hello_init(void)
{
    printk(KERN_ALERT "hello world\n");
    
    syscall_table = (unsigned int*) get_sys_call_table();
    if(syscall_table == 0)
    {
        printk("can't find syscall_table addr\n");
        return 0;
    }
    old_handler = syscall_table[__NR_newhandler];
    printk("addr of old_handler %x\n", old_handler);
    unsigned int orig_cr0 = clear_and_return_cr0();
    syscall_table[__NR_newhandler] = (unsigned long) sys_newhandler;
    setback_cr0(orig_cr0);
    return 0;
}
static void hello_exit(void)
{
    unsigned int orig_cr0 = clear_and_return_cr0();
    syscall_table[__NR_newhandler] = (unsigned long) old_handler;
    setback_cr0(orig_cr0);
    printk(KERN_ALERT "hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);


Makefile

ifneq ($(KERNELRELEASE),)
        obj-m := syscall.o
else
        KERNELDIR ?=/lib/modules/$(shell uname -r)/build
        PWD := $(shell pwd)
default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
        rm *.mod.c *.o *.order *.symvers
endif
.PHONY:clean
clean:
        -rm *.mod.c *.o *.order *.symvers *.ko .*



用户态测试文件
user.c


#include <unistd.h>
#include <errno.h>
#define __NR_newhandler 223

#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name)); \
if (__res >= 0) \
        return (type) __res; \
errno = -__res; \
return -1; \
}

_syscall0(int, newhandler)

int main()
{
    newhandler();
    return 0;
}


1.生成模块文件
make
2.加载
sudo insmod syscall.ko
3.编译user.c
gcc user.c -o user
4.运行user
./user
5.查看dmesg
dmesg

[ 6061.492687] hello world
[ 6061.492694] add of idtr c0761000
[ 6061.492696] addr of idt 0x80 c01033a0
[ 6061.492699] addr of sys_call_table c0593150
[ 6061.492701] addr of old_handler c0167e20
[ 6065.754162] hello I'm new handler


6.删除模块
sudo rmmod syscall
7.查看dmesg
dmesg

[ 6061.492687] hello world
[ 6061.492694] add of idtr c0761000
[ 6061.492696] addr of idt 0x80 c01033a0
[ 6061.492699] addr of sys_call_table c0593150
[ 6061.492701] addr of old_handler c0167e20
[ 6065.754162] hello I'm new handler
[ 6067.688628] hello exit


输出hello I'm new handler表明新添的syscall已成功call了

备注
在linux源代码linxu-source-2.6.32/arch/x86/kernel/entry_32.S有0x80中断处理程序的汇编代码,其中有一行如下

call *sys_call_table(,%eax,4)


为了得到它的二进制码,测试如下
syscall.s

.section .data
sys_call_table:
        .ascii "hello,syscall!!!!\n"
.section .text
.globl _start
_start:
        call *sys_call_table(, %eax,4)

编译链接如下

wj@wj-laptop:~/work/test$ as -o syscall.o syscall.s
wj@wj-laptop:~/work/test$ ld -o syscall syscall.o
wj@wj-laptop:~/work/test$ objdump -d ./syscall

./syscall: file format elf32-i386


Disassembly of section .text:

08048074 <_start>:
 8048074: ff 14 85 7c 90 04 08 call *0x804907c(,%eax,4)

上图中ff 14 85即是程序中搜索sys_call_table地址时用的搜索词,后面便是它的地址了
阅读(2793) | 评论(1) | 转发(1) |
0

上一篇:syscall

下一篇:【转载】linux内核文件读写

给主人留下些什么吧!~~

chinaunix网友2010-11-17 16:43:21

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com