XPsp3键盘设备链/栈信息_01_Code

WDK: GRMWDK_EN_7600_1.ISO

XP SP3 : zh-hans_windows_xp_professional_with_service_pack_3_x86_cd_vl_x14-74070.iso

 

1、zcFirst.c

#include <wdm.h>

// Kbdclass驱动的名字
#define KBD_DRIVER_NAME  L"\\Driver\\Kbdclass"



// 这个函数是事实存在的,只是文档中没有公开。声明一下
// 就可以直接使用了。
NTSTATUS
ObReferenceObjectByName(
                        PUNICODE_STRING ObjectName,
                        ULONG Attributes,
                        PACCESS_STATE AccessState,
                        ACCESS_MASK DesiredAccess,
                        POBJECT_TYPE ObjectType,
                        KPROCESSOR_MODE AccessMode,
                        PVOID ParseContext,
                        PVOID *Object
                        );
NTSTATUS ObQueryNameString(
  IN      PVOID                    Object,
  OUT     POBJECT_NAME_INFORMATION ObjectNameInfo,
  IN      ULONG                    Length,
  OUT     PULONG                   ReturnLength
);

extern POBJECT_TYPE IoDriverObjectType; // ZC: 这个变量是定义在WDK的头文件中的?(wdm.h中?)
ULONG g_C2pKeyCount = 0;
PDRIVER_OBJECT g_DriverObject = NULL;

// ZC: 得到设备对象_pDeviceObject的 某些信息
NTSTATUS ShowInfo_DeviceObject(PDEVICE_OBJECT _pDeviceObject)
{
    NTSTATUS status = 0;
    ULONG ulRtnLen = 0;

    KdPrint(("_pDeviceObject->DeviceType : 0x%08X, _pDeviceObject->Characteristics : 0x%08X\n",
        _pDeviceObject->DeviceType, _pDeviceObject->Characteristics));
    KdPrint(( "STATUS_INFO_LENGTH_MISMATCH : 0x%08X\n", STATUS_INFO_LENGTH_MISMATCH ));

    // ZC: 显示设备对象的名称
    status = ObQueryNameString(_pDeviceObject, NULL, 0, &ulRtnLen);
    if (status == STATUS_INFO_LENGTH_MISMATCH)
    {
        POBJECT_NAME_INFORMATION pObjNameInfo = NULL;
        KdPrint(( "ObQueryNameString - ulRtnLen(1) : 0x%08X\n", ulRtnLen ));
        pObjNameInfo = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool, ulRtnLen);
        status = ObQueryNameString(_pDeviceObject, pObjNameInfo, ulRtnLen, &ulRtnLen);
        if (status == STATUS_SUCCESS)
        {
            //KdPrint(( "ObQueryNameString - ulRtnLen(2) : 0x%08X\n", ulRtnLen ));
            if (pObjNameInfo->Name.Length > 0)
                KdPrint(( "ObQueryNameString - objNameInfo : %wZ\n", &(pObjNameInfo->Name) ));
            else
                KdPrint(( "ObQueryNameString - objNameInfo is empty .\n" ));
        }
        else
        {
            KdPrint(( "ObQueryNameString failed : 0x%08X\n", status ));
        }
        ExFreePool(pObjNameInfo);
    }
    return status;
}

