对<<寒江独钓---Windows内核安全编程>>中第3章<<串口过滤>>的改进
<<寒江独钓>>中第3章的串口过滤只实现了对写操作的过滤, 没有实现对读操作的过滤, 这里, 我改进了一下, 去掉了原来对所有串口的过滤, 改成了只对指定的串口过滤; 增加了同时对读操作的过滤,其实主要就是调用IoSetCompletionRoutine设置完成回调函数.
源代码:
#include <ntddk.h> #include <ntstrsafe.h> /********************************************************** 文件名称:comdrv.c 文件路径:./comdrv/comdrv.c 创建时间:2013-1-29,14:18:08 文件作者:女孩不哭 文件说明:该程序是对<<寒江独钓>>中comcap串口过滤驱动程序的改进版, 改进: [+] 增加了对串口的读取操作的过滤(原来只有写操作) [-] 去掉了原来对所有串口(32个)的过滤,现在只对指定端口 [*] 优化了部分程序 **********************************************************/ //读操作请求计数 ULONG gReadRequestionCounter = 0; //我的设备 设备扩展定义 typedef struct{ PDEVICE_OBJECT pFltObj; PDEVICE_OBJECT pTopDev; }COMDRV_DEVEXT,*PCOMDRV_DEVEXT; //函数的前向声明 NTSTATUS comdrvOpenCom(ULONG comid, PDEVICE_OBJECT* ppOldObj); NTSTATUS comdrvAttachDevice(PDRIVER_OBJECT pDriver, PDEVICE_OBJECT pOldObj); void comdrvDriverUnload(PDRIVER_OBJECT pDriverObject); NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath); void PrintHexString(char* prefix, UCHAR* buffer, ULONG length); NTSTATUS comdrvDispatch(PDEVICE_OBJECT pDevice, PIRP pIrp); NTSTATUS comdrvWrite(PDEVICE_OBJECT pDevice, PIRP pIrp); NTSTATUS comdrvRead(PDEVICE_OBJECT pDevice, PIRP pIrp); NTSTATUS comdrvReadCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); //打开指定ID号的串口设备对象 NTSTATUS comdrvOpenCom(ULONG comid, PDEVICE_OBJECT* ppOldObj) { NTSTATUS status; UNICODE_STRING name; WCHAR str[32] = {0}; PFILE_OBJECT fileobj = NULL; PDEVICE_OBJECT devobj = NULL; RtlStringCchPrintfW(str, 32, L"\\Device\\Serial%d", comid); RtlInitUnicodeString(&name, str); status = IoGetDeviceObjectPointer(&name, FILE_ALL_ACCESS, &fileobj, &devobj); if(status == STATUS_SUCCESS) ObDereferenceObject(fileobj); *ppOldObj = devobj; return status; } //用指定的过虑设备绑定目标设备 NTSTATUS comdrvAttachDevice(PDRIVER_OBJECT pDriver, PDEVICE_OBJECT pOldObj) { NTSTATUS status; PDEVICE_OBJECT pTopDev = NULL; PDEVICE_OBJECT pFltObj; PDEVICE_OBJECT next; PCOMDRV_DEVEXT pDevExt; //创建过虑设备 status = IoCreateDevice(pDriver, sizeof(COMDRV_DEVEXT), NULL, pOldObj->DeviceType, 0, TRUE, &pFltObj); if(status != STATUS_SUCCESS) return status; //拷贝重要标志位 if(pOldObj->Flags & DO_BUFFERED_IO) pFltObj->Flags |= DO_BUFFERED_IO; if(pOldObj->Flags & DO_DIRECT_IO) pFltObj->Flags |= DO_DIRECT_IO; if(pOldObj->Characteristics & FILE_DEVICE_SECURE_OPEN) pFltObj->Flags |= DO_POWER_PAGABLE; //绑定到另一设备上 pTopDev = IoAttachDeviceToDeviceStack(pFltObj, pOldObj); if(pTopDev == NULL){ IoDeleteDevice(pFltObj); pFltObj = NULL; status = STATUS_UNSUCCESSFUL; return status; } pFltObj->Flags &= ~DO_DEVICE_INITIALIZING; pDevExt = (PCOMDRV_DEVEXT)pFltObj->DeviceExtension; pDevExt->pFltObj = pFltObj; pDevExt->pTopDev = pTopDev; return STATUS_SUCCESS; } //打印出内存的16进制 void PrintHexString(char* prefix, UCHAR* buffer, ULONG length) { int x; char* outbuf = NULL; char* poutbuf = NULL; //char* prefix = "comdrv_write:"; int buflen = length*3+3+strlen(prefix); do{ if(length == 0) break; outbuf = (char*)ExAllocatePool(NonPagedPool, buflen); if(outbuf == NULL){ KdPrint(("ExAllocatePool failed!\r\n")); break; } strcpy(outbuf, prefix); poutbuf = outbuf+strlen(prefix); for(x=0; x<length; x++){ sprintf(poutbuf, "%02X ", buffer[x]); poutbuf += 3; } sprintf(poutbuf, "\r\n"); KdPrint((outbuf)); ExFreePool(outbuf); }while(0); } //对写操作的处理 NTSTATUS comdrvWrite(PDEVICE_OBJECT pDevice, PIRP pIrp) { NTSTATUS status; PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp); PCOMDRV_DEVEXT pDevExt = (PCOMDRV_DEVEXT)pDevice->DeviceExtension; ULONG len = pIrpSp->Parameters.Write.Length; PUCHAR buf = NULL; if(pIrp->MdlAddress != NULL) buf = (PUCHAR)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); else buf = (PUCHAR)pIrp->UserBuffer; if(buf == NULL) buf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer; //打印出内容 PrintHexString("comdrv_write:", buf, len); IoSkipCurrentIrpStackLocation(pIrp); return IoCallDriver(pDevExt->pTopDev, pIrp); } //对读完成的处理 NTSTATUS comdrvReadCompletion(PDEVICE_OBJECT pDeviceObject, PIRP pIrp, PVOID pContext) { PIO_STACK_LOCATION CurIrp = NULL; ULONG length = 0; PUCHAR buffer = NULL; ULONG i; CurIrp = IoGetCurrentIrpStackLocation(pIrp); //在操作成功的前提下进行操作 if(NT_SUCCESS(pIrp->IoStatus.Status)){ //得到输出缓冲区 buffer = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer; length = pIrp->IoStatus.Information; //打印出读取到的内容 PrintHexString("comdrv_read:", buffer, length); } //读操作已完成,保持平衡 gReadRequestionCounter--; if(pIrp->PendingReturned) IoMarkIrpPending(pIrp); return pIrp->IoStatus.Status; } //对读操作的处理 NTSTATUS comdrvRead(PDEVICE_OBJECT pDevice, PIRP pIrp) { NTSTATUS status; PCOMDRV_DEVEXT pDevExt = NULL; PIO_STACK_LOCATION CurIrp = NULL; //错误处理 if(pIrp->CurrentLocation == 1){ ULONG ReturnedInfo = 0; KdPrint(("comdrv irp current location error\r\n")); status = STATUS_INVALID_DEVICE_REQUEST; pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = ReturnedInfo; return status; } //读操作增加 gReadRequestionCounter++; pDevExt = (PCOMDRV_DEVEXT)pDevice->DeviceExtension; //设置读完成回调函数并下发IRP CurIrp = IoGetCurrentIrpStackLocation(pIrp); IoCopyCurrentIrpStackLocationToNext(pIrp); IoSetCompletionRoutine(pIrp, comdrvReadCompletion, NULL, TRUE, TRUE, TRUE); return IoCallDriver(pDevExt->pTopDev, pIrp); } //通用分发函数 NTSTATUS comdrvDispatch(PDEVICE_OBJECT pDevice, PIRP pIrp) { NTSTATUS status; PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp); PCOMDRV_DEVEXT pDevExt = (PCOMDRV_DEVEXT)pDevice->DeviceExtension; //忽略所有电源操作 if(pIrpSp->MajorFunction == IRP_MJ_POWER){ PoStartNextPowerIrp(pIrp); IoSkipCurrentIrpStackLocation(pIrp); return PoCallDriver(pDevExt->pTopDev, pIrp); } //直接下发所有请求 IoSkipCurrentIrpStackLocation(pIrp); return IoCallDriver(pDevExt->pTopDev, pIrp); } void comdrvDriverUnload(PDRIVER_OBJECT pDriverObject) { #define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000) #define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000) LARGE_INTEGER li; PCOMDRV_DEVEXT pDevExt = NULL; li.QuadPart = 3*1000*DELAY_ONE_MILLISECOND; pDevExt = (PCOMDRV_DEVEXT)pDriverObject->DeviceObject->DeviceExtension; IoDetachDevice(pDevExt->pTopDev); while(gReadRequestionCounter) KeDelayExecutionThread(KernelMode, FALSE, &li); IoDeleteDevice(pDevExt->pFltObj); } NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { NTSTATUS status; int it; PDEVICE_OBJECT pDevObj = NULL; //我们只过滤读写操作,其它的操作交给下层驱动处理 for(it=0; it<IRP_MJ_MAXIMUM_FUNCTION; it++) pDriverObject->MajorFunction[it] = comdrvDispatch; pDriverObject->MajorFunction[IRP_MJ_WRITE] = comdrvWrite; pDriverObject->MajorFunction[IRP_MJ_READ] = comdrvRead; pDriverObject->DriverUnload = comdrvDriverUnload; //1代表COM2,2代表COM3, ... status = comdrvOpenCom(1, &pDevObj); if(!NT_SUCCESS(status)) return status; status = comdrvAttachDevice(pDriverObject, pDevObj); if(!NT_SUCCESS(status)) return status; return STATUS_SUCCESS; }
源代码下载:https://files.cnblogs.com/nbsofer/comdrv.7z
女孩不哭(QQ:191035066)@2013-02-25 13:59:23 http://www.cnblogs.com/nbsofer
2013-03-09:
发现一个原书中的错误,作者说Windows上的串口设备按串口号依次是\Device\Serial0,\Device\Serial1, ...
这在事实上是不正确的, 因为Prolific的PL2303 USB转RS232驱动生成的设备就不叫\Device\Serialx, 而叫\Device\ProlificSerialx, 这可让我调试程序花了好多时间, 找时间告诉作者.