DxgkInitialize的原理分析

来源:互联网 发布:有趣的网站 知乎 网盘 编辑:程序博客网 时间:2024/06/04 18:28

 很久没写技术文章了,今天实在不想写代码就写一篇技术贴,DxgkInitialize是虚拟显卡驱动注册自己的ddi所用的到函数,做虚拟显卡的人很多只知道去调用却不知道他的原理是什么今天我们就分析下。
首先我看下这个函数汇编代码
                 mov     edi, edi
.text:00016605                 push    ebp
.text:00016606                 mov     ebp, esp
.text:00016608                 sub     esp, 34h
.text:0001660B                 xor     eax, eax
.text:0001660D                 cmp     [ebp+arg_0], eax
.text:00016610                 push    ebx
.text:00016611                 mov     [ebp+var_1], 0
.text:00016615                 mov     [ebp+DeviceObject], eax
.text:00016618                 mov     [ebp+OutputBuffer], eax
.text:0001661B                 jz      loc_16728
.text:00016621                 cmp     [ebp+arg_4], eax
.text:00016624                 jz      loc_16728
.text:0001662A                 mov     ebx, [ebp+FileObject]
.text:0001662D                 cmp     ebx, eax
.text:0001662F                 jz      loc_16728
.text:00016635                 cmp     dword ptr [ebx], 1052h
.text:0001663B                 jnb     short loc_16647
.text:0001663D                 mov     eax, 0C0000059h
.text:00016642                 jmp     loc_1672D
.text:00016647 ; ---------------------------------------------------------------------------
.text:00016647
.text:00016647 loc_16647:                              ; CODE XREF: sub_16603+38j
.text:00016647                 push    esi
.text:00016648                 mov     esi, ds:RtlInitUnicodeString
.text:0001664E                 push    edi
.text:0001664F                 push    offset SourceString ; "\\Registry\\Machine\\System\\CurrentCon"...
.text:00016654                 lea     eax, [ebp+DestinationString]
.text:00016657                 push    eax             ; DestinationString
.text:00016658                 call    esi ; RtlInitUnicodeString  //初始化字符窜                                                      L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\DXGKrnl"
.text:0001665A                 lea     eax, [ebp+DestinationString]
.text:0001665D                 push    eax             ; DriverServiceName
.text:0001665E                 call    ds:ZwLoadDriver  这里就是从注册表里加载DXGKrnl。sys
.text:00016664                 mov     edi, eax
.text:00016666                 test    edi, edi
.text:00016668                 jge     short loc_16672
.text:0001666A                 cmp     edi, 0C000010Eh
.text:00016670                 jnz     short loc_166E6 
.text:00016672
.text:00016672 loc_16672:                              ; CODE XREF: sub_16603+65j
.text:00016672                 push    offset aDeviceDxgkrnl ; "\\Device\\DxgKrnl"
.text:00016677                 lea     eax, [ebp+ObjectName]
.text:0001667A                 push    eax             ; DestinationString
.text:0001667B                 mov     [ebp+var_1], 1
.text:0001667F                 call    esi ; RtlInitUnicodeString
.text:00016681                 lea     eax, [ebp+DeviceObject]
.text:00016684                 push    eax             ; DeviceObject
.text:00016685                 lea     eax, [ebp+FileObject]
.text:00016688                 push    eax             ; FileObject
.text:00016689                 push    0C0000000h      ; DesiredAccess
.text:0001668E                 lea     eax, [ebp+ObjectName]
.text:00016691                 push    eax             ; ObjectName
.text:00016692                 call    ds:IoGetDeviceObjectPointer //获得加载后的驱动的设备对象,以方便下面io请求
.text:00016698                 mov     edi, eax
.text:0001669A                 test    edi, edi
.text:0001669C                 jl      short loc_1670D
.text:0001669E                 push    0               ; State
.text:000166A0                 push    0               ; Type
.text:000166A2                 lea     eax, [ebp+Event]
.text:000166A5                 push    eax             ; Event
.text:000166A6                 call    ds:KeInitializeEvent
.text:000166AC                 lea     eax, [ebp+IoStatusBlock]
.text:000166AF                 push    eax             ; IoStatusBlock
.text:000166B0                 lea     eax, [ebp+Event]
.text:000166B3                 push    eax             ; Event
.text:000166B4                 push    1               ; InternalDeviceIoControl 此处表示建立的主IO码是IRP_MJ_INTERNAL_DEVICE_CONTROL
;
.text:000166B6                 push    4               ; OutputBufferLength
.text:000166B8                 lea     eax, [ebp+OutputBuffer]
.text:000166BB                 push    eax             ; OutputBuffer
.text:000166BC                 push    0               ; InputBufferLength
.text:000166BE                 push    0               ; InputBuffer
.text:000166C0                 push    [ebp+DeviceObject] ; DeviceObject
.text:000166C3                 push    23003Fh         ; IoControlCode
.text:000166C8                 call    ds:IoBuildDeviceIoControlRequest 向dxgkrnl生成请求IO,IO控制码是23003Fh ,结果 放在 OutputBuffer  ,即ebp+OutputBuffer,返回大小是4个字节
.text:000166CE                 test    eax, eax   判断结果是否请求成功
.text:000166D0                 jnz     short loc_166D9 成功了到达loc_166D9 
.text:000166D2                 mov     edi, 0C000009Ah
.text:000166D7                 jmp     short loc_1670D
.text:000166D9 ; ---------------------------------------------------------------------------
.text:000166D9
.text:000166D9 loc_166D9:                              ; CODE XREF: sub_16603+CDj
.text:000166D9                 mov     ecx, [ebp+DeviceObject] ; DeviceObject
.text:000166DC                 mov     edx, eax        ; Irp
.text:000166DE                 call    ds:IofCallDriver //此处像驱动发IO
.text:000166E4                 mov     edi, eax
.text:000166E6
.text:000166E6 loc_166E6:                              ; CODE XREF: sub_16603+6Dj
.text:000166E6                 test    edi, edi判断结果是否请求成功
.text:000166E8                 jl      short loc_16707 判断结果是否请求成功,成功不跳转,顺序执行 
.text:000166EA                 mov     eax, [ebx+8]
.text:000166ED                 push    ebx
.text:000166EE                 push    [ebp+arg_4]
.text:000166F1                 mov     dword_1EAD4, eax
.text:000166F6                 push    [ebp+arg_0]
.text:000166F9                 mov     dword ptr [ebx+8], offset sub_20DB9
.text:00016700                 call    [ebp+OutputBuffer]  //注意:这里是关键函数,这里会调用返回的结果的给的4个字节的地址,会call这个地址,这个函数是什么呢,下面我们继续分析。
.一下不是关键函数省略掉。。。。。。。。
。。。。。。。。。。。。 
.text:0001672F sub_16603       endp
上面那个绿色的 call    [ebp+OutputBuffer] 到底是什么呢?下面我们就分析下dxgkrnl.sys这个驱动
 