// ZC: 遍历设备栈
// ZC: 输入参数_pDeviceObject : 设备栈中的一个 设备对象的指针 (这个设备对象 不一定是位于 设备栈中的哪个位置)
NTSTATUS EnumDeviceStack(PDEVICE_OBJECT _pDeviceObject)
{
    NTSTATUS status = 0;
    PDEVICE_OBJECT pDeviceObject = _pDeviceObject;
    int iIdxStack = 0;

    // (1)、不管 _pDeviceObject位于设备栈的哪个位置,往上找到设备栈中的第一个设备对象
    while (pDeviceObject->AttachedDevice != NULL)
    {
        pDeviceObject = pDeviceObject->AttachedDevice;
    }

    // (2)、从 设备栈中的第一个设备对象 开始,往下遍历 所有 设备对象
    while (TRUE)
    {
        PDEVICE_OBJECT *ppDevObj_AttachedTo = NULL;
        PDEVOBJ_EXTENSION pDevObjExt = NULL;

        KdPrint(( "Stack[%d] -- message begin :\n", iIdxStack ));
        iIdxStack ++;

        status = ShowInfo_DeviceObject(pDeviceObject);
        if (! NT_SUCCESS(status))
            break;

        pDevObjExt = pDeviceObject->DeviceObjectExtension;
        if (pDevObjExt == NULL)
            break;
        KdPrint(( "pDevObjExt->Size : 0x%08X\n", pDevObjExt->Size ));
        KdPrint(( "pDevObjExt->Type : 0x%08X\n", pDevObjExt->Type ));
        //KdPrint(( "&DeviceObject : 0x%08X, 0x%08X\n", pDeviceObject, pDevObjExt->DeviceObject ));
        //{
        //    PDEVICE_OBJECT * pp = (PDEVICE_OBJECT*)((unsigned long)pDevObjExt + 0x4);
        //    KdPrint(( "0x%08X, 0x%08X\n", pp, (*pp) ));
        //}
        KdPrint(( "Stack[%d] -- message end .\n\n", iIdxStack ));

//0x018
        // ZC: 往下遍历
        // ZC: 下面的运算是 根据WinDBG加载过符号表之后执行命令“dt _DEVOBJ_EXTENSION”得到的运算方式。
        // ZC: 可能不同的Windows版本会有差异,要注意
        ppDevObj_AttachedTo = (PDEVICE_OBJECT*)((unsigned long)pDevObjExt + 0x18);
        if ( (*ppDevObj_AttachedTo) != NULL )
            pDeviceObject = (*ppDevObj_AttachedTo);
        else
            break;
    }

    return status;
}

// ZC: 遍历设备链
// ZC: 传入参数 _pDeviceObject : 1个驱动程序(驱动对象)中的 设备链中的 第1个设备对象 的指针
NTSTATUS EnumDeviceChain(PDEVICE_OBJECT _pDeviceObject)
{
    NTSTATUS status = 0;
    int iIdxChain = 0;

    // 这是设备链中的第一个设备    
    PDEVICE_OBJECT pTargetDeviceObject = _pDeviceObject;
    // 现在开始遍历这个设备链
    while (pTargetDeviceObject) 
    {
        KdPrint(( "Chain[%d] :\n", iIdxChain ));
        iIdxChain ++;

        status = EnumDeviceStack(pTargetDeviceObject);
        if (! NT_SUCCESS(status))
            break;

        //next device 
        pTargetDeviceObject = pTargetDeviceObject->NextDevice;
    }// while

    return status;
}





// 这个函数经过改造。能打开驱动对象Kbdclass,然后绑定
// 它下面的所有的设备:
NTSTATUS 
c2pAttachDevices(
                  IN PDRIVER_OBJECT _DriverObject,
                  IN PUNICODE_STRING _RegistryPath)
{
    NTSTATUS status = 0;
    UNICODE_STRING uniNtNameString;
    //PC2P_DEV_EXT devExt;
    PDEVICE_OBJECT pFilterDeviceObject = NULL;
    PDEVICE_OBJECT pTargetDeviceObject = NULL;
    PDEVICE_OBJECT pLowerDeviceObject = NULL;

    PDRIVER_OBJECT KbdDriverObject = NULL;

    KdPrint(("MyAttach\n"));

    // 初始化一个字符串,就是Kdbclass驱动的名字。
    RtlInitUnicodeString(&uniNtNameString, KBD_DRIVER_NAME); 
    // 请参照前面打开设备对象的例子。只是这里打开的是驱动对象。
    status = ObReferenceObjectByName ( 
        &uniNtNameString, 
        OBJ_CASE_INSENSITIVE, 
        NULL, 
        0, 
        IoDriverObjectType, 
        KernelMode, 
        NULL, 
        &KbdDriverObject 
        ); 
    // 如果失败了就直接返回
    if(! NT_SUCCESS(status)) 
    { 
        KdPrint(("MyAttach: Couldn't get the MyTest Device Object\n"));
        KdPrint(("ObReferenceObjectByName return : 0x%08X\n", status));
        return( status ); 
    }
    else
    {
        // 这个打开需要解应用。早点解除了免得之后忘记。
        ObDereferenceObject(_DriverObject);
    }

    status = EnumDeviceChain(KbdDriverObject->DeviceObject);
    return status; 
}

