Young87

当前位置:首页 >个人收藏

枚举内核句柄表(Windows内核学习笔记)

前面我写过有关内核句柄表的一些知识,今天来在这里跟大家分享一下我自己写的内核枚举进程句柄方法。

#include"EnumProcessHandleTable.h"



#ifdef   _WIN64 

#define  _HANDLE_TABLE_  0x200	//硬偏移Win7x64下的HANDLE_TABLE字段在EPROCESS下的偏移
#define  _OFFSET_        0x10	//TableCode中的第一项是用作审计,需要越过他到达HandleTableEntry
#define  _OBJECT_BODY_   0x30	//64位下,越过ObjectHeader到Body的偏移

typedef struct _HANDLE_TABLE
{
	ULONGLONG TableCode;                                                    //0x0
	PVOID QuotaProcess;														//0x8
	VOID* UniqueProcessId;                                                  //0x10
	ULONG64 HandleLock;														//0x18
	struct _LIST_ENTRY HandleTableList;                                     //0x20
	ULONG64 HandleContentionEvent;											//0x30
	PVOID DebugInfo;														//0x38
	LONG ExtraInfoPages;                                                    //0x40
	union
	{
		ULONG Flags;                                                        //0x44
		UCHAR StrictFIFO : 1;                                                 //0x44
	};
	ULONG FirstFreeHandle;                                                  //0x48
	struct _HANDLE_TABLE_ENTRY* LastFreeHandleEntry;                        //0x50
	ULONG HandleCount;                                                      //0x58
	ULONG NextHandleNeedingPool;                                            //0x5c
	ULONG HandleCountHighWatermark;                                         //0x60
}HANDLE_TABLE, *PHANDLE_TABLE;

typedef struct _HANDLE_TABLE_ENTRY
{
	union
	{
		VOID* Object;                                                       //0x0
		ULONG ObAttributes;                                                 //0x0
		struct _HANDLE_TABLE_ENTRY_INFO* InfoTable;                         //0x0
		ULONGLONG Value;                                                    //0x0
	};
	union
	{
		ULONG GrantedAccess;                                                //0x8
		struct
		{
			USHORT GrantedAccessIndex;                                      //0x8
			USHORT CreatorBackTraceIndex;                                   //0xa
		};
		ULONG NextFreeTableEntry;                                           //0x8
	};
}HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

#else    
#define  _HANDLE_TABLE_  0x0f4  //硬偏移Win7x86下的HANDLE_TABLE字段在EPROCESS下的偏移
#define  _OFFSET_        0x8	//TableCode中的第一项是用作审计,需要越过他到达HandleTableEntry
#define  _OBJECT_BODY_   0x18	//32位下,越过ObjectHeader到Body的偏移
typedef  struct _HANDLE_TABLE
{
	ULONG TableCode;                                                        //0x0
	PVOID QuotaProcess;														//0x4
	VOID* UniqueProcessId;                                                  //0x8
	ULONG HandleLock;														//0xc
	struct _LIST_ENTRY HandleTableList;                                     //0x10
	ULONG	HandleContentionEvent;											//0x18
	PVOID   DebugInfo;														//0x1c
	LONG ExtraInfoPages;                                                    //0x20
	union
	{
		ULONG Flags;                                                        //0x24
		UCHAR StrictFIFO : 1;                                               //0x24
	};
	ULONG FirstFreeHandle;                                                  //0x28
	PVOID LastFreeHandleEntry;												//0x2c
	ULONG HandleCount;                                                      //0x30
	ULONG NextHandleNeedingPool;                                            //0x34
	ULONG HandleCountHighWatermark;                                         //0x38
}HANDLE_TABLE, *PHANDLE_TABLE;

//0x8  结构体大小8字节
typedef struct _HANDLE_TABLE_ENTRY
{
	union
	{
		VOID* Object;                                                       //0x0
		ULONG ObAttributes;                                                 //0x0
		struct _HANDLE_TABLE_ENTRY_INFO* InfoTable;                         //0x0
		ULONG Value;                                                        //0x0
	};
	union
	{
		ULONG GrantedAccess;                                                //0x4
		struct
		{
			USHORT GrantedAccessIndex;                                      //0x4
			USHORT CreatorBackTraceIndex;                                   //0x6
		};
		ULONG NextFreeTableEntry;                                           //0x4
	};
}HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;


