• 天书夜读笔记——C++写的内核驱动程序


    友链

    extern "C" {
        #include<ntifs.h>
    }
    
    class MyDriver 
    {
    public:
        MyDriver(PDRIVER_OBJECT driver);
        virtual NTSTATUS OnDispatch(PDEVICE_OBJECT dev, PIRP irp) {
            return STATUS_UNSUCCESSFUL;
        };
        static MyDriver *d_my_driver;
    
    private:
        static NTSTATUS sDispatch(PDEVICE_OBJECT dev, PIRP irp);
        PDRIVER_OBJECT d_driver;
    };
    
    MyDriver::MyDriver(PDRIVER_OBJECT driver) : d_driver(driver)
    {
        size_t i;
        for(i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++) {
            d_driver->MajorFunction[i] = sDispatch;
        }
        d_my_driver = this;
    };
    
    NTSTATUS MyDriver::sDispatch(PDEVICE_OBJECT dev, PIRP irp) {
        return d_my_driver->OnDispatch(dev, irp);
    }
    
    MyDriver* MyDriver::d_my_driver = NULL;
    
    
    void* __cdecl operator new(unsigned int size) {
        void* pt = ExAllocatePool(NonPagedPool, size);
        if(NULL != pt) 
            memset(pt, 0, size);
        return pt;
    }
    
    extern "C" NTSTATUS DriverEntry(
        PDRIVER_OBJECT driver, PUNICODE_STRING reg
    ) {
    	MyDriver::d_my_driver = new MyDriver(driver);
        return STATUS_UNSUCCESSFUL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    类中还定义了一个虚函数(OnDispatch)可以让后续继承该类的子类来进行自己的实现

    由于driver是一个singleton,所以我们可以用d_my_driver指针来指向this,这样就解决了静态函数的调用问题(静态函数无法引用类的非静态成员)

    因为只有静态成员函数才能像C函数一样被使用,但是静态成员函数无法调用虚函数,因此我们需要一个静态成员d_my_drvier,一个指针,让他指向MyDriver,就和this一样,这样我们就能通过d_my_drvier来调用虚函数了

    通过反汇编代码,可以看到,new函数只负责分配内存,构造函数是在driver_entry函数体内被调用的,也就是说编译器在看到new之后会自动调用构造函数

    在这里插入图片描述

    我们来看一下构造函数的实现

    .text:000104CC ; void __thiscall MyDriver::MyDriver(MyDriver *this, _DRIVER_OBJECT *driver)
    .text:000104CC ??0MyDriver@@QAE@PAU_DRIVER_OBJECT@@@Z proc near
    .text:000104CC                                         ; CODE XREF: DriverEntry(x,x)+16p
    .text:000104CC
    .text:000104CC driver          = dword ptr  8
    .text:000104CC
    .text:000104CC this = ecx
    .text:000104CC                 mov     edi, edi
    .text:000104CE                 push    ebp
    .text:000104CF                 mov     ebp, esp
    .text:000104D1                 mov     eax, this
    .text:000104D3                 mov     this, [ebp+driver]
    .text:000104D6                 push    38h
    .text:000104D8                 mov     [eax+4], this
    .text:000104DB                 mov     dword ptr [eax], offset ??_7MyDriver@@6B@ ; const MyDriver::`vftable'
    .text:000104E1                 pop     this
    .text:000104E2
    .text:000104E2 loc_104E2:                              ; CODE XREF: MyDriver::MyDriver(_DRIVER_OBJECT *)+29j
    .text:000104E2                 mov     edx, [eax+4]
    .text:000104E5                 mov     dword ptr [this+edx], offset ?sDispatch@MyDriver@@CGJPAU_DEVICE_OBJECT@@PAU_IRP@@@Z ; MyDriver::sDispatch(_DEVICE_OBJECT *,_IRP *)
    .text:000104EC                 add     this, 4
    .text:000104EF                 cmp     this, 0A4h
    .text:000104F5                 jbe     short loc_104E2
    .text:000104F7                 mov     ?d_my_driver@MyDriver@@2PAV1@A, eax ; MyDriver * MyDriver::d_my_driver
    .text:000104FC                 pop     ebp
    .text:000104FD                 retn    4
    .text:000104FD ??0MyDriver@@QAE@PAU_DRIVER_OBJECT@@@Z endp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以看到调用约定为thiscall

    this指针通过ecx传入函数,ecx是new函数的返回值,也就是新分配的内存地址

    this->eax,然后ebp+driver->this, this->eax+4

    那么也就是说在内存地址偏移量为0x4的地方存入了driver这个参数,就是我们构造函数的那个列表初始化中的d_driver成员变量

    那么前四个字节干嘛去了呢,继续往下看可以看到

    .text:000104DB                 mov     dword ptr [eax], offset ??_7MyDriver@@6B@ ; const MyDriver::`vftable'
    
    • 1

    可以看到,前四个字节存放的是虚函数表

    然后就开始对driver结构体的成员MajorFunction数组依次进行赋值
    你可能会疑问,这里的[this+edx]是什么东西,仔细看一下代码,你会发现,前面有一对push pop操作,使得this的值变成了0x38h,正好是MajorFunction成员在driver结构体中的偏移量,而edx的值是[eax+4],也就是driver成员变量,所以一切都解释得通

    另外,从代码中可以看出MyDriver::d_my_driver是一个全局变量

    构造函数返回后,在driverentry中,构造函数的返回值eax->d_my_driver,这里的eax其实还是new函数的返回值,只不过它所指向的地址被构造函数填满了数据

    看到这里,你应该就能够意识到,类其实就是一堆变量和函数的集合,没什么复杂的东西

    另外需要补充的一点就是,我们必须要生命一个全局变量

    MyDriver* MyDriver::d_my_driver = NULL;
    
    • 1

    因为在构造函数MyDriver::MyDriver中,我们用到了d_my_driver

  • 相关阅读:
    CF-957(D-E)
    【吴恩达机器学习笔记】十、支持向量机
    狂神。SpringBoot学习(3)
    蜂鸣器电路设计中选用注意事项--【电路设计】
    mysql 字段用了关键字, 无法插入更新数据
    iOS 16 中 SwiftUI 4.0 轻松实现导航栏标题可编辑
    住院管理系统
    LInux-4-进程地址空间
    m基于GA遗传算法的高载能负荷响应优化控制模型matlab仿真
    京东面试:说说你对ByteBuf的理解
  • 原文地址:https://blog.csdn.net/ma_de_hao_mei_le/article/details/125422636