2

I want to intercept the open() syscall, for testing each time a file is opened by the user, the message “OPEN IS!” should be displayed in dmesg.

The syscall table and open-call addresses in dmesg are displayed, but the message “OPEN IS!” is not visible. Kernel v. 4.18

I would like to know what the problem is. The code:

unsigned long cr0;
static unsigned long *__sys_call_table;

typedef asmlinkage int (*orig_open_t)(const char *, int, int);

orig_open_t orig_open;

unsigned long *
get_syscall_table_bf(void)
{
    unsigned long *syscall_table;
    unsigned long int i;

    for (i = (unsigned long int)ksys_close; i < ULONG_MAX;
            i += sizeof(void *)) {
        syscall_table = (unsigned long *)i;

        if (syscall_table[__NR_close] == (unsigned long)ksys_close) {
            printk(KERN_INFO "syscall: %08lx\n", syscall_table);
            return syscall_table;
        }
    }
    return NULL;
}

asmlinkage int
hacked_open(const char *filename, int flags, int mode)
{
    printk(KERN_INFO "OPEN IS!\n");
    return 0;
}

static inline void
protect_memory(void)
{
    write_cr0(cr0);
}

static inline void
unprotect_memory(void)
{
    write_cr0(cr0 & ~0x00010000);
}

static int __init
diamorphine_init(void)
{
    __sys_call_table = get_syscall_table_bf();
    if (!__sys_call_table)
        return -1;

    cr0 = read_cr0();

    orig_open = (orig_open_t)__sys_call_table[__NR_open];

    unprotect_memory();
    __sys_call_table[__NR_open] = (unsigned long)hacked_open;
    printk(KERN_INFO "WE DO IT!\n");
    printk(KERN_INFO "hacked is: %08lx\n", hacked_open);
    protect_memory();

    return 0;
}

static void __exit
diamorphine_cleanup(void)
{
    unprotect_memory();
    __sys_call_table[__NR_open] = (unsigned long)orig_open;
    protect_memory();
}

module_init(diamorphine_init);
module_exit(diamorphine_cleanup);

MODULE_LICENSE("GPL");
red0ct
  • 4,840
  • 3
  • 17
  • 44
  • Do you know what is hijacking? – 69 420 1970 Dec 01 '18 at 12:49
  • Why do you not just recompile Linux Kernel with your changes? – Vladimir Pustovalov Dec 04 '18 at 16:20
  • Why don't you just use *`ftrace`* or *`kprobes`*? Some info: [1](https://stackoverflow.com/questions/52764544/how-to-trace-just-system-call-events-with-ftrace-without-showing-any-other-funct/52775914#52775914) and [2](https://stackoverflow.com/questions/53267342/adding-dynamic-tracepoint-through-perf-in-linux-for-function-that-is-not-listed/53421940#53421940). Or your goal is foremost to write some kernel code for yourself? – red0ct Dec 05 '18 at 23:07

1 Answers1

1

I'm guessing something in your hooking is wrong. Either you're hooking a wrong offset of the syscall table or you're completely off. I couldn't understand why explicitly you start searching with ksys_close(), especially when it's an inlined function. You should try looking for the syscall table symbol as such:

typedef void (*_syscall_ptr_t)(void); 
_syscall_ptr_t *_syscall_table = NULL; 
_syscall_table=(_syscall_ptr_t *)kallsyms_lookup_name("sys_call_table");

A different (huge) issue I see with this is resetting CR0, which allows anything within your system to write to a read only memory at the time of your writing, instead of page-walking and setting the W bit on the specific page you're about to edit.

Additional one small word of advice: You should complete your hook to redirect to the original open syscall. Otherwise, you'll result in the entire system reading from STDIN for every newly opened file descriptor (which will kill your system, eventually)

Creator
  • 401
  • 2
  • 9