// 提供一个Unload函数只是为了 (ZC: 动态卸载)
VOID DriverUnload(PDRIVER_OBJECT _DriverObject)
{
    // 但是实际上我们什么都不做,只打印一句话:
    DbgPrint("zcFirst: Our driver is unloading…\n");
}

NTSTATUS DriverEntry( 
                     IN PDRIVER_OBJECT _DriverObject, 
                     IN PUNICODE_STRING _RegistryPath 
                     ) 
{ 
    ULONG i; 
    NTSTATUS status = STATUS_SUCCESS; 
    KdPrint (("zcFirst.SYS: entering DriverEntry\n")); 
/*
    // 填写所有的分发函数的指针
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) 
    { 
        DriverObject->MajorFunction[i] = c2pDispatchGeneral; 
    } 

    // 单独的填写一个Read分发函数。因为要的过滤就是读取来的按键信息
    // 其他的都不重要。这个分发函数单独写。
    DriverObject->MajorFunction[IRP_MJ_READ] = c2pDispatchRead; 

    // 单独的填写一个IRP_MJ_POWER函数。这是因为这类请求中间要调用
    // 一个PoCallDriver和一个PoStartNextPowerIrp,比较特殊。
    DriverObject->MajorFunction [IRP_MJ_POWER] = c2pPower; 

    // 我们想知道什么时候一个我们绑定过的设备被卸载了(比如从机器上
    // 被拔掉了?)所以专门写一个PNP(即插即用)分发函数
    DriverObject->MajorFunction [IRP_MJ_PNP] = c2pPnP; 
*/
    // 卸载函数。
    _DriverObject->DriverUnload = DriverUnload;//c2pUnload; 
//    gDriverObject = DriverObject;

    KdPrint(("zcFirst.sys _DriverObject : 0x%08X\n", _DriverObject));
#if DBG
    //_asm int 3
#endif

    // 绑定所有键盘设备
    status = c2pAttachDevices(_DriverObject, _RegistryPath);

    return status; 
}

 

2、makefile

!IF 0

Copyright (C) Microsoft Corporation, 1997 - 1998

Module Name:

    makefile.

!ENDIF

#
# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
# file to this component.  This file merely indirects to the real make file
# that is shared by all the components of Windows NT
#

#
# if building in a DDK environment
#
!IF defined(DDK_TARGET_OS)

#
# ensure that said build environment is at least Windows XP
# 0x500 == Windows 2000
# 0x501 == Windows XP
# 0x502 == Windows .NET
#
!    IF defined(_NT_TARGET_VERSION) && $(_NT_TARGET_VERSION)>=0x501
!        INCLUDE $(NTMAKEENV)\makefile.def
!    ELSE
!        message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target.
!    ENDIF

!ELSE

#
# not a DDK environment, probably RAZZLE, so build
#
!    INCLUDE $(NTMAKEENV)\makefile.def

!ENDIF

 

3、source

!IF 0

Copyright (C) Microsoft Corporation, 1997 - 1999

Module Name:

    sources.

!ENDIF

TARGETNAME=zcFirst
TARGETPATH=obj
TARGETTYPE=DRIVER

SOURCES =zcFirst.c

 

4、

5、

 

posted @ 2016-12-19 14:23  DriverSkill  阅读(301)  评论(0编辑  收藏  举报