由于ds:IoBuildDeviceIoControlRequest  建立的主IO 是IRP_MJ_INTERNAL_DEVICE_CONTROL,我们看dxgkrnl的DriverObject->MajorFunction[15] = DxgkInternalDeviceIoctl 的函数,进入DxgkInternalDeviceIoctl 后我们找到 次io控制码0x23003F,
 case 0x23003Fu:
      if ( OutputBufferLength >= 4 && v9 )
      {
        *(_DWORD *)v9 = DpiInitialize;
        v10 = 0;
        v31 = 4;
      }
 哈哈发现了什么大家, 对就是DpiInitialize这个函数,这个函数就是返回出去的地址,然后被外部注册驱动所调用。
下次在继续讲这个函数的原理,今天写到此处,该函数就是把外部驱动的 
DRIVER_INITIALIZATION_DATA的结构函数注册到dgxkrnl全局设备结构双向链表中,同时也会填写到当前驱动的DRIVER_OBJECT->Extension 扩展对象中,下次继续讲解。
下面是本章代码 伪代码

NTSTATUS
Dxgkrnl::query_interface( void* dxg_interface,
                          unsigned long cmd_io,
                          unsigned long   dxg_size ) {

    if ( dxg_interface && dxg_size ) {

        if ( dxg_size ) {

            IO_STATUS_BLOCK ioStatus;
            OBJECT_ATTRIBUTES objectAttributes;
            PFILE_OBJECT fileObject;
            HANDLE fileHandle;
            NTSTATUS status;
            UNICODE_STRING afd_device;
            u_longio_code;
            DXGK_INTERFACE* temp = ( DXGK_INTERFACE* ) dxg_interface;

            if ( dxg_size > 8 ) {

                temp->flags=  ( cmd_io == IO_DXG_QUERY_CDD_INTERFACE?2:1 );
                temp->size= dxg_size;
                }

            RtlInitUnicodeString(
                &afd_device,
                L"\\Device\\DxgKrnl");
            InitializeObjectAttributes(&objectAttributes,
                                       &afd_device,
                                       OBJ_KERNEL_HANDLE,
                                       (HANDLE)NULL,
                                       (PSECURITY_DESCRIPTOR)NULL);

            //这里的Open;
            status = ZwOpenFile(
                         &fileHandle,
                         FILE_READ_DATA,
                         &objectAttributes,
                         &ioStatus,
                         FILE_SHARE_READ|FILE_SHARE_WRITE,
                         FILE_NON_DIRECTORY_FILE);

            //打开设备成功
            if( NT_SUCCESS( status ) ) {

                io_code = cmd_io;
                PDEVICE_OBJECTdeviceObject;
                KEVENTwaitEvent;
                PIRPirp;
                FILE_OBJECT*fileObject;
                PIO_STACK_LOCATIONirpSp;
                IO_STATUS_BLOCKIoStatus;
                u_long request_mode = KernelMode;
                KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );

                status = ObReferenceObjectByHandle( fileHandle,
                                                    0,
                                                    *IoFileObjectType,
                                                    request_mode,
                                                    (PVOID *) &fileObject,
                                                    NULL );

                if ( !NT_SUCCESS( status ) ) {
                    return status;
                    }

                KeClearEvent( &fileObject->Event );
                deviceObject = IoGetRelatedDeviceObject( fileObject );

                if ( !deviceObject ) {
                    return STATUS_UNSUCCESSFUL;
                    }

                irp = IoAllocateIrp( deviceObject->StackSize, FALSE );

                if ( !irp ) {
                    //
                    // An IRP could not be allocated.  Cleanup and return an appropriate
                    // error status code.
                    //
                    //IoFreeIrp( fileObject, eventObject );

                    ObDereferenceObject(&fileObject);

                    return STATUS_INSUFFICIENT_RESOURCES;
                    }

                irpSp = IoGetNextIrpStackLocation( irp );

                //
                // Set the major function code based on the type of device I/O control
                // function the caller has specified.
                //

                irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
                irpSp->FileObject = fileObject;
                irpSp->DeviceObject = deviceObject;
                //
                // Copy the caller's parameters to the service-specific portion of the
                // IRP for those parameters that are the same for all four methods.
                //

                irpSp->Parameters.DeviceIoControl.OutputBufferLength = dxg_size;
                irpSp->Parameters.DeviceIoControl.InputBufferLength = dxg_size;
                irpSp->Parameters.DeviceIoControl.IoControlCode = io_code;
                irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;

                //设置Irp
                irp->UserIosb =&IoStatus;
                irp->UserEvent = &waitEvent;
                irp->UserBuffer = dxg_interface;
                irp->Tail.Overlay.Thread = PsGetCurrentThread();
                IoQueueThreadIrp( irp );

                status = IoCallDriver(deviceObject, irp);

                if ( status == STATUS_PENDING ) {
                    status = KeWaitForSingleObject(
                                 &waitEvent,
                                 Executive,
                                 KernelMode,
                                 FALSE,
                                 NULL);

                    status = IoStatus.Status;
                    }

                ObDereferenceObject(fileObject);

                ZwClose( fileHandle );
                // IoBuildDeviceIoControlRequest
                return status;
                }
            }
        }

    return STATUS_INVALID_PARAMETER;
    } 


 DriverInitializationData.Version = 0x2025;
        DriverInitializationData.Reserved = 0;
        DriverInitializationData.DxgkDdiAddDevice= dxg_ddi::DdiAddDevice;
        DriverInitializationData.DxgkDdiStartDevice= dxg_ddi::DdiStartDevice;
        DriverInitializationData.DxgkDdiStopDevice= dxg_ddi::DdiStopDevice;
        DriverInitializationData.DxgkDdiRemoveDevice= dxg_ddi::DdiRemoveDevice;
        DriverInitializationData.DxgkDdiDispatchIoRequest= dxg_ddi::DdiDispatchIoRequest;
        DriverInitializationData.DxgkDdiInterruptRoutine= dxg_ddi::DdiInterruptRoutine;
        DriverInitializationData.DxgkDdiDpcRoutine= dxg_ddi::DdiDpcRoutine;
        DriverInitializationData.DxgkDdiQueryChildRelations= dxg_ddi::DdiQueryChildRelations;
        DriverInitializationData.DxgkDdiQueryChildStatus= dxg_ddi::DdiQueryChildStatus;
        DriverInitializationData.DxgkDdiQueryDeviceDescriptor= dxg_ddi::DdiQueryDeviceDescriptor;
        DriverInitializationData.DxgkDdiControlEtwLogging= dxg_ddi::DdiControlEtwLogging;
        DriverInitializationData.DxgkDdiQueryAdapterInfo= dxg_ddi::DdiQueryAdapterInfo;
        DriverInitializationData.DxgkDdiSetPowerState= dxg_ddi::DdiSetPowerState;
        DriverInitializationData.DxgkDdiNotifyAcpiEvent= dxg_ddi::DdiNotifyAcpiEvent;
        DriverInitializationData.DxgkDdiResetDevice= dxg_ddi::DdiResetDevice;
        DriverInitializationData.DxgkDdiUnload= dxg_ddi::DdiUnload;
        DriverInitializationData.DxgkDdiQueryInterface= dxg_ddi::DdiQueryInterface;
        DriverInitializationData.DxgkDdiControlEtwLogging= dxg_ddi::DdiControlEtwLogging;
        DriverInitializationData.DxgkDdiCreateDevice= dxg_ddi::DdiCreatedevice;
        DriverInitializationData.DxgkDdiCreateAllocation= dxg_ddi::DdiCreateAllocation;
        DriverInitializationData.DxgkDdiDestroyAllocation= dxg_ddi::DdiDestroyAllocation;
        DriverInitializationData.DxgkDdiDescribeAllocation= dxg_ddi::DdiDescribeAllocation;
        DriverInitializationData.DxgkDdiGetStandardAllocationDriverData= dxg_ddi::DdiGetStandardAllocationDriverData;
        DriverInitializationData.DxgkDdiAcquireSwizzlingRange= dxg_ddi::DdiAcquireSwizzlingRange;
        DriverInitializationData.DxgkDdiReleaseSwizzlingRange= dxg_ddi::DdiReleaseSwizzlingRange;
        DriverInitializationData.DxgkDdiPatch= dxg_ddi::DdiPatch;
        DriverInitializationData.DxgkDdiSubmitCommand= dxg_ddi::DdiSubmitCommand;
        DriverInitializationData.DxgkDdiPreemptCommand= dxg_ddi::DdiPreemptCommand;
        DriverInitializationData.DxgkDdiBuildPagingBuffer= dxg_ddi::DdiBuildPagingBuffer;
        DriverInitializationData.DxgkDdiSetPalette= dxg_ddi::DdiSetPalette;
        DriverInitializationData.DxgkDdiSetPointerPosition= dxg_ddi::DdiSetPointerPosition;
        DriverInitializationData.DxgkDdiSetPointerShape= dxg_ddi::DdiSetPointerShape;
        DriverInitializationData.DxgkDdiResetFromTimeout= dxg_ddi::DdiResetFromTimeout;
        DriverInitializationData.DxgkDdiRestartFromTimeout= dxg_ddi::DdiRestartFromTimeout;
        DriverInitializationData.DxgkDdiEscape= dxg_ddi::DdiEscape;
        DriverInitializationData.DxgkDdiCollectDbgInfo= dxg_ddi::DdiCollectDbgInfo;
        DriverInitializationData.DxgkDdiQueryCurrentFence= dxg_ddi::DdiQueryCurrentFence;
        DriverInitializationData.DxgkDdiIsSupportedVidPn= dxg_ddi::DdiIsSupportedVidPn;
        DriverInitializationData.DxgkDdiRecommendFunctionalVidPn= dxg_ddi::DdiRecommendFunctionalVidPn;
        DriverInitializationData.DxgkDdiEnumVidPnCofuncModality= dxg_ddi::DdiEnumVidPnCofuncModality;
        DriverInitializationData.DxgkDdiSetVidPnSourceAddress= dxg_ddi::DdiSetVidPnSourceAddress;
        DriverInitializationData.DxgkDdiSetVidPnSourceVisibility= dxg_ddi::DdiSetVidPnSourceVisibility;
        DriverInitializationData.DxgkDdiCommitVidPn= dxg_ddi::DdiCommitVidPn;
        DriverInitializationData.DxgkDdiUpdateActiveVidPnPresentPath= dxg_ddi::DdiUpdateActiveVidPnPresentPath;
        DriverInitializationData.DxgkDdiRecommendMonitorModes= dxg_ddi::DdiRecommendMonitorModes;
        DriverInitializationData.DxgkDdiRecommendVidPnTopology= dxg_ddi::DdiRecommendVidPnTopology;
        DriverInitializationData.DxgkDdiGetScanLine= dxg_ddi::DdiGetScanLine;
        DriverInitializationData.DxgkDdiStopCapture= dxg_ddi::DdiStopCapture;
        DriverInitializationData.DxgkDdiControlInterrupt= dxg_ddi::DdiControlInterrupt;
        DriverInitializationData.DxgkDdiCreateOverlay= dxg_ddi::DdiCreateOverlay;
        DriverInitializationData.DxgkDdiDestroyDevice= dxg_ddi::DdiDestroyDevice;
        DriverInitializationData.DxgkDdiOpenAllocation= dxg_ddi::DdiOpenAllocation;
        DriverInitializationData.DxgkDdiCloseAllocation= dxg_ddi::DdiCloseAllocation;
        DriverInitializationData.DxgkDdiRender= dxg_ddi::DdiRender;
        DriverInitializationData.DxgkDdiPresent= dxg_ddi::DdiPresent;
        DriverInitializationData.DxgkDdiUpdateOverlay= dxg_ddi::DdiUpdateOverlay;
        DriverInitializationData.DxgkDdiFlipOverlay= dxg_ddi::DdiFlipOverlay;
        DriverInitializationData.DxgkDdiDestroyOverlay= dxg_ddi::DdiDestroyOverlay;
        DriverInitializationData.DxgkDdiCreateContext= dxg_ddi::DdiCreateContext;
        DriverInitializationData.DxgkDdiDestroyContext= dxg_ddi::DdiDestroyContext;
        DriverInitializationData.DxgkDdiLinkDevice= dxg_ddi::DdiLinkDevice;
        DriverInitializationData.DxgkDdiSetDisplayPrivateDriverFormat= dxg_ddi::DdiSetDisplayPrivateDriverFormat;
        DriverInitializationData.DxgkDdiDescribePageTable= dxg_ddi::DdiDescribePageTable;
        DriverInitializationData.DxgkDdiUpdatePageTable= dxg_ddi::DdiUpdatePageTable;
        DriverInitializationData.DxgkDdiUpdatePageDirectory= dxg_ddi::DdiUpdatePageDirectory;
        DriverInitializationData.DxgkDdiMovePageDirectory= dxg_ddi::DdiMovePageDirectory;
        DriverInitializationData.DxgkDdiSubmitRender= dxg_ddi::DdiSubmitRender;
        DriverInitializationData.DxgkDdiCreateAllocation2= dxg_ddi::DdiCreateAlloction2;
        DriverInitializationData.DxgkDdiRenderKm= dxg_ddi::DdiRenderKm;
        DriverInitializationData.DxgkDdiQueryVidPnHWCapability= dxg_ddi::DdiQueryVidPnHWCapability;

 memset(
            &krnl->dpi_init ,
            0,
            sizeof( DPI_INIT ));

        krnl->query_interface(
            &krnl->dpi_init,
            0x23003F,
            sizeof(DPI_INIT));

        if ( krnl->dpi_init.pDpi_Init ) {

            UNICODE_STRING driver_name;
            RtlInitUnicodeString( &driver_name , L"DxgkProxy" );

            //调用Dpi初始化接口
            NTSTATUS temp_status = krnl->dpi_init.pDpi_Init(
                                       device->DriverObject ,
                                       &driver_name ,
                                       (void*) &DriverInitializationData );

            //IoGetDriverObjectExtension;
            if ( NT_SUCCESS(temp_status )) {
}
0 0
原创粉丝点击