编写NT驱动使得APP能够读取PCI设备配置信息

来源:互联网 发布:国际云计算大会 编辑:程序博客网 时间:2024/05/21 20:38

     驱动程序是一个软件组件,可以让操作系统和设备之间实现通信。一般操作系统可以分为两个主要组成部分,即User Mode和Kernel Mode。用户的APP运行在系统的User Mode下,而驱动程序则运行在系统的Kernel Mode下。由于Windows在User Mode下做了许多限制,使得在用户模式下的APP有很多资源不能访问到,这时候就可以通过驱动来实现对Kernel Mode下的资源进行访问,如图5.1所示。

图 5.1

 

    NT驱动程序一般是由3部分组成,即DriverEntry、DispatchRoutine和DriveUnload。其中DriverEntry主要进行驱动程序的初始化,即:创建设备和DispatchRoutine的注册工作。当Driver被加载时,DriverEntry会被系统进程调用;DriverUnLoad在驱动被卸载时被调用,做回收资源操作,如删除创建的设备与设备符号连接、删除程序中定义的句柄等;DispatchRoutine是由一系列回调函数组成,系统在对设备进行操作或者响应设备中断时会调用这些回调函数。与此对应的,需要在User Mode中的APP编写驱动的加载函数LoadDriver,驱动的卸载函数UnLoadDriver以及APP给Driver的派遣函数IRP。APP指令与NT Driver指令的对应关系如图5.2所示。

图 5.2

 

    其中APP与NT Driver之间的通信流程如下图5.3所示。

图 5.3

 

    DispatchRoutine得到IRP函数后,根据MajorFunction找到对应的派遣函数,随后再根据MiniFunction完成相应的任务。

//////////////////////////////////////////////////////////////////////////////////////////

NT Driver代码如下:

#include "ntddk.h"typedef unsigned long DWORD;#define IN#define DEBUGMSG//IOCTL宏#define DEVICE_PCI_INDEX 0x860#define READ_PCI_INFO CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_PCI_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)#define NT_DEVICE_NAME L"\\Device\\wdkApp"#define DOS_DEVICE_NAME L"\\DosDevices\\wdkApp"   //符号连接 ,应该与App中的CreateFile里的“\\\\.\\wakApp对应起来”typedef struct _DEVICE_EXTENSION{  PDEVICE_OBJECT pDevice;  UNICODE_STRING DeviceName;  UNICODE_STRING SymLinkName;}DEVICE_EXTENSION,*PDEVICE_EXTENSION;VOID DriverUnload (IN PDRIVER_OBJECT DriverObject);NTSTATUS DispatchRoutine (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);extern "C"  NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {    NTSTATUS ntStatus = STATUS_SUCCESS;  PDEVICE_OBJECT lpDeviceObject = NULL;  UNICODE_STRING DeviceNameString = {0};  UNICODE_STRING DeviceLinkString = {0};  RtlInitUnicodeString(&DeviceNameString,NT_DEVICE_NAME);  //创建设备  ntStatus = IoCreateDevice(DriverObject,0,&DeviceNameString,FILE_DEVICE_UNKNOWN,0,false,&lpDeviceObject);  if (!NT_SUCCESS(ntStatus))  {    return ntStatus;  }  RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);   //创建符号链接  ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&DeviceNameString);  if (!NT_SUCCESS(ntStatus))   {     if (lpDeviceObject)     {       IoDeleteDevice(lpDeviceObject);     }     return ntStatus;   }   DriverObject->DriverUnload = DriverUnload;        DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine;       DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine;  return STATUS_SUCCESS;     }NTSTATUS DispatchRoutine (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp) {    NTSTATUS ntStatus=STATUS_SUCCESS;    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈    ULONG IoControlCodes=0;             //I/O控制代码     //设置IRP状态   pIrp->IoStatus.Status=STATUS_SUCCESS;   pIrp->IoStatus.Information=0;   #ifdef DEBUGMSG     DbgPrint("Starting HelloWorldDispatch()\n");   #endif   IrpStack=IoGetCurrentIrpStackLocation(pIrp);    //得到当前调用者的IRP   switch (IrpStack->MajorFunction)   {     case IRP_MJ_CREATE:         #ifdef DEBUGMSG           DbgPrint("IRP_MJ_CREATE\n");         #endif         break;     case IRP_MJ_DEVICE_CONTROL:         #ifdef DEBUGMSG           DbgPrint("IRP_MJ_DEVICE_CONTROL\n");         #endif        //取得I/O控制代码    IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode;     switch (IoControlCodes)    {      case READ_PCI_INFO:  {#ifdef DEBUGMSG DbgPrint("READ_PCI_INFO\n"); #endif//获得PCI设备信息ULONG *INBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;WRITE_PORT_ULONG((PULONG)0xCF8,INBuffer[0]);ULONG *OutBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;OutBuffer[0] = READ_PORT_ULONG((PULONG)0xCFC);#ifdef DEBUGMSG DbgPrint("%lx\n",OutBuffer[0]); #endifbreak;   }                 default:           pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER;          break;     }    break;    default:        break;    }     ntStatus=pIrp->IoStatus.Status; pIrp->IoStatus.Information = 4;    IoCompleteRequest(pIrp,IO_NO_INCREMENT);     return ntStatus; } VOID DriverUnload (IN PDRIVER_OBJECT DriverObject) {     UNICODE_STRING DeviceLinkString={0};     PDEVICE_OBJECT DeviceObjectTemp1=NULL;     PDEVICE_OBJECT DeviceObjectTemp2=NULL;     #ifdef DEBUGMSG       DbgPrint("Starting HelloWorldUnLoad()\n");     #endif     RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);     if (DeviceLinkString.Buffer)       IoDeleteSymbolicLink(&DeviceLinkString);     if (DriverObject)     {       DeviceObjectTemp1=DriverObject->DeviceObject;       while (DeviceObjectTemp1)       {         DeviceObjectTemp2=DeviceObjectTemp1;         DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;         IoDeleteDevice(DeviceObjectTemp2);       }     } } 

