很久没写技术文章了,今天实在不想写代码就写一篇技术贴,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_long io_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_OBJECT deviceObject;
KEVENT waitEvent;
PIRP irp;
FILE_OBJECT* fileObject;
PIO_STACK_LOCATION irpSp;
IO_STATUS_BLOCK IoStatus;
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 )) {
}
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)