System Call Hooking

MySprtlty·2024년 3월 26일
0

Kernel

목록 보기
8/10

🏷️System Call Hooking

📌고려 사항

  • 현재 x86_64에서 (kernel version = 5.14.0) System Call Hooking시 고려해야 할 사항이 몇가지 있다.

1. system call wrapper

2. disable cr0 wp bit

  • control register의 write protection bit를 먼저 꺼야될 수도 있다.

3. KASLR

  • booting시 sys_call_table의 주소를 무작위로 바꾼다.
  • .config에서 끌 수 있다.

4. SMEP, SMAP

📌sys_read hooking example (kernel 5.14.0)

  • 아래 예시는 kernel 5.14.0 x86_64 아키텍처에서 수행했다.
/*
 * Hooking sys_read
 */

#define CR0_WP 0

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/moduleparam.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
#include <asm/ptrace.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mysprtlty");
MODULE_DESCRIPTION("System Call Hooking Test");
MODULE_VERSION("0.01");

typedef int (*sys_call_wrapper)(struct pt_regs *);
unsigned long sys_call_table;

#if CR0_WP
static unsigned long int cr0;
extern unsigned long int __force_order;

static inline void write_forced_cr0(unsigned long value)
{
  asm volatile("mov %0,%%cr0":"+r"(value),"+m"(__force_order));
}

static inline void zero_cr0_wp(void)
{
  write_forced_cr0(read_cr0() & (~0x10000));
}

static inline void one_cr0_wp(void)
{
  write_forced_cr0(read_cr0() | 0x10000);
}
#endif

/* get the address of sys_call_table */
static unsigned long int **acquire_sys_call_table(void)
{
	unsigned long int (*kallsyms_lookup_name)(const char *name);

	struct kprobe kp = {
		.symbol_name = "kallsyms_lookup_name",
	};

	if (register_kprobe(&kp) < 0){
		return NULL;
	}
	kallsyms_lookup_name = (unsigned long (*)(const char *name))kp.addr;
	unregister_kprobe(&kp);

	return (unsigned long int **)kallsyms_lookup_name("sys_call_table");
}

static int enable_page_rw(void *ptr)
{
	unsigned int level;

	pte_t *pte = lookup_address((unsigned long) ptr, &level);

	if(pte->pte &~_PAGE_RW){
		pte->pte |=_PAGE_RW;
	}

	return 0;
}

static int disable_page_rw(void *ptr)
{
	unsigned int level;

	pte_t *pte = lookup_address((unsigned long) ptr, &level);

	pte->pte = pte->pte &~_PAGE_RW;

	return 0;
}

/* original sys_read */ 
sys_call_wrapper orig_sys_read;

/* my_sys_read */
int my_sys_read(struct pt_regs *regs)
{
	static unsigned int count = 0;

	if(count < 5) {
    printk(KERN_INFO  "[+] my_sys_read is called %d times.", count + 1);
    count++;
    }

	return (*orig_sys_read)(regs);
}

static int __init hooking_sys_read_init(void) {
	printk(KERN_INFO "[+] hooking_sys_read module inserted successfully!\n");

	sys_call_table = acquire_sys_call_table();
	printk(KERN_INFO "[+] the address of sys_call_table = @%lx\n", sys_call_table);

	enable_page_rw((void *)sys_call_table);

	orig_sys_read = ((sys_call_wrapper *)sys_call_table)[__NR_read];

	if (!orig_sys_read) {
		return -1;
	}

	((sys_call_wrapper *)sys_call_table)[__NR_read] = my_sys_read;

	disable_page_rw((void *)sys_call_table);

	printk(KERN_INFO "[+] the address of orig_sys_read = %p", orig_sys_read);

	return 0;
}

static void __exit hooking_sys_read_exit(void)
{
	printk(KERN_INFO "[+] hooking_sys_read module unloaded\n");

	enable_page_rw((void *)sys_call_table);

	((sys_call_wrapper *)sys_call_table)[__NR_read] = orig_sys_read;

	disable_page_rw((void *)sys_call_table);
}

module_init(hooking_sys_read_init);
module_exit(hooking_sys_read_exit);

📌References

profile
2Co 4:7

0개의 댓글