我们在进行Windows编程的时候,经常需要进行IO控制与内核通信,我们来实现IO控制与内核通信。请见代码实现与注释讲解
驱动代码实现与分析
/* 头文件 */ #include <ntddk.h>// 包括了很多NT内核的类型、结构、函数定义,开发驱动时需要包括此头文件 #include <string.h> #include "xioctl.h" /* 常量与预定义 */ #define NT_DEVICE_NAME L"\\Device\\XIOCTL" #define DOS_DEVICE_NAME L"\\DosDevices\\IoctlTest" #if DBG #define XIOCTL_KDPRINT(_x_) \ DbgPrint("XIOCTL.SYS: ");\ DbgPrint _x_; #else #define XIOCTL_KDPRINT(_x_) #endif /* 函数声明 */ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); NTSTATUS XioctlCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS XioctlDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp ); VOID XioctlUnloadDriver(PDRIVER_OBJECT DriverObject ); VOID PrintIrpInfo( PIRP Irp ); VOID PrintChars( PCHAR BufferAddress, ULONG CountChars ); #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, DriverEntry ) #pragma alloc_text( PAGE, XioctlCreateClose) #pragma alloc_text( PAGE, XioctlDeviceControl) #pragma alloc_text( PAGE, XioctlUnloadDriver) #pragma alloc_text( PAGE, PrintIrpInfo) #pragma alloc_text( PAGE, PrintChars) #endif // ALLOC_PRAGMA /************************************* * DriverEntry * 功能 驱动的入口函数,分配了相关处理例程 **************************************/ NTSTATUS DriverEntry( IN OUT PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS ntStatus; UNICODE_STRING ntUnicodeString; // 设备名 UNICODE_STRING ntWin32NameString; // Win32 设备名 PDEVICE_OBJECT deviceObject = NULL; // 设备对象 RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME ); // 创建设备 ntStatus = IoCreateDevice( DriverObject, // 驱动对象 DriverEntry 的参数 0, // 不使用设备扩展 &ntUnicodeString, // 设备名 "\Device\XIOCTL" FILE_DEVICE_UNKNOWN, // 设备类型 FILE_DEVICE_SECURE_OPEN, // FALSE, // &deviceObject ); // 设备对象 if ( !NT_SUCCESS( ntStatus ) ) { XIOCTL_KDPRINT(("Couldn't create the device object\n")); return ntStatus; } // 初始化处理例程 DriverObject->MajorFunction[IRP_MJ_CREATE] = XioctlCreateClose;// 创建时会调用 DriverObject->MajorFunction[IRP_MJ_CLOSE] = XioctlCreateClose;// 关闭时会调用 // 处理IO控制 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = XioctlDeviceControl; DriverObject->DriverUnload = XioctlUnloadDriver;// 卸载时会调用 // WIN32 设备名 RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME ); // 在设备名和WIN32设备名之间创建符号连接 ntStatus = IoCreateSymbolicLink( &ntWin32NameString, &ntUnicodeString ); if ( !NT_SUCCESS( ntStatus ) ) { XIOCTL_KDPRINT(("Couldn't create symbolic link\n")); IoDeleteDevice( deviceObject ); } return ntStatus; } /************************************* * XioctlCreateClose * 功能 驱动对象的处理例程,由DriverEntry指定 * 本函数中驱动对象在创建和关闭时调用的例程。 * 没有实际的功能,只是将状态设置为 成功 **************************************/ NTSTATUS XioctlCreateClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } /************************************* * XioctlUnloadDriver * 功能 卸载驱动时调用的例程, * 删除符号连接,删除设备 **************************************/ VOID XioctlUnloadDriver( IN PDRIVER_OBJECT DriverObject ) { PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; UNICODE_STRING uniWin32NameString; RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); // 删除符号连接 IoDeleteSymbolicLink( &uniWin32NameString ); // 删除设备 if ( deviceObject != NULL ) { IoDeleteDevice( deviceObject ); } } /************************************* * XioctlDeviceControl * 功能 处理IO控制的例程 **************************************/ NTSTATUS XioctlDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION irpSp;// 当前栈的位置 NTSTATUS ntStatus = STATUS_SUCCESS;// 执行状态,成功\失败 ULONG inBufLength; // 输入缓存大小 ULONG outBufLength; // 输出缓存大小 PCHAR inBuf, outBuf; // 输入输出缓存 PCHAR data = "This String is from Device Driver !!!"; ULONG datalen = strlen(data)+1;//输出数据的长度 PMDL mdl = NULL; PCHAR buffer = NULL; // 处理IRP irpSp = IoGetCurrentIrpStackLocation( Irp ); inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; if(!inBufLength || !outBufLength) { ntStatus = STATUS_INVALID_PARAMETER; goto End; } // 判断IOCTL switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) { case IOCTL_XIOCTL_BUFFER: // 显示收到的IRP XIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n")); PrintIrpInfo(Irp); // 设备IN OUT 缓存 inBuf = Irp->AssociatedIrp.SystemBuffer; outBuf = Irp->AssociatedIrp.SystemBuffer; // 从输入缓存中获得信息 XIOCTL_KDPRINT(("\tData from User : %s", inBuf)); // 复制数据到输出缓存 strncpy(outBuf, data, outBufLength); // 打印输出输出缓存的内容 XIOCTL_KDPRINT(("\tData to User : %s", outBuf)); // 设置IRP Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); break; // 还可以定义其他IO 控制码 default: // 处理其他示知的IO code ntStatus = STATUS_INVALID_DEVICE_REQUEST; XIOCTL_KDPRINT(("ERROR: unrecognized IOCTL %x\n", irpSp->Parameters.DeviceIoControl.IoControlCode)); break; } End: // 设备状态,完成IPR处理 Irp->IoStatus.Status = ntStatus; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return ntStatus; } /************************************* * PrintIrpInfo * 功能 打印IPR信息 **************************************/ VOID PrintIrpInfo( PIRP Irp) { PIO_STACK_LOCATION irpSp; irpSp = IoGetCurrentIrpStackLocation( Irp ); XIOCTL_KDPRINT(("\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n", Irp->AssociatedIrp.SystemBuffer)); XIOCTL_KDPRINT(("\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer)); XIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n", irpSp->Parameters.DeviceIoControl.Type3InputBuffer)); XIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n", irpSp->Parameters.DeviceIoControl.InputBufferLength)); XIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n", irpSp->Parameters.DeviceIoControl.OutputBufferLength )); return; }
实现加载与卸载驱动,
/* 头文件 */ #include <windows.h> #include <winioctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "..\sys\xioctl.h" /* 全局变量 */ char OutputBuffer[100]; char InputBuffer[100]; /* 函数声明 */ BOOL InstallDriver( SC_HANDLE, LPCTSTR, LPCTSTR ); BOOL RemoveDriver( SC_HANDLE, LPCTSTR ); BOOL StartDriver( SC_HANDLE , LPCTSTR ); BOOL StopDriver( SC_HANDLE , LPCTSTR ); /************************************* * InstallDriver * 功能 创建服务、安装驱动 * 参数 SchSCManager,服务控制器句柄 * DriverName,服务名 * ServiceExe,驱动的可执行程序路径 **************************************/ BOOL InstallDriver( SC_HANDLE SchSCManager, LPCTSTR DriverName, LPCTSTR ServiceExe ) { SC_HANDLE schService; DWORD err; // 调用CreateService创建服务 schService = CreateService(SchSCManager, // 服务控制器,SCM句柄 DriverName, // 服务名 DriverName, // 服务的显示名 SERVICE_ALL_ACCESS, // 存取权限 SERVICE_KERNEL_DRIVER, // 服务类型 SERVICE_DEMAND_START, // 启动类型 SERVICE_ERROR_NORMAL, // 启动错误的处理 ServiceExe, // 可执行程序 NULL, NULL, NULL, NULL, NULL ); if (schService == NULL) { // 创建服务失败 err = GetLastError(); // 服务已经存在 if (err == ERROR_SERVICE_EXISTS) { return TRUE;// 返回成功 } else { // 输出错误信息,返回失败 printf("CreateService failed! Error = %d \n", err ); return FALSE; } } // 创建成功,关闭服务 if (schService) { CloseServiceHandle(schService); } // 返回成功 return TRUE; } /************************************* * RemoveDriver * 功能 删除驱动服务 * 参数 SchSCManager,服务控制器句柄 * DriverName,服务名 **************************************/ BOOL RemoveDriver( SC_HANDLE SchSCManager, LPCTSTR DriverName ) { SC_HANDLE schService; BOOLEAN rCode; // 打开服务 schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { // 服务打开失败 printf("OpenService failed! Error = %d \n", GetLastError()); return FALSE; } // 删除服务 if (DeleteService(schService)) { rCode = TRUE; } else { //失败 printf("DeleteService failed! Error = %d \n", GetLastError()); rCode = FALSE; } // 关闭服务句柄 if (schService) { CloseServiceHandle(schService); } return rCode; } /************************************* * StartDriver * 功能 起动服务,加载执行驱动 * 参数 SchSCManager,服务控制器句柄 * DriverName,服务名 **************************************/ BOOL StartDriver( SC_HANDLE SchSCManager, LPCTSTR DriverName ) { SC_HANDLE schService; DWORD err; // 打开服务 schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { // 失败 printf("OpenService failed! Error = %d \n", GetLastError()); return FALSE; } // 启动服务 if (!StartService(schService, // 服务句柄 0, // 参数个数,无 NULL // 参数指针,无 )) { // 启动失败 err = GetLastError(); // 已经开始运行 if (err == ERROR_SERVICE_ALREADY_RUNNING) { // 返回成功 return TRUE; } else { // 失败,打印错误 printf("StartService failure! Error = %d \n", err ); return FALSE; } } // 关闭服务句柄 if (schService) { CloseServiceHandle(schService); } return TRUE; } /************************************* * StopDriver * 功能 停止服务,停止驱动运行 * 参数 SchSCManager,服务控制器句柄 * DriverName,服务名 **************************************/ BOOL StopDriver( SC_HANDLE SchSCManager, LPCTSTR DriverName ) { BOOLEAN rCode = TRUE; SC_HANDLE schService; SERVICE_STATUS serviceStatus; // 打开服务 schService = OpenService(SchSCManager, DriverName, SERVICE_ALL_ACCESS ); if (schService == NULL) { // 失败 printf("OpenService failed! Error = %d \n", GetLastError()); return FALSE; } // 停止运行 if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus )) { rCode = TRUE; } else { // 失败 printf("ControlService failed! Error = %d \n", GetLastError() ); rCode = FALSE; } // 关闭服务句柄 if (schService) { CloseServiceHandle (schService); } return rCode; } /************************************* * GetDriverPath * 功能 获得服务驱动的路径 * 参数 DriverLocation,返回驱动的路径 **************************************/ BOOL GetDriverPath( LPSTR DriverLocation ) { DWORD driverLocLen = 0; // 驱动.sys文件在本程序同一目标下 driverLocLen = GetCurrentDirectory(MAX_PATH, DriverLocation ); if (!driverLocLen) { printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); return FALSE; } // 构造路径,加上驱动名 lstrcat(DriverLocation, "\\"); lstrcat(DriverLocation, DRIVER_NAME); lstrcat(DriverLocation, ".sys"); return TRUE; } /************************************* * int _cdecl main( ) * 功能 加载驱动,进行控制 **************************************/ int _cdecl main() { HANDLE hDevice; BOOL bRc; ULONG bytesReturned; DWORD errNum = 0; UCHAR driverLocation[MAX_PATH]; SC_HANDLE schSCManager;// 服务控制器句柄 // 打开服务控制器,后续安装、启动都会使用到。 schSCManager = OpenSCManager(NULL, // 本机 NULL, // 本机数据库 SC_MANAGER_ALL_ACCESS // 存取权限 ); if (!schSCManager) { // 打开失败 printf("Open SC Manager failed! Error = %d \n", GetLastError()); return 1; } // 获得驱动文件的路径 if (!GetDriverPath(driverLocation)) { return 1; } // 安装驱动服务 if (InstallDriver(schSCManager, DRIVER_NAME, driverLocation )) { // 安装成功,启动服务,运行驱动 if(!StartDriver(schSCManager, DRIVER_NAME )) { printf("Unable to start driver. \n"); return 1; } } else { // 安装失败,删除驱动。 RemoveDriver(schSCManager, DRIVER_NAME ); printf("Unable to install driver. \n"); return 1; } // 打开驱动,获得控制所用的句柄 // 由驱动创建的符号链接 hDevice = CreateFile( "\\\\.\\IoctlTest", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if ( hDevice == INVALID_HANDLE_VALUE ) { printf ( "Error: CreatFile Failed : %d\n", GetLastError()); return 1; } // 打印,输入输出。 printf("InputBuffer Pointer = %p, BufLength = %d\n", InputBuffer, sizeof(InputBuffer)); printf("OutputBuffer Pointer = %p BufLength = %d\n", OutputBuffer, sizeof(OutputBuffer)); // 输入到内核的数据, lstrcpy(InputBuffer, "This String is from User Application; using IOCTL_XIOCTL_BUFFER"); printf("\nCalling DeviceIoControl IOCTL_XIOCTL_BUFFER:\n"); // 清空输出缓存 memset(OutputBuffer, 0, sizeof(OutputBuffer)); // 进行IO控制, bRc = DeviceIoControl ( hDevice,// 句柄 (DWORD) IOCTL_XIOCTL_BUFFER,// IOCTL &InputBuffer,// 输入数据 strlen ( InputBuffer )+1,// 输入数据的长度 &OutputBuffer,// 输出数据 sizeof( OutputBuffer),// 输出数据长度 &bytesReturned,// 实际输出的数据长度 NULL ); // 判断是否成功 if ( !bRc ) { printf ( "Error in DeviceIoControl : %d", GetLastError()); return 1; } // 打印从内核输出的内容 printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); // 关闭句柄 CloseHandle ( hDevice ); // 停止运行 StopDriver(schSCManager, DRIVER_NAME ); // 删除服务 RemoveDriver(schSCManager, DRIVER_NAME ); // 关闭服务控制器 CloseServiceHandle (schSCManager); return 0; }
实现ring3下面的调用
/* 头文件 */ #include <Windows.h> #include <Winioctl.h> #include <stdio.h> /* 函数声明 */ DWORD EnjectCdrom(LPSTR szCdRomName); DWORD PrintNTFSInfo(LPSTR szVolumeName); /************************************* * main * 功能 -cdrom <盘符> 弹出光盘 * -ntfs <盘符> 显示nfts分区的信息 **************************************/ int main(int argc, char* argv[]) { CHAR szName[64]; if(argc == 3) { // 构造设备名 wsprintf(szName, "\\\\.\\%s.", argv[2]); // 弹出光盘 if(lstrcmp(argv[1],"-cdrom") == 0) { EnjectCdrom( szName ); return 0; } // 获取NTFS分区详细信息 if(lstrcmp(argv[1],"-ntfs") == 0) { PrintNTFSInfo( szName ); return 0; } } // 使用方法 printf("usage: \n\t %s -cdrom <volume>\n\t %s -ntfs <volume>\nlike this: \n\t -cdrom G:", argv[0], argv[0]); return 0; } /************************************* * DWORD EnjectCdrom(LPSTR szCdRomName) * 功能 弹出指定的光盘 * 参数 szCdRomName,设备名 **************************************/ DWORD EnjectCdrom(LPSTR szCdRomName) { HANDLE hDevice; DWORD dwBytesReturned; hDevice = CreateFile(szCdRomName, // 设备名 GENERIC_ALL, // 存取权限 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, // 共享方式 NULL, // 默认安全属性 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("Could not open file (error %d)\n", GetLastError()); return 0; } // 发送IOCTL if(!DeviceIoControl( (HANDLE) hDevice, // 设备句柄 IOCTL_STORAGE_EJECT_MEDIA, // 控制码 NULL, // 输入缓存 0, // 输入缓存大小 NULL, // 输出缓存 0, // 输出缓存大小 &dwBytesReturned, // 实际需要的输输入缓存大小 NULL // 非OVERLAPPED )) { printf("DeviceIoControl error (%d)",GetLastError()); return 0; } return 1; } /************************************* * DWORD PrintNTFSInfo(LPSTR szVolumeName) * 功能 获取显示指定的NTFS驱动器信息 * 参数 szVolumeName,设备名 **************************************/ DWORD PrintNTFSInfo(LPSTR szVolumeName) { // FSCTL_GET_NTFS_VOLUME_DATA IO控制的返回值保存在 // NTFS_VOLUME_DATA_BUFFER结构中 NTFS_VOLUME_DATA_BUFFER nvdb; DWORD dwBufferSize; HANDLE hDevice; // 清空参数 ZeroMemory(&nvdb,sizeof(nvdb)); hDevice = CreateFile(szVolumeName, GENERIC_ALL, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("Could not open file (error %d)\n", GetLastError()); return 0; } if(DeviceIoControl( hDevice, // 设备句柄 FSCTL_GET_NTFS_VOLUME_DATA, // 控制码 NULL, // 输入缓存 0, // 输入缓存大小 &nvdb, // 输出缓存 sizeof( NTFS_VOLUME_DATA_BUFFER ), // 输出缓存大小 &dwBufferSize, // 返回的实际数据大小 NULL // 非OVERLAPPED )) { // 打印获取的信息 printf("SerialNumber %lu\n",nvdb.VolumeSerialNumber); printf("Starting logical cluster number of the master file table: %lu\n",nvdb.MftStartLcn); printf("Length of the master file table: %lu\n",nvdb.MftValidDataLength); printf("... ...\n"); } else { printf("DeviceIoControl error: (%d)\n",GetLastError()); return 0; } return 1; }
/* 头文件 */ #include <Windows.h> #include <Winioctl.h> #include <stdio.h> /* 函数声明 */ DWORD EnjectCdrom(LPSTR szCdRomName); DWORD PrintNTFSInfo(LPSTR szVolumeName); /************************************* * main * 功能 -cdrom <盘符> 弹出光盘 * -ntfs <盘符> 显示nfts分区的信息 **************************************/ int main(int argc, char* argv[]) { CHAR szName[64]; if(argc == 3) { // 构造设备名 wsprintf(szName, "\\\\.\\%s.", argv[2]); // 弹出光盘 if(lstrcmp(argv[1],"-cdrom") == 0) { EnjectCdrom( szName ); return 0; } // 获取NTFS分区详细信息 if(lstrcmp(argv[1],"-ntfs") == 0) { PrintNTFSInfo( szName ); return 0; } } // 使用方法 printf("usage: \n\t %s -cdrom <volume>\n\t %s -ntfs <volume>\nlike this: \n\t -cdrom G:", argv[0], argv[0]); return 0; } /************************************* * DWORD EnjectCdrom(LPSTR szCdRomName) * 功能 弹出指定的光盘 * 参数 szCdRomName,设备名 **************************************/ DWORD EnjectCdrom(LPSTR szCdRomName) { HANDLE hDevice; DWORD dwBytesReturned; hDevice = CreateFile(szCdRomName, // 设备名 GENERIC_ALL, // 存取权限 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, // 共享方式 NULL, // 默认安全属性 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("Could not open file (error %d)\n", GetLastError()); return 0; } // 发送IOCTL if(!DeviceIoControl( (HANDLE) hDevice, // 设备句柄 IOCTL_STORAGE_EJECT_MEDIA, // 控制码 NULL, // 输入缓存 0, // 输入缓存大小 NULL, // 输出缓存 0, // 输出缓存大小 &dwBytesReturned, // 实际需要的输输入缓存大小 NULL // 非OVERLAPPED )) { printf("DeviceIoControl error (%d)",GetLastError()); return 0; } return 1; } /************************************* * DWORD PrintNTFSInfo(LPSTR szVolumeName) * 功能 获取显示指定的NTFS驱动器信息 * 参数 szVolumeName,设备名 **************************************/ DWORD PrintNTFSInfo(LPSTR szVolumeName) { // FSCTL_GET_NTFS_VOLUME_DATA IO控制的返回值保存在 // NTFS_VOLUME_DATA_BUFFER结构中 NTFS_VOLUME_DATA_BUFFER nvdb; DWORD dwBufferSize; HANDLE hDevice; // 清空参数 ZeroMemory(&nvdb,sizeof(nvdb)); hDevice = CreateFile(szVolumeName, GENERIC_ALL, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hDevice == INVALID_HANDLE_VALUE) { printf("Could not open file (error %d)\n", GetLastError()); return 0; } if(DeviceIoControl( hDevice, // 设备句柄 FSCTL_GET_NTFS_VOLUME_DATA, // 控制码 NULL, // 输入缓存 0, // 输入缓存大小 &nvdb, // 输出缓存 sizeof( NTFS_VOLUME_DATA_BUFFER ), // 输出缓存大小 &dwBufferSize, // 返回的实际数据大小 NULL // 非OVERLAPPED )) { // 打印获取的信息 printf("SerialNumber %lu\n",nvdb.VolumeSerialNumber); printf("Starting logical cluster number of the master file table: %lu\n",nvdb.MftStartLcn); printf("Length of the master file table: %lu\n",nvdb.MftValidDataLength); printf("... ...\n"); } else { printf("DeviceIoControl error: (%d)\n",GetLastError()); return 0; } return 1; }