例子驱动通信基础架构
1.Ring0编写驱动层代码:
//codemsg.h 定义通信控制代码 #ifndef _DEFINE_H_ #define _DEFINE_H_ // _number: 0 -> 2047 : reserved for Microsoft 微软保留 // 2047 -> 4095 : reserved for OEMs 用户自己定义 #define CODEMSG(_number) CTL_CODE(FILE_DEVICE_UNKNOWN, _number , METHOD_BUFFERED,\ FILE_READ_DATA | FILE_WRITE_DATA) //定义控制码 #define INIT_FILE_NAME 2047 #endif //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.h #ifndef _KERNEL_MODULE_H_ #define _KERNEL_MODULE_H_ #include <ntifs.h> #include "codemsg.h" //设备对象的名称 #define DEVICE L"\\Device\\www.AntiGameProtect.com" //链接符号的名称 #define DOSDEVICE L"\\DosDevices\\www.AntiGameProtect.com" PDEVICE_OBJECT DriverDeviceObject; #endif //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring0.c #include "Ring0.h" //驱动卸载例程函数,在这里释放一些资源。 VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; //删除符号链接 RtlInitUnicodeString(&DosDeviceName, DOSDEVICE); IoDeleteSymbolicLink(&DosDeviceName ); //删除驱动对象 if(DriverDeviceObject != NULL) IoDeleteDevice(DriverDeviceObject); DbgPrint("驱动卸载成功!\r\n"); } //默认的例程处理函数 NTSTATUS IODispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } //验证一个WCHAR内容的指针能否够訪问 BOOLEAN ValidateWCHARString(WCHAR *pwzStr, ULONG_PTR Length) { ULONG i; __try { //第一步推断指针和大小是否为NULL,是的话就不是必需验证了 if (*pwzStr == NULL || Length == 0) { return FALSE; } //以length长度循环检查指针pwzStr里面的值 for (i = 0; i < Length; i++) { //检查内存能否够訪问。 if (!MmIsAddressValid((PUCHAR)pwzStr + i)) { //仅仅要有一个字节是不可读取,就失败 return FALSE; } } }__except(EXCEPTION_EXECUTE_HANDLER) { //触发了异常 return FALSE; } return TRUE; } //IRP通信例程处理函数 NTSTATUS IOManager(PDEVICE_OBJECT DeviceObject, PIRP Irp) { //获取当前IrpStack,通过读取其结构成员,取出我们须要的控制码IRPcode PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp); //获取控制码IRPcode ULONG IRPcode = StackLocation->Parameters.DeviceIoControl.IoControlCode; WCHAR *buf; SIZE_T size; WCHAR *pwzCopyBuf = NULL; //获取应用层传进来的内存缓冲区 buf = (WCHAR*)Irp->AssociatedIrp.SystemBuffer; //内存缓冲区的字节长度 size = (SIZE_T)Irp->Size; //设置Irp的状态 Irp->IoStatus.Status = STATUS_SUCCESS; switch(IRPcode) { case CODEMSG(INIT_FILE_NAME): //从应用层传进来的buf,你无法预知这个值能否够訪问,所以,这里要验证我们传递进来的buf的有效性,才干够在驱动层訪问buf //所以,这里我写了一个ValidateWCHARString来验证这个变量 __try{ //推断Buffer的有效性 if (ValidateWCHARString(buf, size)) { //提示-应用层数据传到了驱动层 DbgPrint("Buf ==> %ws:%d\r\n", buf, size); //申请内存。相似应用层的new,并给于标识'fp' pwzCopyBuf = (WCHAR*)ExAllocatePoolWithTag(NonPagedPool, size, 'fp'); //假设申请内存成功 if (pwzCopyBuf) { //内存初始化 memset(pwzCopyBuf, 0, size); //copy到我们新申请的内存 memcpy(pwzCopyBuf,buf,size); //显示从应用层获取到的字符串信息 DbgPrint("CopyBuf ==> %ws\r\n", pwzCopyBuf); //在驱动以下用C语言来写,就要遵守windows的规则。申请的内存,必须要释放。 //要记得释放内存 ExFreePool(pwzCopyBuf); } } } __except (EXCEPTION_EXECUTE_HANDLER) { //获取异常的状态码 Irp->IoStatus.Status = GetExceptionCode(); } break; default: Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; } //设置Irp的返回码 IoCompleteRequest(Irp, IO_NO_INCREMENT); return Irp->IoStatus.Status; } //驱动的入口函数DriverEntry NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING theRegistryPath) { UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status; //初始化驱动符号名 //UNICODE_STRING是一个结构体,相似win32里面的结构体。比方SYSTEMTIME //在Win系统下,内核的结构体都是能够通过windbg或者wrk获得 /* lkd> dt_unicode_string nt!_UNICODE_STRING +0x000 Length : Uint2B //文本长度 +0x002 MaximumLength : Uint2B //最大长度 +0x004 Buffer : Ptr32 Uint2B //文本内容。是unicode类型,即WCHAR */ //设备名称字符串 RtlInitUnicodeString(&DeviceName, DEVICE); //符号链接字符串 RtlInitUnicodeString(&DosDeviceName, DOSDEVICE); //创建设备对象 status = IoCreateDevice( DriverObject, // ptr to caller object 0, // extension device allocated byte number &DeviceName, // device name FILE_DEVICE_UNKNOWN, 0, // no special caracteristics FALSE, // we can open many handles in same time &DeviceObject); // [OUT] ptr to the created object if (!NT_SUCCESS(status)) { return STATUS_NO_SUCH_DEVICE; } //相同也须要一个符号链接。不然会影响到驱动和应用层的通信 status = IoCreateSymbolicLink(&DosDeviceName,&DeviceName); if(!NT_SUCCESS(status)) { IoDeleteDevice(DriverDeviceObject); return STATUS_NO_SUCH_DEVICE; } //设置驱动卸载例程函数 DriverObject->DriverUnload = DriverUnload; //IRP_MJ_CREATE。响应的是应用层函数CreateFile,应用层调用这个函数就会进入这个例程 DriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch; //以下的分别相应应用层CloseHandle、ReadFile、WriteFile函数 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IODispatch; DriverObject->MajorFunction[IRP_MJ_READ] = IODispatch; DriverObject->MajorFunction[IRP_MJ_WRITE] = IODispatch; //一般我们跟应用层通信,都是通过IRP_MJ_DEVICE_CONTROL例程,这个例程相应的是应用层下的DeviceIoControl DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager; //DeviceIoControl() //设置通信方式--直接方式I/O DeviceObject->Flags |= DO_BUFFERED_IO; //设置文件字对齐 DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; //设备初始化完成能够工作了 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; //提示驱动载入成功 DbgPrint("Hello Driver !\r\n"); return STATUS_SUCCESS; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Ring3.cpp #include <windows.h> #include <stdio.h> //包括控制码的头文件 #include "..\Ring0\codemsg.h" //向驱动发送请求 BOOL CallDriver(char *ID,char *lpBuffer) { HANDLE service = 0; HANDLE device = 0; char ret[1024]; WCHAR ToSend[512]; DWORD code = -1; DWORD bytes; //通过符号连接打开设备对象 device = CreateFile("\\\\.\\www.AntiGameProtect.com", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if( !device || device==INVALID_HANDLE_VALUE ) { printf("打开驱动失败,驱动载入不成功. %d\r\n",GetLastError()); return FALSE; } //推断输入的命令是否是"-file" if(!strcmp(ID,"-file")) { //相应我们驱动以下的控制码。code = INIT_FILE_NAME; } //推断驱动的控制码是否有效 if (code == -1) { printf("无效的ID\r\n"); return FALSE; } //将ascii码lpBuffer字符串转unicode码字符串ToSend MultiByteToWideChar(CP_ACP, 0, lpBuffer, -1, ToSend, sizeof(ToSend)); DeviceIoControl(device, CODEMSG(code), //驱动的控制码 ToSend, //输入缓冲区 (wcslen(ToSend)+1)*2, //输入缓冲区的大小 &ret, //输出缓冲区 sizeof(ret), //输出缓冲区的大小 &bytes, //返回的字节数 NULL); //关闭驱动文件 CloseHandle(device); printf("完毕!\r\n"); return TRUE; } //main函数 void main(int argc,char *argv[]) { //推断用户输入的合法性 if (argc != 3) { printf("Example:%s ID CommandLine\r\n",argv[0]); return; } //调用驱动的代码 CallDriver(argv[1], argv[2]); return; }
版权声明:本文博主原创文章。博客,未经同意不得转载。