命令字:!ndx.chrdevs !ndx.blkdevs

用法描述:

!ndx.chrdevs :显示字符设备,和cat /proc/devices 显示的Character devices 一致
!ndx.blkdevs :显示块设备,和cat /proc/devices 显示的 Block devices 一致

开发过程:

1.找到关键全局变量

fs\proc\devices.c文件下有相关的遍历和显示回调函数,我们通过显示的回调函数,能找到存放字符设备的全局变量

show回调函数的实现:

字符设备显示函数:

fs\char_dev.c下定义了哈希表chrdevs,它的大小为255。

块设备显示函数:

block\genhd.c下定义了哈希表major_names,它的大小为255.

那么我们遍历这两个指针数组,读取对应结构体字段即可,要准确获取相应字段还需查看内核中的遍历,可以清楚知晓对应的数据结构

2.理清相关数据结构

在devinfo_start,开始获取的时候,有两个宏定义,分别定义了字符设备最大数量和块设备最大数量,均为512。

#define CHRDEV_MAJOR_MAX 512

#ifdef CONFIG_BLOCK
#define BLKDEV_MAJOR_MAX    512
#else
#define BLKDEV_MAJOR_MAX    0
#endif

static void *devinfo_start(struct seq_file *f, loff_t *pos)
{
    if (*pos < (BLKDEV_MAJOR_MAX + CHRDEV_MAJOR_MAX))
        return pos;
    return NULL;
}

再看哈希表结构:

3.读取变量和相关偏移,输出信息

DECLARE_API(chrdevs)
{
    ULONG64 ptr_chrdevs = 0;
    ULONG read;
    GetExpressionEx("lk!chrdevs", &ptr_chrdevs, NULL);
    if (ptr_chrdevs == 0) {
        dprintf("Failed to get chrdevs address. Please fix symbol.\n");
        return;
    }

    //读取 chrdevs 哈希表
    ULONG64 chrdevs[CHRDEV_MAJOR_HASH_SIZE];
    ULONG nNameOffset, nMajorOffset, nBaseminorOffset, nMinorctOffset, nNextOffset;
    char name[64];
    unsigned int baseminor;
    int minorct;
    ExtReadMemory(ptr_chrdevs, chrdevs, sizeof(chrdevs), &read);

    //获取相关字段的偏移
    GetFieldOffset("char_device_struct", "name", &nNameOffset);
    GetFieldOffset("char_device_struct", "major", &nMajorOffset);
    GetFieldOffset("char_device_struct", "baseminor", &nBaseminorOffset);
    GetFieldOffset("char_device_struct", "minorct", &nMinorctOffset);
    GetFieldOffset("char_device_struct", "next", &nNextOffset);
    // 遍历所有可能的主设备号,输出结果
    for (int major = 0; major < CHRDEV_MAJOR_MAX; major++) {
        int bucket = major % CHRDEV_MAJOR_HASH_SIZE;
        ULONG64 device_ptr = chrdevs[bucket];
        while (device_ptr != 0) {
            unsigned int dev_major = 0;
            ExtReadMemory(device_ptr + nMajorOffset, &dev_major, sizeof(dev_major), &read);
            if (dev_major == (unsigned int)major) {
                ExtReadMemory(device_ptr + nNameOffset, name, sizeof(name), &read);
                ExtReadMemory(device_ptr + nBaseminorOffset, &baseminor, sizeof(baseminor), &read);
                ExtReadMemory(device_ptr + nMinorctOffset, &minorct, sizeof(minorct), &read);
                dprintf("chrdev[%03d]%016llX major:%-8u baseminor:%-10u minorct:%-8d name:%-40.40s\n",
                    major, device_ptr, dev_major, baseminor, minorct, name);
            }
            ULONG64 next_ptr = 0;
            ExtReadMemory(device_ptr + nNextOffset, &next_ptr, sizeof(next_ptr), &read);
            device_ptr = next_ptr;
        }
    }
}

4.实例测试

!ndx.chrdevs

!ndx.blkdevs

cat /proc/devices

对比发现相同字段是一致的,我们还增添加相关信息的输出。

作者:郭建程  创建时间:2025-09-01 11:31
最后编辑:郭建程  更新时间:2025-09-11 16:05