• 抬起头,继续前进吧,去把这个不完美的故事,变成你成所期望的样子
  • 登山路上我们会放弃很多东西,但这些被我们丢掉在我们登上山顶之际,都会一一回来
  • 不论开发还是逆向,数学水平的高低直接决定了”你的饭碗里有没有肉”
  • 万丈高楼平地起,勿在浮沙筑高台

Windows驱动开发-串口过滤驱动示例

C++ 菜鸟 6个月前 (02-01) 1357次浏览 已收录 0个评论
[隐藏]

Windows 驱动开发-串口过滤驱动示例

一、前言

串口这个一般来说已经非常少用,但在学习过滤驱动时,串口过滤驱动可以很好的让我们对过滤驱动有一个很好的认识。
使用工具:
Debug View
Device Tree

二、流程

菜鸟写了一个 NT 式串口过滤驱动,如果熟悉设备栈以及驱动程序的组成,其实也没啥好讲,主要操作如下:
        1、打开串口设备,获得设备对象
        2、创建过滤设备,附加到串口的设备栈上
具体细节我们在代码中来看。

三、主要代码

打开串口设备,封装一个函数

#pragma PAGEDCODE
PDEVICE_OBJECT OpenCom(ULONG ulID, NTSTATUS *pNtStatus)
{
    PAGED_CODE();
    UNICODE_STRING ustrObjectName;

    UNICODE_STRING ustrDriverObjectName;
    static WCHAR wszObjectName[32] = { 0 };
    PFILE_OBJECT pstFileObject = NULL;
    PDEVICE_OBJECT pstDeviceObject = NULL;
    // Get serial port name.
    RtlStringCchPrintfW(wszObjectName, 32, L"\\Device\\Serial%d", ulID);
    RtlInitUnicodeString(&ustrObjectName, wszObjectName);

    // Open device object.
    *pNtStatus = IoGetDeviceObjectPointer(&ustrObjectName,
                                          FILE_ALL_ACCESS,
                                          &pstFileObject,
                                          &pstDeviceObject);
    if (STATUS_SUCCESS == *pNtStatus)
    {
        ObDereferenceObject(pstFileObject);
    }

    return pstDeviceObject;
} //! OpenCom() END

创建设备并附加到串口的设备栈上

#pragma PAGEDCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pstDriverObject)
{
    PAGED_CODE();
    NTSTATUS ntStatus;
    PDEVICE_OBJECT pstDeviceObject = NULL;
    PDEVICE_EXTENSION pstDeviceExtension = NULL;
    PDEVICE_OBJECT pstSerialPortDeviceObject = NULL;

    for (size_t cntI = 0; cntI < SERIAL_PORT_NUMBER; cntI++)
    {
        pstSerialPortDeviceObject = OpenCom(cntI, &ntStatus);
        if (!NT_SUCCESS(ntStatus))
        {
            KdPrint(("Open COM failed.\r\n"));
            continue;
        }

        ntStatus = IoCreateDevice(pstDriverObject,
                                  sizeof(*pstDeviceExtension),
                                  NULL,
                                  FILE_DEVICE_UNKNOWN,
                                  pstSerialPortDeviceObject->Characteristics,
                                  TRUE,
                                  &pstDeviceObject);
        if (!NT_SUCCESS(ntStatus))
        {
            KdPrint(("Create Device faile.\r\n"));
            return ntStatus;
        }

        if (pstSerialPortDeviceObject->Flags & DO_BUFFERED_IO)
        {
            pstDeviceObject->Flags |= DO_BUFFERED_IO;
        }

        if (pstSerialPortDeviceObject->Flags & DO_DIRECT_IO)
        {
            pstDeviceObject->Flags |= DO_DIRECT_IO;
        }

        PDEVICE_OBJECT pstNextDeviceObject = NULL;
        ntStatus = 
            IoAttachDeviceToDeviceStackSafe(pstDeviceObject,
                                            pstSerialPortDeviceObject,
                                            &pstNextDeviceObject);
        if (!NT_SUCCESS(ntStatus))
        {
            KdPrint(("Create Device faile.\r\n"));
            IoDeleteDevice(pstDeviceObject);
            return ntStatus;
        }

        pstDeviceExtension = 
            (PDEVICE_EXTENSION)(pstDeviceObject->DeviceExtension);
        pstDeviceExtension->pstDeviceObject_ = pstDeviceObject;
        pstDeviceExtension->pstNextDeviceObject_ = pstNextDeviceObject;

        // Set device has started.
        pstSerialPortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
    }

    return STATUS_SUCCESS;
} //! CreateDevice() END

分发处理中,电源信息和除了写 IRP 的都直接发到下一层驱动处理。对于写 IRP 则简单打印下信息。

