当前位置:网站首页>Reading notes at night -- deep into virtual function

Reading notes at night -- deep into virtual function

2022-06-25 01:16:00 ma_ de_ hao_ mei_ le

Friend chain

First put the previous MyDriver Class to implement

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

class MySubDriver : public MyDriver
{
public:
    MySubDriver(PDRIVER_OBJECT driver) : MyDriver(driver) {};
    virtual NTSTATUS OnDispatch(PDEVICE_OBJECT dev, PIRP irp) {
        DbgPrint("this is the dispatch function of MySubDriver\r\n");
        return STATUS_UNSUCCESSFUL;
    }
};

extern "C" NTSTATUS DriverEntry(
    PDRIVER_OBJECT driver, PUNICODE_STRING reg
) {
	MyDriver::d_my_driver = new MySubDriver(driver);
    return STATUS_UNSUCCESSFUL;
}

build Then throw it to ida in

.text:00010486 ; int __stdcall MyDriver::sDispatch(_DEVICE_OBJECT *dev, _IRP *irp)
.text:00010486 [email protected]@@[email protected]@[email protected]@@Z proc near
.text:00010486                                         ; DATA XREF: MyDriver::MyDriver(_DRIVER_OBJECT *)+19o
.text:00010486
.text:00010486 dev             = dword ptr  8
.text:00010486 irp             = dword ptr  0Ch
.text:00010486
.text:00010486                 mov     edi, edi
.text:00010488                 push    ebp
.text:00010489                 mov     ebp, esp
.text:0001048B                 mov     ecx, [email protected]@@[email protected] ; MyDriver * MyDriver::d_my_driver
.text:00010491                 mov     eax, [ecx]
.text:00010493                 pop     ebp
.text:00010494                 jmp     dword ptr [eax]
.text:00010494 [email protected]@@[email protected]@[email protected]@@Z endp

This is MyDriver Class sDispatch function , In our C++ In the code , Inside the function , Called OnDispatch function

NTSTATUS MyDriver::sDispatch(PDEVICE_OBJECT dev, PIRP irp) {
    return d_my_driver->OnDispatch(dev, irp);
}

But in the assembly code above , I didn't see it call Instructions , only one jmp Jump instruction

According to the assembly code , You can see that the final program jumps to eax The address stored in the memory pointed to . and eax The value of comes from [ecx],ecx The value of comes from d_my_driver, That is to say this The pointer , According to us The introduction of the last article ,ecx Points to the virtual function table , that [ecx] This is the real content of the virtual function table , We can give c++ In the document mydriver Class and add a virtual function in sdispatch Call to see how many bytes a virtual function occupies in the table

Add a virtual function and call it :

extern "C" {
    
    #include<ntifs.h>
}

