前面的文章有聊到怎么拿到linux sys_call_table,高版本和低版本内核都有对应的方式,那么这篇文章讲怎么去hook Linux 系统调用,建议在虚拟机中尝试,此篇文章内核如下所示:

curtis@curtis-virtual-machine:~/Desktop/test$ uname -a
Linux curtis-virtual-machine 4.2.0-42-generic #49~14.04.1-Ubuntu SMP Wed Jun 29 20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

代码:hook_read.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
#include <asm/paravirt.h>

unsigned long **sys_call_table;
unsigned long original_cr0;

asmlinkage long (*ref_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage long new_sys_read(unsigned int fd, char __user *buf, size_t count)
{
	/*do everything what you want*/
	printk("sys_read has benn hook!\n");
	return ref_sys_read(fd, buf, count);
}

//set a page writeable
int make_rw(unsigned long address)
{
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte |= _PAGE_RW;
    return 0;
}
 
//set a page read only
int make_ro(unsigned long address)
{ 
    unsigned int level;
    pte_t *pte = lookup_address(address, &level);
    pte->pte = pte->pte & ~_PAGE_RW;
    return 0;
}


//Consider race condition on SMP systems.
void
disable_wp(void)
{
    unsigned long cr0;

    preempt_disable();
    cr0 = read_cr0();
    clear_bit(X86_CR0_WP_BIT, &cr0);
    write_cr0(cr0);
    preempt_enable();

    return;
}

//Consider race condition on SMP systems.
void
enable_wp(void)
{
    unsigned long cr0;

    preempt_disable();
    cr0 = read_cr0();
    set_bit(X86_CR0_WP_BIT, &cr0);
    write_cr0(cr0);
    preempt_enable();

    return;
}

//find sys_call_table address
static unsigned long **acquire_sys_call_table(void)
{
    unsigned long int offset = (unsigned long int) sys_close;
    unsigned long **sct;
    
    printk(KERN_INFO "finding syscall table from: %p\n", (void*)offset);

    while (offset < ULLONG_MAX)
    {
    	sct = (unsigned long **)offset;

    	if (sct[__NR_close] == (unsigned long *)sys_close)
        {
            printk(KERN_INFO "sys call table found: %p\n", (void*)sct);
    		return sct;
        }
    	offset += sizeof(void *);
    }

    return NULL;
}


static int __init read_hook_start(void) 
{
	if(!(sys_call_table = acquire_sys_call_table()))
		return -1;
	printk("sysc_call_table address:%p\n",(void *)sys_call_table);	
//	original_cr0 = read_cr0();
	printk("cr0 value is:0x%ld\n",read_cr0());
//	disable_wp();
//	write_cr0(original_cr0 & ~0x000100000);
	make_rw((long unsigned int)sys_call_table);
	ref_sys_read = (void *)sys_call_table[__NR_read];
	printk("sys_open address is :%p\n",ref_sys_read);
	sys_call_table[__NR_read] = (unsigned long *)new_sys_read;
	printk("Nes sys_open address is :%p\n",(void*)sys_call_table[__NR_read]);
	make_ro((long unsigned int)sys_call_table);
//	write_cr0(original_cr0);
//	enable_wp();
	
	return 0;
}

static void __exit read_hook_end(void) 
{
	if(!sys_call_table) {
		return;
	}

//	disable_wp();	
//	write_cr0(original_cr0 & ~0x00010000);
	make_rw((long unsigned int)sys_call_table);
	sys_call_table[__NR_read] = (unsigned long *)ref_sys_read;
	make_ro((long unsigned int)sys_call_table);
//	write_cr0(original_cr0);
//	enable_wp();
	
	printk("Bye bye test!\n");
}

module_init(read_hook_start);
module_exit(read_hook_end);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Curtis li");

Makefile:

obj-m :=hook_read.o
KERNEL := /lib/modules/$(shell uname -r)/build
 
all:
	make -C $(KERNEL) M=$(shell pwd) modules
install:
	make -C $(KERNEL) M=$(shell pwd) modules_install
	depmod -A
clean:
	make -C $(KERNEL) M=$(shell pwd) clean

简要代码分析:
初始化函数通过以sys_close为基址遍历内存找到sys_call_table地址,拿到地址后,需要解决的是内核内存写保护的问题,代码中分别给到三种方法来关闭内存的写保护,实际上是两种,一种是改pte参数,一种是修改cr0寄存器的值(两种方法实现),先要定义好open的原始函数和open_hook函数,在open_hook函数中可以做自己想做的事情,但是一定要记得返回到原始open函数入口地址。
效果展示:

[  584.867416] sys_read has benn hook!
[  584.867416] sys_read has benn hook!
[  584.867417] sys_read has benn hook!
[  584.867418] sys_read has benn hook!
[  584.867418] sys_read has benn hook!
[  584.868939] sys_read has benn hook!
[  584.868951] sys_read has benn hook!
[  584.869104] sys_read has benn hook!
[  584.869259] sys_read has benn hook!
[  584.869261] sys_read has benn hook!
[  584.869277] sys_read has benn hook!
[  584.869279] sys_read has benn hook!
[  584.869288] sys_read has benn hook!
[  584.869289] sys_read has benn hook!
[  584.869294] Bye bye test!

open函数被成功Hook住,此文章介绍的是低内核版本的open_hook,高版本获取sys_call_table的值方式不一样,可以参考之前文章!!!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