我有一个 NT 式驱动 HelloDDK,“在之前的调试中没出错”。
我想为这个驱动增加与应用程序通信的功能。
我在 HelloDDK.h 中增加了函数声名:NTSTATUS DeviceIoControl( IN PDEVICE_OBJECT, IN PIRP ); // IRP_MJ_DEVICE_CONTROL 的派遣函数,与设备交互
在 DriverEntry() 中注册了该函数:pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControl;
在 DeviceIoControl.h 中增加了函数实现:
#define MY_DEVICE_IOCTL \
CTL_CODE( FILE_DEVICE_UNKNOWN, \
0x800, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
NTSTATUS
DeviceIoControl( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp )
{
NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION pIoStack = 0; // I/O 堆栈 PCHAR pInputBuffer = 0; // 输入缓冲区指针 PCHAR pOutputBuffer = 0; // 输出缓冲区指针 ULONG InputBufferSize = 0; // 输入缓冲区的大小 ULONG OutputBufferSize = 0; // 输出缓冲区的大小 ULONG IoCode = 0; // IOCODE 码 PCHAR DeviceOutput = "the string from DeviceIoControl() in the Driver"; // 输出到应用程序 ULONG OutDataLen = strlen( DeviceOutput ) + 1; //信息长度含结尾一个NULL
KdPrint(( "in the DeviceIoControl() for the HelloDDK project \n" ));
pIoStack = IoGetCurrentIrpStackLocation( pIrp ); // 获取当前 I/O 堆栈 InputBufferSize = pIoStack->Parameters.DeviceIoControl.InputBufferLength; OutputBufferSize = pIoStack->Parameters.DeviceIoControl.OutputBufferLength; IoCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;
if ( MY_DEVICE_IOCTL == IoCode ) // IOCTL 码编号 0x800。
{
KdPrint(( "控制码 MY_DEVICE_IOCTL,编号 0x800。\n" ));
pInputBuffer = pIrp->AssociatedIrp.SystemBuffer; // 操作输入缓冲区
KdPrint(( "the string from Appliction %s\n", pInputBuffer )); //打印出应用层传入的内容
pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer; // 操作输出缓冲区 RtlCopyBytes( pOutputBuffer, DeviceOutput, OutputBufferSize ); // 复制要传出的字符串到输出缓冲区
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = OutputBufferSize;
} else
{
pIrp->IoStatus.Status = STATUS_INVALID_VARIANT; pIrp->IoStatus.Information = 0;
}
#if DBG // 调试状态
_asm int 3 // 断点
#endif
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); // 完成此次 IRP
return pIrp->IoStatus.Status;
}
卸载函数:#pragma PAGEDCODE
void
HelloDDKUnload( IN PDRIVER_OBJECT pDriverObject ) // 驱动卸载
{
PDEVICE_OBJECT pDeviceObject; // 设备对象 PDEVICE_EXTENSION pDeviceExtension; // 设备扩展,HelloDDK.h 中 UNICODE_STRING symLinkName; // 符号链接名
pDeviceObject = pDriverObject->DeviceObject; // 由驱动对象得到设备对象
while ( NULL != pDeviceObject )
{
pDeviceExtension = pDeviceObject->DeviceExtension; symLinkName = pDeviceExtension->sSymlinkName; IoDeleteSymbolicLink( &symLinkName ); //删除符号链接
pDeviceObject = pDeviceObject->NextDevice; // 指向下一个设备对象 IoDeleteDevice( pDeviceExtension->pDevice ); // 删除当前设备对象
} #if DBG // 调试状态
_asm int 3 // 断点
#endif KdPrint(( "in the HelloDDKUnload() for the HelloWDM project \n" ));
}我在虚拟机中调试时,先在虚拟机中的控制台中输入: net start HelloDDK提示:服务启动成功。
紧接者,在不执行任何其它步骤的情况下,在虚拟机中的控制台中输入: net stop HelloDDK回车,此时,在 WinDbg 中,出现以下提示:*** Fatal System Error: 0x00000050
(0xFCA260E0,0x00000000,0x80564772,0x00000000)Break instruction exception - code 80000003 (first chance)A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.A fatal system error has occurred.Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
............................................................................................................Loading User SymbolsLoading unloaded module list
.........
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 50, {fca260e0, 0, 80564772, 0}*** ERROR: Module load completed but symbols could not be loaded for mssmbios.sys
Probably caused by : HelloDDK.sys ( HelloDDK!HelloDDKUnload+39 )Followup: MachineOwner
---------nt!RtlpBreakWithStatusInstruction:
804e4592 cc int 3
我只要将新增的与 DeviceIoControl() 有关的代码都去掉,就能正常停止该驱动。不知错在哪里?请高人指点!先谢了!
我想为这个驱动增加与应用程序通信的功能。
我在 HelloDDK.h 中增加了函数声名:NTSTATUS DeviceIoControl( IN PDEVICE_OBJECT, IN PIRP ); // IRP_MJ_DEVICE_CONTROL 的派遣函数,与设备交互
在 DriverEntry() 中注册了该函数:pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControl;
在 DeviceIoControl.h 中增加了函数实现:
#define MY_DEVICE_IOCTL \
CTL_CODE( FILE_DEVICE_UNKNOWN, \
0x800, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
NTSTATUS
DeviceIoControl( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp )
{
NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION pIoStack = 0; // I/O 堆栈 PCHAR pInputBuffer = 0; // 输入缓冲区指针 PCHAR pOutputBuffer = 0; // 输出缓冲区指针 ULONG InputBufferSize = 0; // 输入缓冲区的大小 ULONG OutputBufferSize = 0; // 输出缓冲区的大小 ULONG IoCode = 0; // IOCODE 码 PCHAR DeviceOutput = "the string from DeviceIoControl() in the Driver"; // 输出到应用程序 ULONG OutDataLen = strlen( DeviceOutput ) + 1; //信息长度含结尾一个NULL
KdPrint(( "in the DeviceIoControl() for the HelloDDK project \n" ));
pIoStack = IoGetCurrentIrpStackLocation( pIrp ); // 获取当前 I/O 堆栈 InputBufferSize = pIoStack->Parameters.DeviceIoControl.InputBufferLength; OutputBufferSize = pIoStack->Parameters.DeviceIoControl.OutputBufferLength; IoCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;
if ( MY_DEVICE_IOCTL == IoCode ) // IOCTL 码编号 0x800。
{
KdPrint(( "控制码 MY_DEVICE_IOCTL,编号 0x800。\n" ));
pInputBuffer = pIrp->AssociatedIrp.SystemBuffer; // 操作输入缓冲区
KdPrint(( "the string from Appliction %s\n", pInputBuffer )); //打印出应用层传入的内容
pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer; // 操作输出缓冲区 RtlCopyBytes( pOutputBuffer, DeviceOutput, OutputBufferSize ); // 复制要传出的字符串到输出缓冲区
pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = OutputBufferSize;
} else
{
pIrp->IoStatus.Status = STATUS_INVALID_VARIANT; pIrp->IoStatus.Information = 0;
}
#if DBG // 调试状态
_asm int 3 // 断点
#endif
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); // 完成此次 IRP
return pIrp->IoStatus.Status;
}
卸载函数:#pragma PAGEDCODE
void
HelloDDKUnload( IN PDRIVER_OBJECT pDriverObject ) // 驱动卸载
{
PDEVICE_OBJECT pDeviceObject; // 设备对象 PDEVICE_EXTENSION pDeviceExtension; // 设备扩展,HelloDDK.h 中 UNICODE_STRING symLinkName; // 符号链接名
pDeviceObject = pDriverObject->DeviceObject; // 由驱动对象得到设备对象
while ( NULL != pDeviceObject )
{
pDeviceExtension = pDeviceObject->DeviceExtension; symLinkName = pDeviceExtension->sSymlinkName; IoDeleteSymbolicLink( &symLinkName ); //删除符号链接
pDeviceObject = pDeviceObject->NextDevice; // 指向下一个设备对象 IoDeleteDevice( pDeviceExtension->pDevice ); // 删除当前设备对象
} #if DBG // 调试状态
_asm int 3 // 断点
#endif KdPrint(( "in the HelloDDKUnload() for the HelloWDM project \n" ));
}我在虚拟机中调试时,先在虚拟机中的控制台中输入: net start HelloDDK提示:服务启动成功。
紧接者,在不执行任何其它步骤的情况下,在虚拟机中的控制台中输入: net stop HelloDDK回车,此时,在 WinDbg 中,出现以下提示:*** Fatal System Error: 0x00000050
(0xFCA260E0,0x00000000,0x80564772,0x00000000)Break instruction exception - code 80000003 (first chance)A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.A fatal system error has occurred.Connected to Windows XP 2600 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
............................................................................................................Loading User SymbolsLoading unloaded module list
.........
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 50, {fca260e0, 0, 80564772, 0}*** ERROR: Module load completed but symbols could not be loaded for mssmbios.sys
Probably caused by : HelloDDK.sys ( HelloDDK!HelloDDKUnload+39 )Followup: MachineOwner
---------nt!RtlpBreakWithStatusInstruction:
804e4592 cc int 3
我只要将新增的与 DeviceIoControl() 有关的代码都去掉,就能正常停止该驱动。不知错在哪里?请高人指点!先谢了!
void
HelloDDKUnload( IN PDRIVER_OBJECT pDriverObject ) // 驱动卸载
{
PDEVICE_OBJECT pDeviceObject; // 设备对象 PDEVICE_EXTENSION pDeviceExtension; // 设备扩展,HelloDDK.h 中 UNICODE_STRING symLinkName; // 符号链接名
pDeviceObject = pDriverObject->DeviceObject; // 由驱动对象得到设备对象
while ( NULL != pDeviceObject )
{
pDeviceExtension = pDeviceObject->DeviceExtension; symLinkName = pDeviceExtension->sSymlinkName;
KdPrint(( "断点 2 in the HelloDDKUnload()\n" )); #if DBG // 调试状态
_asm int 3 // 断点
#endifIoDeleteSymbolicLink( &symLinkName ); //删除符号链接
KdPrint(( "断点 3 in the HelloDDKUnload()\n" )); #if DBG // 调试状态
_asm int 3 // 断点
#endif
pDeviceObject = pDeviceObject->NextDevice; // 指向下一个设备对象 IoDeleteDevice( pDeviceExtension->pDevice ); // 删除当前设备对象
}
#if DBG // 调试状态
_asm int 3 // 断点
#endif KdPrint(( "in the HelloDDKUnload() for the HelloWDM project \n" ));
}
从中可看出,symLinkName 是从设备扩展中获取的:pDeviceExtension = pDeviceObject->DeviceExtension; symLinkName = pDeviceExtension->sSymlinkName;
在不增加与 DeviceIoControl() 有关的代码时,服务能正常停止。那就说明,下面这行应该没问题:IoDeleteSymbolicLink( &symLinkName ); //删除符号链接
那为什么增加与 DeviceIoControl() 有关的代码后,服务不能正常停止呢?
我只启动和停止服务,中间无任何其它操作。DeviceIoControl() 中的代码并未被执行。不知为何错在:
IoDeleteSymbolicLink( &symLinkName ); //删除符号链接 请指点!!
_asm int 3 // 断点
#endif 去掉
我在 WinDbg 中设置了符号表的路径,符号表的路径与本机上 HelloDDK 驱动的 .sys 文件在同一目录下。但我在 WinDbg 中的 Watch 窗口中看不到任何变量显示?
下面是初始化 symLinkName 的代码:RtlInitUnicodeString( &symLinkName, L"\\??\\HelloDDK");
我在 HelloDDKUnload() 添加了打印 symLinkName 的代码:KdPrint(( "symLinkName 的值: %wZ\n", &symLinkName )); // 打印变量的内容 #if DBG // 调试状态
_asm int 3 // 断点
#endif
然后,我先把与 DeviceIoControl() 有关的代码注释掉,然后调试。执行到:KdPrint(( "symLinkName 的值: %wZ\n", &symLinkName )); // 打印变量的内容
这行时,在 WinDbg 中显示:symLinkName 的值: \??\HelloDDK说明没问题。而且,直到最后都没出错,服务也能正常停止。
然后,我再把与 DeviceIoControl() 有关的代码加上,然后调试。执行到:KdPrint(( "symLinkName 的值: %wZ\n", &symLinkName )); // 打印变量的内容
这行时,在 WinDbg 中显示:symLinkName 的值:
说明 symLinkName 的值不对。但也说明问题出在与 DeviceIoControl() 有关的代码加上。与 DeviceIoControl() 有关的代码具体代码都在本帖第一楼中,我看不出问题所在。
请高人们帮忙指点指点了!!!!
#include <ntddk.h>
#define NTDDK_H
#endif// 内存模式#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
// 自定义宏,计算数组元素个数,用于默认派遣函数
#define MyArraySize( p ) ( sizeof( p ) / sizeof( ( p )[0] ) )typedef struct DEVICE_EXTENSION // 自定义设备扩展
{
PDEVICE_OBJECT pDevice; // 设备对象指针 UNICODE_STRING sDeviceName; // 设备名,由内核使用 UNICODE_STRING sSymlinkName; // 符号链接名,由应用程序使用} DEVICE_EXTENSION, *PDEVICE_EXTENSION;NTSTATUS DriverEntry( IN PDRIVER_OBJECT, IN PUNICODE_STRING ); // 入口void HelloDDKUnload( IN PDRIVER_OBJECT ); // 驱动卸载NTSTATUS CreateDevice( IN PDRIVER_OBJECT ); // 添加新设备
NTSTATUS ReadDevice( IN PDEVICE_OBJECT, IN PIRP ); // IRP_MJ_READ 的派遣函数
//IRP_MJ_DEVICE_CONTROL 的派遣函数,与设备交互
NTSTATUS DeviceIoControl( IN PDEVICE_OBJECT, IN PIRP );NTSTATUS DispatchRoutine( IN PDEVICE_OBJECT, IN PIRP ); // 默认派遣函数// CreateDevice.h
#pragma INITCODE
NTSTATUS
CreateDevice( IN PDRIVER_OBJECT pDriverObject ) // 添加新设备
{
NTSTATUS status; // 状态码 PDEVICE_OBJECT pDeviceOb; // 设备对象 PDEVICE_EXTENSION pDeviceExtension; // 自定义的设备扩展数据,HelloDDK.h 中 UNICODE_STRING DeviceName; // 设备名 UNICODE_STRING symLinkName; // 符号链接
// 初始化字符串 RtlInitUnicodeString( &DeviceName, L"\\Device\\HelloDDKDevice"); RtlInitUnicodeString( &symLinkName, L"\\??\\HelloDDK");
status = IoCreateDevice( pDriverObject, sizeof( DEVICE_EXTENSION ),
&DeviceName,
FILE_DEVICE_UNKNOWN,
0, TRUE, &pDeviceOb ); if( !NT_SUCCESS( status ) )
return status;
pDeviceOb->Flags |= DO_BUFFERED_IO;
// 填写设备扩展 pDeviceExtension = pDeviceOb->DeviceExtension; pDeviceExtension->pDevice = pDeviceOb; pDeviceExtension->sDeviceName = DeviceName; pDeviceExtension->sSymlinkName = symLinkName;
// 创建设备的符号链接 status = IoCreateSymbolicLink( &symLinkName, &DeviceName ); if( !NT_SUCCESS( status ) ) // 符号链接创建“失败”
{
IoDeleteDevice( pDeviceOb ); // 删除设备对象 return status;
} #if DBG // 调试状态
_asm int 3 // 断点
#endif
KdPrint(( "in the CreateDevice() for the HelloDDK project \n" )); return STATUS_SUCCESS; // 成功
}
请帮我看看哪儿有问题,先谢了!
我觉得,符号链接等字符串,被我拷贝到了设备扩展对象中。而我的 HelloDDKUnload() 是从设备扩展对象中读取得到符号链接的字符串值。我想,如果我定义一个设备扩展的“全局对象”,把这个对象载入“分页内存”。然后,我把 CreateDevice() 载入“初始化内存”。我再在 CreateDevice() 中把符号链接等字符串拷贝到这个设备扩展的“全局对象”中。那么,我的 HelloDDKUnload() 就能从设备扩展对象中读取到正确的符号链接的字符串值。这样做,不知是否合理?