////////////////////////////////////////////////////////////////////////////////////

对应的APP代码如下:

// App.cpp#include "stdafx.h"#include <windows.h>#include <stdio.h>#define DEVICE_PCI_INDEX 0x860//IOCTL宏#define READ_PCI_INFO CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_PCI_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)//用来判断CreateFile是否成功int flag = 0;void TestDriver();//加载驱动//lpszDriverName:驱动程序在注册表中的名字//分为3部,1.新建驱动服务并判断是否有错误发生;2.打开驱动服务;3.开始驱动服务bool LoadNTDriver(wchar_t* lpszDriverName, wchar_t* lpszDriverPath) //驱动名&&驱动路径{wchar_t szDriverPath[MAX_PATH];GetFullPathName(lpszDriverPath, MAX_PATH, szDriverPath, NULL);printf("%s\n", szDriverPath);         //输出C,表示C盘SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (hSCM == NULL){printf("OpenSCManager error:%d\n", GetLastError());return false;}//创建驱动服务SC_HANDLE hDriver = CreateService(hSCM, lpszDriverName, lpszDriverName, SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,szDriverPath, NULL, NULL, NULL, NULL, NULL);DWORD dwError;if (hDriver == NULL){dwError = GetLastError();if (dwError != ERROR_IO_PENDING && dwError != ERROR_SERVICE_EXISTS){printf("CreateService error:%d\n", dwError);CloseServiceHandle(hSCM);return false;}else{printf("Service already Created.\n");}hDriver = OpenService(hSCM, lpszDriverName, SERVICE_ALL_ACCESS);if (hDriver == NULL){printf("OpenService error:%d\n", GetLastError());CloseServiceHandle(hSCM);return false;           }else{printf("OpenService OK!\n");}}else{printf("CreateService OK!\n");}dwError = StartService(hDriver,NULL,NULL);if (!dwError){dwError = GetLastError();if (dwError != ERROR_IO_PENDING && dwError != ERROR_SERVICE_ALREADY_RUNNING){printf("StartService error:%d\n", dwError);CloseServiceHandle(hSCM);CloseServiceHandle(hDriver);return false;}else{printf("Service already run\n");CloseServiceHandle(hSCM);CloseServiceHandle(hDriver);return true;}       }return true;}//卸载驱动//szSrvName:即为lpServiceName//3步:1.找到对应的驱动服务;2.停止此驱动服务;3.删除该驱动服务bool UnLoadNTDriver(wchar_t* szSrvName){SC_HANDLE hSCM = NULL;SC_HANDLE hSrv = NULL;hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);if (hSCM == NULL){printf("OpenSCManager error:%d\n", GetLastError());return false;}else{printf("OpenSCManager OK!\n");}hSrv = OpenService(hSCM, szSrvName, SERVICE_ALL_ACCESS);if (hSrv == NULL){printf("OpenService error:%d\n", GetLastError());CloseServiceHandle(hSCM);return false;           }else{printf("OpenService OK!\n");}SERVICE_STATUS ss;if (!ControlService(hSrv, SERVICE_CONTROL_STOP, &ss)){printf("ControlService error:%d\n", GetLastError());CloseServiceHandle(hSCM);CloseServiceHandle(hSrv);return false;}else{printf("ControlService ok!\n");}if (!DeleteService(hSrv)){printf("DeleteService error:%d\n", GetLastError());CloseServiceHandle(hSCM);CloseServiceHandle(hSrv);return false;}else{printf("DeleteService ok!\n");}return TRUE;}int main(void){bool bRet = LoadNTDriver(L"wdkApp",L"C:\\wdkApp.sys");if (!bRet){printf("LoadNTDriver error\n");return -1;}printf("Press any key to Test Driver!\n");getchar();TestDriver();printf("Press any key to Unload Driver!\n");getchar();bRet = UnLoadNTDriver(L"wdkApp");if (!bRet){printf("UnLoadNTDriver error\n");return -1;}return 0;}void TestDriver(){DWORD PCI_Addr,PCI_Data;DWORD bus,dev,func;ULONG nOutput;HANDLE hDriver = CreateFile(L"\\\\.\\wdkApp", GENERIC_READ|GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hDriver!= INVALID_HANDLE_VALUE){printf("Open Driver OK!\n");flag = 1;/* 接收数据 */for(bus = 0;bus<=0xFF;++bus){for (dev = 0; dev<=0x1F; ++dev){for (func = 0; func<=0x07; ++func){PCI_Addr = 0x80000000 + (bus<<16) + (dev<<11) + (func<<8);DeviceIoControl(hDriver,READ_PCI_INFO,&PCI_Addr,4,&PCI_Data,4,&nOutput,NULL);if((PCI_Data&0xFFFF)!=0xFFFF){printf("%04x\t%04x\t%04x\t%04x\t%04x\n",bus,dev,func,PCI_Data>>16,PCI_Data);}}}}getchar();}else{printf("Open Driver fail,error:%d\n", GetLastError());flag = 0;}CloseHandle(hDriver);}