/* * module_hunter.c v0.2.0 - Search for patterns in the kernel address space * that look like module structures. This tools find hidden modules that * unlinked themself from the chained list of loaded modules. * * insmod ./module_hunter.ko * * usage: cat /proc/showmodules && dmesg * * Originally listed in http://www.phrack.org/phrack/61/p61-0x03_Linenoise.txt * * Updated 2006/1/22 * - Now works with 2.6.x Fedora-based kernels * - Will list only hidden modules * * TODO: * - Properly use /proc files instead of dmesg for output * * This hunter is not foolproof and can easily be circumvented. */ #include #ifdef CONFIG_SMP #define __SMP__ #endif #ifdef MODVERSIONS #include #endif #include #include #include #include #include #include #include #include #include #include #include // FIXME: This is a variable in later kernels.. The kernel code doesn't // ever seem to change it, but it is possible they may make it dynamic // in the future (possibly for > 32bit arch or PAE, but then this whole // module would probably break) #define MY_VMALLOC_RESERVE (128 << 20) /* Black magic voodoo. Unlikely to work on non-x86 or even PAE */ int valid_addr(unsigned long address) { unsigned long page; if (!address) return 0; page = ((unsigned long *)init_mm.pgd)[address >> 22]; if (page & 1) { page &= PAGE_MASK; address &= 0x003ff000; page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; //pte if (page) return 1; } return 0; } int is_print(char *str) { while(*str != 0) { if (*str < 0x21 || *str > 0x7e) return 0; str++; } return 1; } int is_in_list(struct module *mod) { struct list_head *list = &__this_module.list; do { if (list == &mod->list) { return 1; } list = list->next; } while(list != &__this_module.list); return 0; } ssize_t showmodule_read(struct file *unused_file, char *buffer, size_t len, loff_t *off) { struct module *mod = NULL; unsigned long p; int found_one = 0; printk("The following modules (if any) are not listed in lsmod:\n\n"); for (p=VMALLOC_START; pmodule_core) #ifdef CONFIG_MODULE_UNLOAD && (!mod->exit || valid_addr((unsigned long)mod->exit)) #endif && (!mod->module_init || valid_addr((unsigned long)mod->module_init)) && mod->core_size < 2<<20 && mod->init_size < 2<<20 && mod->state == 0 && is_print(mod->name) && strlen(mod->name)) { if (!is_in_list(mod)) { found_one = 1; printk("0x%p%20s core_size: %ld init_size %ld\n", mod, mod->name, mod->core_size, mod->init_size); } } } } if (!found_one) { printk("No hidden modules found! (This does not guarantee your system is clean)\n"); } return 0; } static struct file_operations showmodules_ops = { read: showmodule_read, }; int init_module(void) { struct proc_dir_entry *entry; printk("\nModule Hunter v0.2\n"); entry = create_proc_entry("showmodules", S_IRUSR, &proc_root); entry->proc_fops = &showmodules_ops; printk("Installed /proc/showmodules\n"); return 0; } void cleanup_module() { remove_proc_entry("showmodules", &proc_root); } MODULE_LICENSE("GPL");