class MyDriver 
{
    
public:
    MyDriver(PDRIVER_OBJECT driver);
    virtual NTSTATUS OnDispatch(PDEVICE_OBJECT dev, PIRP irp) {
    
        return STATUS_UNSUCCESSFUL;
    };
    virtual NTSTATUS test_virtual_fucn(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) + d_my_driver->test_virtual_fucn(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;
}

class MySubDriver : public MyDriver
{
    
public:
    MySubDriver(PDRIVER_OBJECT driver) : MyDriver(driver) {
    };
    virtual NTSTATUS OnDispatch(PDEVICE_OBJECT dev, PIRP irp) {
    
        DbgPrint("this is the dispatch function of MySubDriver\r\n");
        return STATUS_UNSUCCESSFUL;
    }
};

extern "C" NTSTATUS DriverEntry(
    PDRIVER_OBJECT driver, PUNICODE_STRING reg
) {
    
	MyDriver::d_my_driver = new MySubDriver(driver);
    return STATUS_UNSUCCESSFUL;
}

sObDispatch Assembly code for

.text:00010486 ; int __stdcall MyDriver::sDispatch(_DEVICE_OBJECT *dev, _IRP *irp)
.text:00010486 [email protected]@@[email protected]@[email protected]@@Z proc near
.text:00010486                                         ; DATA XREF: MyDriver::MyDriver(_DRIVER_OBJECT *)+19o
.text:00010486
.text:00010486 dev             = dword ptr  8
.text:00010486 irp             = dword ptr  0Ch
.text:00010486
.text:00010486                 mov     edi, edi
.text:00010488                 push    ebp
.text:00010489                 mov     ebp, esp
.text:0001048B                 mov     ecx, [email protected]@@[email protected] ; MyDriver * MyDriver::d_my_driver
.text:00010491                 mov     eax, [ecx]
.text:00010493                 push    esi
.text:00010494                 push    [ebp+irp]
.text:00010497                 push    [ebp+dev]
.text:0001049A                 call    dword ptr [eax+4]
.text:0001049D                 push    [ebp+irp]
.text:000104A0                 mov     ecx, [email protected]@@[email protected] ; MyDriver * MyDriver::d_my_driver
.text:000104A6                 push    [ebp+dev]
.text:000104A9                 mov     esi, eax
.text:000104AB                 mov     eax, [ecx]
.text:000104AD                 call    dword ptr [eax]
.text:000104AF                 add     eax, esi
.text:000104B1                 pop     esi
.text:000104B2                 pop     ebp
.text:000104B3                 retn    8
.text:000104B3 [email protected]@@[email protected]@[email protected]@@Z endp

You can see that there are two calls ,
···
.text:0001049A call dword ptr [eax+4]

.text:000104AD call dword ptr [eax]

···

therefore , We can determine the occupation of a virtual function table 4 Bytes , In fact, this can be inferred without testing , about x86 Applications for , The address is 32bit Of , A virtual function is just an address ( Function address ), That is to say 4bytes

Derived class mysubdriver Virtual function table and base class mydriver There must be some relation in the virtual function table of , Can be called mydriver The virtual function of can call mysubdriver Corresponding implementation function of

Take a look at mysubdriver How to initialize the virtual function table by the constructor of

mysubdriver Constructor for :

.text:00010534 ; void __thiscall MySubDriver::MySubDriver(MySubDriver *this, _DRIVER_OBJECT *driver)
.text:00010534 [email protected]@[email protected][email protected]@@Z proc near
.text:00010534                                         ; CODE XREF: DriverEntry(x,x)+16p
.text:00010534
.text:00010534 driver          = dword ptr  8
.text:00010534
.text:00010534 this = ecx
.text:00010534                 mov     edi, edi
.text:00010536                 push    ebp
.text:00010537                 mov     ebp, esp
.text:00010539                 push    esi
.text:0001053A                 push    [ebp+driver]    ; driver
.text:0001053D                 mov     esi, this
.text:0001053F                 call    [email protected]@[email protected][email protected]@@Z ; MyDriver::MyDriver(_DRIVER_OBJECT *)
.text:00010544                 mov     dword ptr [esi], offset [email protected]@[email protected] ; const MySubDriver::`vftable'
.text:0001054A                 mov     eax, esi
.text:0001054C                 pop     esi
.text:0001054D                 pop     ebp
.text:0001054E                 retn    4
.text:0001054E [email protected]@[email protected][email protected]@@Z endp

You can see mydriver The virtual function table of is actually mysubdriver The virtual function table of is replaced , Calling mydriver Before the constructor ecx Nothing has changed , Then incoming mydriver Constructor's this Pointers and mysubdriver Of this The pointer is the same , stay mydriver After the constructor call is completed ,this Will point to the virtual function table , But the next instruction

.text:00010544                 mov     dword ptr [esi], offset [email protected]@[email protected] ; const MySubDriver::`vftable'

bring this(esi stay mydriver The constructor is saved before calling this Value ) The content pointed to has changed , Turned into mysubdriver Virtual function table of

 Insert picture description here

原网站

版权声明
本文为[ma_ de_ hao_ mei_ le]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206242037582258.html