#endif


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
	UNREFERENCED_PARAMETER(RegisterPath);
	HANDLE   ProcessID = 0x0FDC;      //Taskmgr进程ID,此处给定一个值,为了在虚拟机调试驱动代码

	NTSTATUS Status = STATUS_SUCCESS;
	DbgPrint("Beginning!\r\n");

	DriverObject->DriverUnload = DriverUnload;//驱动卸载例程

	//枚举进程句柄表
	//这个函数必须在卸载函数的后面,否则可能导致驱动无法卸载
	EnumProcessHandleTable(ProcessID);

	return Status;
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);
	DbgPrint("DriverUnload()\r\n");
}

NTSTATUS  EnumProcessHandleTable(HANDLE ProcessID)
{
	PEPROCESS		EProcess = NULL;     //进程体指针
	PHANDLE_TABLE   HandleTable = NULL;
	NTSTATUS        Status = STATUS_SUCCESS;
	ULONG_PTR       TableCode = NULL;
	ULONG           Flag = NULL;
	__try
	{
		//the driver must call ObDereferenceObject to dereference the Process parameter received 
		//from the PsLookupProcessByProcessID routine.
		//必须调用ObReferenceObject解除引用
		Status = PsLookupProcessByProcessId(ProcessID,&EProcess);//通过进程ID获得进程体指针
		/*
		NTSTATUS NTAPI PsLookupProcessByProcessId(IN HANDLE ProcessId,OUT PEPROCESS *Process)
		{
			PHANDLE_TABLE_ENTRY CidEntry;
			PEPROCESS FoundProcess;
			NTSTATUS Status = STATUS_INVALID_PARAMETER;
			PAGED_CODE();
			PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId);
			KeEnterCriticalRegion();

	
			CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
			if (CidEntry)
			{

				FoundProcess = CidEntry->Object;

		
				if (FoundProcess->Pcb.Header.Type == ProcessObject)
				{
		
					if (ObReferenceObjectSafe(FoundProcess))
					{
						*Process = FoundProcess;
						Status = STATUS_SUCCESS;
					}
				}

	
				ExUnlockHandleTableEntry(PspCidTable, CidEntry);
			}
			KeLeaveCriticalRegion();
			return Status;
		}
		*/

		//MmIsAddressValid判断地址是否有效,内部实现是通过虚拟地址转换物理地址的方法
		if (NT_SUCCESS(Status) && MmIsAddressValid(EProcess))
		{
			/*
			kd> dt _Eprocess 894d13c0
			nt!_EPROCESS
			+0x000 Pcb              : _KPROCESS
			+0x098 ProcessLock      : _EX_PUSH_LOCK
			+0x0a0 CreateTime       : _LARGE_INTEGER 0x1d4e118`8f81a1dd
			+0x0a8 ExitTime         : _LARGE_INTEGER 0x0
			+0x0b0 RundownProtect   : _EX_RUNDOWN_REF
			+0x0b4 UniqueProcessId  : 0x00000e9c Void
			+0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x8495aba8 - 0x89756bd8 ]
			+0x0c0 ProcessQuotaUsage : [2] 0x1888
			+0x0c8 ProcessQuotaPeak : [2] 0x18c4
			+0x0d0 CommitCharge     : 0x278
			+0x0d4 QuotaBlock       : 0x8927f640 _EPROCESS_QUOTA_BLOCK
			+0x0d8 CpuQuotaBlock    : (null)
			+0x0dc PeakVirtualSize  : 0x5589000
			+0x0e0 VirtualSize      : 0x4cf5000
			+0x0e4 SessionProcessLinks : _LIST_ENTRY [ 0x8eb89010 - 0x895d4e24 ]
			+0x0ec DebugPort        : (null)
			+0x0f0 ExceptionPortData : 0x891f8858 Void
			+0x0f0 ExceptionPortValue : 0x891f8858
			+0x0f0 ExceptionPortState : 0y000
			+0x0f4 ObjectTable      : 0xa4b32f58 _HANDLE_TABLE

			0: kd> dd 0xa4b32f58
			a4b32f58  a5b29000 894d13c0 00000e9c 00000000
			a4b32f68  849544e8 a4b0d398 00000000 00000000
			a4b32f78  00000000 00000000 000001f4 a5b29ff8
			a4b32f88  00000074 00000800 00000080 0043005c
			a4b32f98  060d0209 73634946 00000000 87d4c930
			a4b32fa8  896fa2c0 a4b32fac 00000000 00000000
			a4b32fb8  896fa2ec 8854e478 00000000 00010001
			a4b32fc8  00000001 00000000 a4b65118 a4b39fd0

			0: kd> dt _Handle_Table 0xa4b32f58
			nt!_HANDLE_TABLE
			+0x000 TableCode        : 0xa5b29000
			+0x004 QuotaProcess     : 0x894d13c0 _EPROCESS
			+0x008 UniqueProcessId  : 0x00000e9c Void
			+0x00c HandleLock       : _EX_PUSH_LOCK
			+0x010 HandleTableList  : _LIST_ENTRY [ 0x849544e8 - 0xa4b0d398 ]
			+0x018 HandleContentionEvent : _EX_PUSH_LOCK
			+0x01c DebugInfo        : (null)
			+0x020 ExtraInfoPages   : 0n0
			+0x024 Flags            : 0
			+0x024 StrictFIFO       : 0y0
			+0x028 FirstFreeHandle  : 0x1f4
			+0x02c LastFreeHandleEntry : 0xa5b29ff8 _HANDLE_TABLE_ENTRY
			+0x030 HandleCount      : 0x74
			+0x034 NextHandleNeedingPool : 0x800
			+0x038 HandleCountHighWatermark : 0x80

			0: kd> dd 0xa5b29000
			a5b29000  00000000 fffffffe 8e6771e9 00000003
			a5b29010  894edde1 00100020 891d0f69 00100020
			a5b29020  a4b31cb9 00020019 896233c1 001f0001
			a5b29030  894c3d61 001f0001 98dd0819 000f003f
			a5b29040  8946a7e9 001f0003 9ceb4f59 00000001
			a5b29050  885e7bd9 00000804 88ad40e1 021f0003
			a5b29060  89234f91 000f037f 892776f1 000f01ff
			a5b29070  89234f91 000f037f 885ce351 00000804


			0: kd> !object 8e6771e8+ 0x18   //所有对象的Head 在32位下大小为0x18  64位下为0x30 越过头的偏移
			Object: 8e677200  Type: (871446a0) Directory
			ObjectHeader: 8e6771e8 (new version)
			HandleCount: 37  PointerCount: 83
			Directory Object: 8c005ed0  Name: KnownDlls

			Hash Address  Type          Name
			---- -------  ----          ----
			00  8e67f650 Section       gdi32.dll
			8e6430e8 Section       kernelbase.dll
			8c12dfd8 Section       IMAGEHLP.dll
			02  8c107450 Section       NORMALIZ.dll
			03  920b2a50 Section       ole32.dll
			9459cc58 Section       URLMON.dll
			04  969a8ee0 Section       USP10.dll
			05  976b4900 Section       DEVOBJ.dll
			976fa378 Section       api-ms-win-downlevel-user32-l1-1-0.dll
			06  977cf9c8 Section       CFGMGR32.dll
			8c122920 Section       SHELL32.dll
			8e648a60 Section       WLDAP32.dll
			07  977cf410 Section       api-ms-win-downlevel-version-l1-1-0.dll
			08  8e63e660 Section       api-ms-win-downlevel-ole32-l1-1-0.dll
			09  8c10f940 Section       user32.dll
			977cfa30 Section       profapi.dll
			14  980f0438 Section       MSASN1.dll
			16  8c1abf88 SymbolicLink  KnownDllPath
			977ed590 Section       COMCTL32.dll
			17  8c1cc330 Section       PSAPI.DLL
			969a8d80 Section       CRYPT32.dll
			18  8c122fd8 Section       OLEAUT32.dll
			8e678880 Section       advapi32.dll
			8e63e700 Section       api-ms-win-downlevel-normaliz-l1-1-0.dll
			19  8c1b2598 Section       SHLWAPI.dll
			8c1f4580 Section       IERTUTIL.dll
			969a8a98 Section       ntdll.dll
			20  8c114dd8 Section       WS2_32.dll
			21  8c191cb8 Section       LPK.dll
			980f0768 Section       USERENV.dll
			22  976d6ad8 Section       api-ms-win-downlevel-shlwapi-l1-1-0.dll
			8e7ff2e0 Section       sechost.dll
			23  8c12deb8 Section       COMDLG32.dll
			24  8e673948 Section       difxapi.dll
			25  8e68b990 Section       Setupapi.dll
			26  8e63bd70 Section       MSCTF.dll
			8c064da0 Section       WININET.dll
			27  8c1a1ea8 Section       IMM32.dll
			976fa850 Section       WINTRUST.dll
			28  8c11b238 Section       MSVCRT.dll
			31  8e648608 Section       rpcrt4.dll
			8c1f9fd8 Section       clbcatq.dll
			32  8e6628a8 Section       kernel32.dll
			34  969e5600 Section       api-ms-win-downlevel-advapi32-l1-1-0.dll
			35  8e689238 Section       NSI.dll


			*/
			HandleTable = (PHANDLE_TABLE)(*((ULONG_PTR*)((ULONG_PTR)EProcess + _HANDLE_TABLE_)));//0x0f4偏移
			if (MmIsAddressValid(HandleTable))
			{
				TableCode = (ULONG_PTR)(HandleTable->TableCode) & 0xFFFFFFFFFFFFFFFC;
				//当TableCode与FFFFFFC按位与的时候,C为 1100 所以会使TableCode的低两位全部变成00;
				//即通过按位与操作之后,会使TableCode变为真正的地址
				Flag = (ULONG)(HandleTable->TableCode) & 0x03;//得层数
				//当TableCode与0x03按位与的时候,3 为 0011 所以会使TableCode的低两位全部变成 00 01 10 11四种可能结果,
				//但是句柄表最多只有3层

				switch (Flag)
				{
				case 0:   //00
				{
					//单层表
					//511项
					Operation0(TableCode);
					break;
				}
				case 1:  //01
				{
					//双层表
					//1023项-》511+511
					Operation1(TableCode);
					break;
				}
				case 2:  //10
				{
					//三层表
					//1024-》1024-》511
					Operation2(TableCode);
					break;
				}
				default: //11
				{
					break;
				}
				}
			}
			else
			{
				Status = STATUS_UNSUCCESSFUL;
			}

			Status = STATUS_SUCCESS;
		}
		else
		{
			return STATUS_UNSUCCESSFUL;
		}

	}
	__except ((EXCEPTION_EXECUTE_HANDLER))
	{

	}
	if (NT_SUCCESS(Status))
	{
		ObReferenceObject(EProcess);
		EProcess = NULL;
	}

}