#pragma PAGEDCODE
NTSTATUS DefaultDispatchRoutine(IN PDEVICE_OBJECT pstDeviceObject,
                                IN PIRP pstIrp)
{
    PAGED_CODE();
    KdPrint(("Enter DefaultDispatchRoutine\n"));

    do
    {
        PIO_STACK_LOCATION pstStackLocation = 
            IoGetCurrentIrpStackLocation(pstIrp);
        if (NULL == pstStackLocation)
        {
            KdPrint(("The current stack location is NULL.\r\n"));
            break;
        }
        PDEVICE_EXTENSION pstDeviceExtension = 
            (PDEVICE_EXTENSION)pstDeviceObject->DeviceExtension;

        // Power irp.
        if (IRP_MJ_POWER == pstStackLocation->MajorFunction)
        {
            PoStartNextPowerIrp(pstIrp);
            IoSkipCurrentIrpStackLocation(pstIrp);
            return PoCallDriver(pstDeviceExtension->pstNextDeviceObject_, 
                                pstIrp);
        }

        // Write irp.
        if (IRP_MJ_WRITE == pstStackLocation->MajorFunction)
        {
            ULONG ulLen = pstStackLocation->Parameters.Write.Length;
            PUCHAR pucBuffer = NULL;
            if (NULL != pstIrp->MdlAddress)
            {
                pucBuffer =
                    (PUCHAR)MmGetSystemAddressForMdlSafe(pstIrp->MdlAddress,
                                                         NormalPagePriority);
            }
            else if (NULL != pstIrp->UserBuffer)
            {
                pucBuffer = (PUCHAR)pstIrp->UserBuffer;
            }
            else
            {
                pucBuffer = (PUCHAR)pstIrp->AssociatedIrp.SystemBuffer;
            }

            if (NULL == pucBuffer)
            {
                KdPrint(("All buffer are NULL.\r\n"));
                break;
            }

            for (ULONG cntI = 0; cntI < ulLen; cntI++)
            {
                KdPrint(("COM Send Data: %c\r\n", pucBuffer[cntI]));
            }
        } //! if 'Write irp' END

        IoSkipCurrentIrpStackLocation(pstIrp);
        return IoCallDriver(pstDeviceExtension->pstNextDeviceObject_, pstIrp);
    } while (FALSE);

    KdPrint(("Leave DefaultDispatchRoutine\n"));
    pstIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    pstIrp->IoStatus.Information = 0;
    IoCompleteRequest(pstIrp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
} //! DefaultDispatchRoutine() END

删除设备时注意要先解绑

#pragma PAGEDCODE
VOID DriverUnload(IN PDRIVER_OBJECT pstDriverObject)
{
    PAGED_CODE();

    PDEVICE_OBJECT pstNextDeviceObject = NULL;
    PDEVICE_EXTENSION pstDeviceExtension = NULL;
    NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
    ULONG ulDeviceObjectNumber = 0;
    PDEVICE_OBJECT *apstDeviceObejctList = NULL;
    ULONG ulDeiveObjectListSize = 0;

    KdPrint(("Enter DriverUnload\n"));

    // Delete device and symbol.
    do
    {
        // Get number of device object.
        ntStatus = IoEnumerateDeviceObjectList(pstDriverObject,
                                               NULL,
                                               0,
                                               &ulDeviceObjectNumber);
        ulDeiveObjectListSize = sizeof(PDEVICE_OBJECT) * ulDeviceObjectNumber;

        // Allocate memory.
        apstDeviceObejctList = 
            (PDEVICE_OBJECT *)
            ExAllocatePoolWithTag(PagedPool,
                                  ulDeiveObjectListSize,
                                  DEVICE_OBJECT_LIST_TAG);
        if (NULL == apstDeviceObejctList)
        {
            KdPrint(("ExAllocatePoolWithTag failed.\r\n"));
            break;
        }

        // Get device object list.
        ntStatus = IoEnumerateDeviceObjectList(pstDriverObject,
                                               apstDeviceObejctList,
                                               ulDeiveObjectListSize,
                                               &ulDeviceObjectNumber);
        if (!NT_SUCCESS(ntStatus))
        {
            KdPrint(("IoEnumerateDeviceObjectList failed.\r\n"));
            break;
        }

        for (ULONG cntI = 0; cntI < ulDeviceObjectNumber; cntI++)
        {
            // Normal check.
            if (NULL == apstDeviceObejctList[cntI])
            {
                continue;
            }

            ObDereferenceObject(apstDeviceObejctList[cntI]);
            pstDeviceExtension = 
                (PDEVICE_EXTENSION)apstDeviceObejctList[cntI]->DeviceExtension;

            if (NULL != pstDeviceExtension &&
                NULL != pstDeviceExtension->pstNextDeviceObject_)
            {
                IoDetachDevice(pstDeviceExtension->pstNextDeviceObject_);
            }

            IoDeleteDevice(apstDeviceObejctList[cntI]);
        }
    } while (false); //! do 'Delete device and symbol' while END 

    // Free memory.
    if (NULL != apstDeviceObejctList)
    {
        ExFreePoolWithTag(apstDeviceObejctList, DEVICE_OBJECT_LIST_TAG);
    }
} //! DriverUnload() END

四、测试

驱动服务已经启动,用 DeviceTree 查看下串口设备栈。(点击查看大图)
Windows 驱动开发-串口过滤驱动示例
打开 Debug View,然后用自己写的 TestSerialTool 来测试下。(点击查看大图)
Windows 驱动开发-串口过滤驱动示例
Debug View 中的输出。(点击查看大图)
Windows 驱动开发-串口过滤驱动示例

五、完整工程

SerialFilter

六、小结

万事开头难,在度过难关后,踩过的坑多了,慢慢路就平坦了,关键就是去做。Just do it! Happy coding! ^_^


学习心得 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明Windows 驱动开发-串口过滤驱动示例
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址