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

友链

extern "C" {
    #include
}

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;
}

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

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

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

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

天书夜读笔记——C++写的内核驱动程序_第1张图片

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

.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

可以看到调用约定为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'

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

然后就开始对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;

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

你可能感兴趣的:(安全,c++,开发语言)