나는 시스템 호출(예: )을 연결하는 것을 목표로 학습 목적으로 다음 LKM을 작성했습니다 openat(2)
.
문제는 후크를 성공적으로 비활성화 CR0.WP
하고 설정한 후 sys_call_table[__NR_openat]
시스템이 정지된다는 것입니다.
Linux 커널에 대해 깊은 지식을 갖고 있는 사람이라면 누구나 이런 일이 발생하는 이유에 대해 논평할 수 있습니까?
노트:
LKM을 실행하려면 CAP_SET_EMPTY_OFFSET
및 커널의 해당 오프셋으로 바꾸거나 SYS_CALL_TABLE_OFFSET
얻은 주소를 하드코딩해야 합니다.sys_call_table
sudo cat /proc/kallsyms | grep sys_call_table
암호:
#include <linux/module.h> /* Needed by all modules */
#include <linux/syscalls.h>
#include <linux/capability.h>
#include <linux/set_memory.h> /* Needed by set_memory_rw */
/*
* Avoid tainting the kernel, however the kernel will still be tainted if the
* module is not signed
*/
MODULE_LICENSE("GPL");
#define CAP_SET_EMPTY_OFFSET 0x45fe0
#define SYS_CALL_TABLE_OFFSET 0x2e0
static unsigned long* __sys_call_table;
unsigned long *find_sys_call_table(void)
{
unsigned long rodata_start;
rodata_start = (unsigned long)&__cap_empty_set - CAP_SET_EMPTY_OFFSET;
return (unsigned long*)(rodata_start + SYS_CALL_TABLE_OFFSET);
}
static inline void __write_cr0(unsigned long val)
{
asm volatile ("mov %0, %%cr0": : "r" (val));
}
static inline void disable_write_protection(void)
{
preempt_disable();
barrier();
__write_cr0(read_cr0() & (~ 0x00010000));
}
static inline void enable_write_protection(void)
{
__write_cr0(read_cr0() | 0x00010000);
barrier();
preempt_enable();
}
typedef asmlinkage long (*orig_openat_t)(int, const char*, int, umode_t);
orig_openat_t orig_openat;
asmlinkage long
hooked_openat(int dirfd, const char __user* pathname, int flags, umode_t mode)
{
//printk(KERN_INFO "%s: hooked openat\n", __func__);
return orig_openat(dirfd, pathname, flags, mode);
}
static int __init syscall_init(void)
{
printk(KERN_DEBUG "%s: started\n", __func__);
printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());
__sys_call_table = find_sys_call_table();
printk(KERN_INFO "%s: __sys_call_table: %px\n", __func__, __sys_call_table);
orig_openat = (orig_openat_t)__sys_call_table[__NR_openat];
printk(KERN_INFO "%s: orig_openat: %px\n", __func__, (void*)orig_openat);
disable_write_protection();
printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());
__sys_call_table[__NR_openat] = (unsigned long)hooked_openat;
printk(KERN_INFO "%s: hooked_openat: %px\n", __func__, (void*)hooked_openat);
enable_write_protection();
printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());
return 0;
}
static void __exit syscall_release(void)
{
disable_write_protection();
__sys_call_table[__NR_openat] = (unsigned long)orig_openat;
enable_write_protection();
printk(KERN_DEBUG "%s: exited\n", __func__);
}
/* set the entry point of the module */
module_init(syscall_init);
/* set the exit point of the module */
module_exit(syscall_release);
답변1
orig_openat
문제는 필요한 곳에 설정하지 않는다는 것입니다.
orig_openat = (orig_openat_t) _sys_call_table[__NR_openat];
_sys_call_table[__NR_openat] = (unsigned long)hooked_openat;
전화를 끊을 때.