linux kernel hook


简介

好久都没搞linux的kernel了,记录一下

Makefile

CONFIG_MODULE_SIG=n
obj-m += hook_test.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

CONFIG_MODULE_SIG=n是针对module verification failed: signature and/or required key missing - tainting kernel的最简单方法,或者直接进行签名

常用命令

  • 插入模块 insmod
  • 查看模块 lsmod
  • 查看信息 dmesg
  • 卸载模块 rmmod
  • 载入模块 modprobe -a

对于printk直接输出到termianl

dmesg -wH &

然后运行模块

对于指定等级的输出

dmesg -wH | grep ERR &

在内核源码中使用
printk(KERN_EMERG "ERROR!\n");

对于syscall的hook

#include<linux/init.h>
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/unistd.h>
#include<linux/sched.h>
#include<linux/syscalls.h>
#include<linux/string.h>
#include<linux/fs.h>
#include<linux/fdtable.h>
#include<linux/uaccess.h>
#include <linux/kallsyms.h>
#include<linux/rtc.h>
#include<linux/vmalloc.h>
#include <linux/slab.h>

//module macros
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("hook sys_mkdir");

//module constructor/destructor
typedef unsigned long (*sys_call_ptr_t)(void);
sys_call_ptr_t *_sys_call_table = NULL;

typedef asmlinkage long (*old_mkdir_t)(const char __user *pathname, umode_t mode);
old_mkdir_t old_mkdir = NULL;

// hooked mkdir function
asmlinkage long hooked_mkdir(const char __user *pathname, umode_t mode) {

        printk("hooked sys_mkdir(), mkdir name: ");
        printk(pathname);
        old_mkdir(pathname, mode);
}

// memory protection shinanigans
unsigned int level;
pte_t *pte;

//obtain sys_call_table
static int get_sys_call_table(void){
    unsigned long tmp_sys_call_table = 0;
    int ans = 0;

    tmp_sys_call_table = kallsyms_lookup_name("sys_call_table");
    if(tmp_sys_call_table != 0)
    {
        ans = 1;
        _sys_call_table = tmp_sys_call_table;
        printk("[+] find sys_call_table: 0x%lx\n", tmp_sys_call_table);
    }
    return ans;
}
// initialize the module
static int hooked_init(void) {
    printk("+ Loading hook_mkdir module\n");
    if(!get_sys_call_table()){
        return 0;
    }
    // now we can hook syscalls ...such as uname
    // first, save the old gate (fptr)
    old_mkdir = (old_mkdir_t) _sys_call_table[__NR_mkdir];

    // unprotect sys_call_table memory page
    pte = lookup_address((unsigned long) _sys_call_table, &level);

    // change PTE to allow writing
    set_pte_atomic(pte, pte_mkwrite(*pte));

    printk("+ unprotected kernel memory page containing sys_call_table\n");

    // now overwrite the __NR_uname entry with address to our uname
    _sys_call_table[__NR_mkdir] = (sys_call_ptr_t) hooked_mkdir;

    printk("+ sys_mkdir hooked!\n");

    return 0;
}

static void hooked_exit(void) {
    if(old_mkdir != NULL) {
        // restore sys_call_table to original state
        _sys_call_table[__NR_mkdir] = (sys_call_ptr_t) old_mkdir;

        // reprotect page
        set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW));
    }

    printk("+ Unloading hook_mkdir module\n");
}

/*entry/exit macros*/
module_init(hooked_init);
module_exit(hooked_exit);

对于vdso的hook

利用漏洞

  • 利用内核漏洞rce改到用户态可写,然后修改vdso
  • 利用内核任意写漏洞进行修改vdso

前提是,你得有能用的内核洞!!!!!

修改源码

直接修改linux内核源码,重新编译

修改sources.list

sed -i 's/# deb-src/deb-src/g' /etc/apt/sources.list;

获取源码

apt-cache search linux-source
apt-get source linux-source-5.4.0

or

apt-get install linux-source-5.4.0

编译过程

sudo su;
apt-get install -y build-essential kernel-package bison libncurses5-dev libssl-dev build-essential openssl zlibc minizip libidn11-dev libidn11;
make mrproper && make clean && make menuconfig;
make -j8;
make modules_install;
make install;
reboot;

ubuntu18以上加上

apt-get install flex libelf-dev;

需要精简一点的话

make localmodconfig
make menuconfig

联合起来

make mrproper && make clean && make localmodconfig && time make -j40 && make modules_install && make install && reboot

make mrproper && make clean && make localmodconfig && time make -j32 && make modules_install && make install && reboot

make mrproper && make clean && make localmodconfig && time make -j24 && make modules_install && make install && reboot

make mrproper && make clean && make localmodconfig && time make -j16 && make modules_install && make install && reboot

make mrproper && make clean && make localmodconfig && time make -j12 && make modules_install && make install && reboot

make mrproper && make clean && make localmodconfig && time make -j8 && make modules_install && make install && reboot

顺便丢一个编译时间的表,以后参考,都是ubuntu20.04.1,可能有其他因素影响,比如硬盘io

CPU 编译线程数 时间
E5-2660v2*2 40 326
I7-8700K 12 243
I7-4790(hdd) 8 2471

文章作者: xyzz
文章链接: http://www.xyzzpwn.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 xyzz !
 上一篇
esxi迁移虚拟机 esxi迁移虚拟机
简介原来的esxi进行淘汰处理,需要将里面数据迁移出来,等新的服务器到了迁移过去esxi: 122t raid6备份机器: 7t hdd新esxi:82t raid6 虚拟机先发现资源池和vm ovftool vi://root:{
2020-09-28
下一篇 
ubuntu编译安装qemu ubuntu编译安装qemu
简介通过ubuntu编译安装qemu ubuntu20.04.1 qemu v5.1.50 源码https://github.com/qemu/qemu.git 安装依赖apt-get install -y htop gcc g++
2020-09-10
  目录