NTSTATUS Operation0(ULONG_PTR TableCode)
{
	PHANDLE_TABLE_ENTRY HandleTableEntry = NULL;
	ULONG Index = 0;
	HandleTableEntry = (PHANDLE_TABLE_ENTRY)((ULONG_PTR*)(TableCode + _OFFSET_));
	ULONG_PTR  ObjectCount = 0;

	for (Index = 0; Index<(PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)); Index++)
	{
		if (MmIsAddressValid((PVOID)HandleTableEntry))
		{

			PVOID ObjectHeader = (PVOID)(*(ULONG_PTR*)HandleTableEntry & 0xFFFFFFFFFFFFFFF8);
			//ObjectHeader 0x1000 大于8的值 全部变为8;小于8的全为0


			if (MmIsAddressValid(ObjectHeader))
			{
				PVOID ObjectBody = (PVOID)((ULONG_PTR)ObjectHeader + _OBJECT_BODY_);


				if (MmIsAddressValid(ObjectBody))   //这里应当判断对象是否合法
				{
					//打印数量以及ObjectBody的地址
					ObjectCount++;
					DbgPrint("ObjectCount:%d   ObjectBody:%p\r\n", ObjectCount,ObjectBody);	
				}


			}


		}
		HandleTableEntry++;     //结构体指针++ 越过当前这个结构体

	}
	return STATUS_SUCCESS;
}




NTSTATUS Operation1(ULONG_PTR TableCode)
{
	do
	{
		//枚举每一层的句柄表项
		Operation0(*(ULONG_PTR*)TableCode);
		TableCode += sizeof(ULONG_PTR);
	} while (*(PULONG_PTR)TableCode != 0 && MmIsAddressValid((PVOID)*(PULONG_PTR)TableCode));

	return STATUS_SUCCESS;
}


NTSTATUS  Operation2(ULONG_PTR TableCode)
{
	do
	{
		Operation1(*(ULONG_PTR*)TableCode);
		TableCode += sizeof(ULONG_PTR);
	} while (*(PULONG_PTR)TableCode != 0);

	return STATUS_SUCCESS;
}

“If you can take it,you can make it.”

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: Linux Kernel调度器的过去,现在和未来

下一篇: 7 年工作经验的程序员,从大厂跳槽出来后的处境 | 程序员有话说

精华推荐