基于块设备的Linux内核内存监视模块

Table of Contents

就在完成了支持Linux 5.10的ramdisk驱动模块后不久,突发奇想,既然之前提到Linux内核模块之间地址空间是完全共享的,那么可以编写一个模块,通过块设备驱动的方式来直接对内存进行读写。

因此,我便对之前块设备驱动的代码做了些许改动,编写了一个新的模块,名为spy

于是我便尝试从新的模块对之前的ramdisk模块进行一个数据盗取。

获取数据的地址

Linux内核本身提供了一个查看内核符号的接口,位于/proc/kallsyms,我们只需要将它cat出来然后用grep选择我们所需的数据即可。

$ sudo cat /proc/kallsyms | grep myramdisk
ffffffffc0bd8024 r _note_7  [myramdisk]
ffffffffc0bd7000 t myramdisk_queue_rq   [myramdisk]
ffffffffc0bd900c d __warned.0   [myramdisk]
ffffffffc0bd8180 r myramdisk_mq_ops [myramdisk]
ffffffffc0bd8200 r myramdisk_fops   [myramdisk]
ffffffffc0bd7272 t myramdisk_exit   [myramdisk]
ffffffffc0bd80d2 r .LC1 [myramdisk]
ffffffffc0bd8278 r myramdisk_dev_size   [myramdisk]
ffffffffc0bd9040 d __this_module    [myramdisk]
ffffffffc0bd7272 t cleanup_module   [myramdisk]
ffffffffc0bd9400 b myramdisk_devs   [myramdisk]
ffffffffc0bd9680 b myramdisk_major  [myramdisk]

然后我们已知,myramdisk_devs结构体长这样:

struct myramdisk_dev {
    unsigned char *data;
    struct request_queue *queue;
    struct gendisk *gd;
    struct blk_mq_tag_set tag_set;
} myramdisk_devs[myramdisk_ndev];

可见,如果我们要盗取data指针的数据,那么偏移量为0,但是需要访问1次嵌套指针。

使用我写的玩具spy模块

根据参数定义,使用如下:

sudo insmod spy.ko spy_addr=ffffffffc0bd9400 spy_ptr_nested=1

测试数据盗取效果

注:需要先写入数据再加载模块,否则可能会受到缓存影响。

$ sudo dd if=/dev/urandom of=/dev/myramdisk0 bs=1M count=16
16+0 records in
16+0 records out
16777216 bytes (17 MB, 16 MiB) copied, 0.438467 s, 38.3 MB/s

$ sudo md5sum /dev/myramdisk0
7a1715b7fdc38fd7923e7f7e410cee30  /dev/myramdisk0

$ sudo insmod spy.ko spy_addr=ffffffffc0bd9400 spy_ptr_nested=1

$ sudo md5sum /dev/spy0
7a1715b7fdc38fd7923e7f7e410cee30  /dev/spy0

可以看到,创建的spy完全复制了ramdisk模块的内存,测试成功。

注意事项

需要注意内存访问越界导致Page Fault,进而导致模块崩溃的问题。请注意设置spy_dev_size参数。

成品代码

https://github.com/cyyself/simple-linux-kernel-module/tree/master/kernel_spy

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to Top