c - Linux Kernel: System call hooking example -
i'm trying write simple test code demonstration of hooking system call table.
"sys_call_table" no longer exported in 2.6, i'm grabbing address system.map file, , can see correct (looking through memory @ address found, can see pointers system calls).
however, when try modify table, kernel gives "oops" "unable handle kernel paging request @ virtual address c061e4f4" , machine reboots.
this centos 5.4 running 2.6.18-164.10.1.el5. there sort of protection or have bug? know comes selinux, , i've tried putting in permissive mode, doesn't make difference
here's code:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/unistd.h> void **sys_call_table; asmlinkage int (*original_call) (const char*, int, int); asmlinkage int our_sys_open(const char* file, int flags, int mode) { printk("a file opened\n"); return original_call(file, flags, mode); } int init_module() { // sys_call_table address in system.map sys_call_table = (void*)0xc061e4e0; original_call = sys_call_table[__nr_open]; // hook: crashes here sys_call_table[__nr_open] = our_sys_open; } void cleanup_module() { // restore original call sys_call_table[__nr_open] = original_call; }
i found answer myself.
http://www.linuxforums.org/forum/linux-kernel/133982-cannot-modify-sys_call_table.html
the kernel changed @ point system call table read only.
cypherpunk:
even if late solution may interest others too: in entry.s file find: code:
.section .rodata,"a" #include "syscall_table_32.s"sys_call_table -> readonly have compile kernel new if want "hack" around sys_call_table...
the link has example of changing memory writable.
nasekomoe:
hi everybody. replies. solved problem long ago modifying access memory pages. have implemented 2 functions upper level code:
#include <asm/cacheflush.h> #ifdef kern_2_6_24 #include <asm/semaphore.h> int set_page_rw(long unsigned int _addr) { struct page *pg; pgprot_t prot; pg = virt_to_page(_addr); prot.pgprot = vm_read | vm_write; return change_page_attr(pg, 1, prot); } int set_page_ro(long unsigned int _addr) { struct page *pg; pgprot_t prot; pg = virt_to_page(_addr); prot.pgprot = vm_read; return change_page_attr(pg, 1, prot); } #else #include <linux/semaphore.h> int set_page_rw(long unsigned int _addr) { return set_memory_rw(_addr, 1); } int set_page_ro(long unsigned int _addr) { return set_memory_ro(_addr, 1); } #endif // kern_2_6_24
here's modified version of original code works me.
#include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/unistd.h> #include <asm/semaphore.h> #include <asm/cacheflush.h> void **sys_call_table; asmlinkage int (*original_call) (const char*, int, int); asmlinkage int our_sys_open(const char* file, int flags, int mode) { printk("a file opened\n"); return original_call(file, flags, mode); } int set_page_rw(long unsigned int _addr) { struct page *pg; pgprot_t prot; pg = virt_to_page(_addr); prot.pgprot = vm_read | vm_write; return change_page_attr(pg, 1, prot); } int init_module() { // sys_call_table address in system.map sys_call_table = (void*)0xc061e4e0; original_call = sys_call_table[__nr_open]; set_page_rw(sys_call_table); sys_call_table[__nr_open] = our_sys_open; } void cleanup_module() { // restore original call sys_call_table[__nr_open] = original_call; }
Comments
Post a Comment