Ich schreibe ein LKM, um die erweiterten Attribute einer Datei zu untersuchen, um festzustellen, ob sie geöffnet werden sollte oder nicht. Ich habe einen Insmode: Unbekanntes Symbol in der Modulausgabe. Ich kann nicht finden, was das verursacht. Modul unter:Insmod: Unbekanntes Symbol in der Modulausgabe
#include <linux/module.h> /* Needed by all kernel modules */
#include <linux/kernel.h> /* Needed for loglevels (KERN_WARNING, KERN_EMERG, KERN_INFO, etc.) */
#include <linux/init.h> /* Needed for __init and __exit macros. */
#include <linux/unistd.h> /* sys_call_table __NR_* system call function indices */
#include <linux/fs.h> /* filp_open */
#include <linux/slab.h> /* kmalloc */
#include <asm/paravirt.h> /* write_cr0 */
#include <asm/uaccess.h> /* get_fs, set_fs */
#include <linux/xattr.h>
#include <linux/dcache.h> /*dentry*/
#define PROC_V "/proc/version"
#define BOOT_PATH "/boot/System.map-"
#define MAX_VERSION_LEN 256
//https://tnichols.org/2015/10/19/Hooking-the-Linux-System-Call-Table/
unsigned long *syscall_table = NULL;
//unsigned long *syscall_table = (unsigned long *)0xffffffff81801400;
asmlinkage int (*original_open)(const char*, int flags, mode_t);
static int find_sys_call_table (char *kern_ver) {
char system_map_entry[MAX_VERSION_LEN];
int i = 0;
/*
* Holds the /boot/System.map-<version> file name as we build it
*/
char *filename;
/*
* Length of the System.map filename, terminating NULL included
*/
size_t filename_length = strlen(kern_ver) + strlen(BOOT_PATH) + 1;
/*
* This will point to our /boot/System.map-<version> file
*/
struct file *f = NULL;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs (KERNEL_DS);
printk(KERN_EMERG "Kernel version: %s\n", kern_ver);
filename = kmalloc(filename_length, GFP_KERNEL);
if (filename == NULL) {
printk(KERN_EMERG "kmalloc failed on System.map-<version> filename allocation");
return -1;
}
/*
* Zero out memory to be safe
*/
memset(filename, 0, filename_length);
/*
* Construct our /boot/System.map-<version> file name
*/
strncpy(filename, BOOT_PATH, strlen(BOOT_PATH));
strncat(filename, kern_ver, strlen(kern_ver));
/*
* Open the System.map file for reading
*/
f = filp_open(filename, O_RDONLY, 0);
if (IS_ERR(f) || (f == NULL)) {
printk(KERN_EMERG "Error opening System.map-<version> file: %s\n", filename);
return -1;
}
memset(system_map_entry, 0, MAX_VERSION_LEN);
/*
* Read one byte at a time from the file until we either max out
* out our buffer or read an entire line.
*/
while (vfs_read(f, system_map_entry + i, 1, &f->f_pos) == 1) {
/*
* If we've read an entire line or maxed out our buffer,
* check to see if we've just read the sys_call_table entry.
*/
if (system_map_entry[i] == '\n' || i == MAX_VERSION_LEN) {
// Reset the "column"/"character" counter for the row
i = 0;
if (strstr(system_map_entry, "sys_call_table") != NULL) {
char *sys_string;
char *system_map_entry_ptr = system_map_entry;
sys_string = kmalloc(MAX_VERSION_LEN, GFP_KERNEL);
if (sys_string == NULL) {
filp_close(f, 0);
set_fs(oldfs);
kfree(filename);
return -1;
}
memset(sys_string, 0, MAX_VERSION_LEN);
strncpy(sys_string, strsep(&system_map_entry_ptr, " "), MAX_VERSION_LEN);
//syscall_table = (unsigned long long *) kstrtoll(sys_string, NULL, 16);
//syscall_table = kmalloc(sizeof(unsigned long *), GFP_KERNEL);
//syscall_table = kmalloc(sizeof(syscall_table), GFP_KERNEL);
kstrtoul(sys_string, 16, &syscall_table);
printk(KERN_EMERG "syscall_table retrieved\n");
kfree(sys_string);
break;
}
memset(system_map_entry, 0, MAX_VERSION_LEN);
continue;
}
i++;
}
filp_close(f, 0);
set_fs(oldfs);
kfree(filename);
return 0;
}
/*
* We have to pass in a pointer to a buffer to store the parsed
* version information in. If we declare a pointer to the
* parsed version info on the stack of this function, the
* pointer will disappear when the function ends and the
* stack frame is removed.
*/
char *acquire_kernel_version (char *buf) {
struct file *proc_version;
char *kernel_version;
/*
* We use this to store the userspace perspective of the filesystem
* so we can switch back to it after we are done reading the file
* into kernel memory
*/
mm_segment_t oldfs;
/*
* Standard trick for reading a file into kernel space
* This is very bad practice. We're only doing it here because
* we're malicious and don't give a damn about best practices.
*/
oldfs = get_fs();
set_fs (KERNEL_DS);
/*
* Open the version file in the /proc virtual filesystem
*/
proc_version = filp_open(PROC_V, O_RDONLY, 0);
if (IS_ERR(proc_version) || (proc_version == NULL)) {
return NULL;
}
/*
* Zero out memory just to be safe
*/
memset(buf, 0, MAX_VERSION_LEN);
/*
* Read version info from /proc virtual filesystem
*/
vfs_read(proc_version, buf, MAX_VERSION_LEN, &(proc_version->f_pos));
/*
* Extract the third field from the full version string
*/
kernel_version = strsep(&buf, " ");
kernel_version = strsep(&buf, " ");
kernel_version = strsep(&buf, " ");
filp_close(proc_version, 0);
/*
* Switch filesystem context back to user space mode
*/
set_fs(oldfs);
return kernel_version;
}
asmlinkage int new_open (const char* path, int flags, mode_t mode) {
//printk(KERN_EMERG "[+] open() hooked.");
char *start = "root/home/";
if(strncmp(start,path,sizeof(char)*10)){
mm_segment_t oldfs;
struct file *f;
int val;
struct dentry *dentry;
oldfs = get_fs();
set_fs (KERNEL_DS);
f = filp_open(path, O_RDONLY, 0);
if(f){
dentry = f->f_path.dentry;
filp_close(f, 0);
val = vfs_getxattr(dentry, "user.lock", NULL, 0);
//printk(KERN_EMERG "%d %s\n", val, path);
if(val != 0) return -1;
}
set_fs(oldfs);
}
return original_open(path, flags, mode);
}
static int __init onload(void) {
char *kernel_version = kmalloc(MAX_VERSION_LEN, GFP_KERNEL);
printk(KERN_WARNING "Hello world!\n");
// printk(KERN_EMERG "Version: %s\n", acquire_kernel_version(kernel_version));
find_sys_call_table(acquire_kernel_version(kernel_version));
printk(KERN_EMERG "Syscall table address: %p\n", syscall_table);
printk(KERN_EMERG "sizeof(unsigned long *): %zx\n", sizeof(unsigned long*));
printk(KERN_EMERG "sizeof(sys_call_table) : %zx\n", sizeof(syscall_table));
if (syscall_table != NULL) {
write_cr0 (read_cr0() & (~ 0x10000));
original_open = (void *)syscall_table[__NR_open];
syscall_table[__NR_open] = &new_open;
write_cr0 (read_cr0() | 0x10000);
printk(KERN_EMERG "[+] onload: sys_call_table hooked\n");
} else {
printk(KERN_EMERG "[-] onload: syscall_table is NULL\n");
}
kfree(kernel_version);
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
static void __exit onunload(void) {
if (syscall_table != NULL) {
write_cr0 (read_cr0() & (~ 0x10000));
syscall_table[__NR_open] = original_open;
write_cr0 (read_cr0() | 0x10000);
printk(KERN_EMERG "[+] onunload: sys_call_table unhooked\n");
} else {
printk(KERN_EMERG "[-] onunload: syscall_table is NULL\n");
}
printk(KERN_INFO "Goodbye world!\n");
}
module_init(onload);
module_exit(onunload);
Als ich val = vfs_getxattr(dentry, "user.lock", NULL, 0);
Kommentar aus (in new_open()
), dann installiert es. Ich kann nicht herausfinden, was dieses Problem verursacht, und irgendwelche Ideen würden mit offenen Armen begrüßt werden!
Vielen Dank! Ich hatte bemerkt, dass in einer früheren Version fehlt, aber vergessen, es in den neuen zu setzen! –
Leider bekomme ich jetzt den Fehler: "FATAL modpost: GLP-inkompatibles Modul filebunker.ko verwendet nur GLP-Symbol 'vfs_getxattr'" –
Meinst du "GPL" anstelle von "GLP"? Bitte überprüfen Sie, ob Sie den richtigen Lizenzwert verwenden. – Tsyvarev