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// Kbdclass驱动的名字#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass"// 这个函数是事实存在的,只是文档中没有公开。声明一下// 就可以直接使用了。NTSTATUSObReferenceObjectByName( 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 0Copyright (C) Microsoft Corporation, 1997 - 1998Module 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 0Copyright (C) Microsoft Corporation, 1997 - 1999Module Name: sources.!ENDIFTARGETNAME=zcFirstTARGETPATH=objTARGETTYPE=DRIVERSOURCES =zcFirst.c
4、
5、