Windows中有两种句柄表分别是:
全局句柄表与私有句柄表使用一个结构体
在三环调用API需要调用ID打开句柄的有:
句柄表中存放的是指针,32位就是32位指针
x64 算法:
进程ID / 4 = 表索引
表索引 * 16 = 全局句柄表条目
x86算法:
进程ID / 4 = 表索引
表索引 * 8 = 全局句柄表条目
为什么 * 8 因为每一项占8字节,前4字节为头,后4字节为地址
选择某目标进程获取到PID2220:
可以使用PspCidTable来寻找句柄表指针:
kd> dq PspCidTable
fffff800`0403dbc8 fffff8a0`00004970 00000000`00000000
fffff800`0403dbd8 ffffffff`8000001c 00000000`00000101
fffff800`0403dbe8 ffffffff`800002bc ffffffff`80000024
fffff800`0403dbf8 00000000`00000000 00000000`00000113
fffff800`0403dc08 00000000`00000000 00000000`00000000
fffff800`0403dc18 fffff800`03f98b40 00000000`00000000
fffff800`0403dc28 00000000`00000000 00000000`00000000
fffff800`0403dc38 00000000`00000000 00000000`00000008
查看_handle_table结构相关信息:
kd> dt _handle_table fffff8a0`00004970
nt!_HANDLE_TABLE
+0x000 TableCode : 0xfffff8a0`01738001
+0x008 QuotaProcess : (null)
+0x010 UniqueProcessId : (null)
+0x018 HandleLock : _EX_PUSH_LOCK
+0x020 HandleTableList : _LIST_ENTRY [ 0xfffff8a0`00004990 - 0xfffff8a0`00004990 ]
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 DebugInfo : (null)
+0x040 ExtraInfoPages : 0n0
+0x044 Flags : 1
+0x044 StrictFIFO : 0y1
+0x048 FirstFreeHandle : 0x8a8
+0x050 LastFreeHandleEntry : 0xfffff8a0`01739980 _HANDLE_TABLE_ENTRY
+0x058 HandleCount : 0x20f
+0x05c NextHandleNeedingPool : 0xc00
+0x060 HandleCountHighWatermark : 0x264
其中tableCode记录了表级与表地址,HandleCount记录了当前句柄表中有多少个句柄,在tableCode最后一位说明了句柄表中有几层:
0xfffff8a0`01738001 代表句柄表中有两层
当最后一位为0时,代表直接指向句柄表,当最后一位为1时代表指向一个数组,数组中的值才指向的是句柄,这个数组可以存放句柄表的指针,为2时就变成了一个三维数组
代码表示为:
X86下_HANDLE_TABLE_ENTRY结构大小为8,x64下结构大小为16,每张表4k大小4k/16=256,所以一张表可以存256个handle。二级三级表存放指针,x64下一个指针地址占用8字节,x86下占用4字节。4k/8=512
/*为0时*/
Handle Handle_table[256] = {};
/*为1时*/
Handle_table Handle_table[512][0] = Handle_table;
查看数组发现了三个handle表:
kd> dq 0xfffff8a0`01738000
fffff8a0`01738000 fffff8a0`00005000 fffff8a0`01739000
fffff8a0`01738010 fffff8a0`01bdc000 00000000`00000000
fffff8a0`01738020 00000000`00000000 00000000`00000000
fffff8a0`01738030 00000000`00000000 00000000`00000000
fffff8a0`01738040 00000000`00000000 00000000`00000000
fffff8a0`01738050 00000000`00000000 00000000`00000000
fffff8a0`01738060 00000000`00000000 00000000`00000000
fffff8a0`01738070 00000000`00000000 00000000`00000000
以刚刚的进程为例子,PID=2220:
2220 / 4 = 555
得到结果555,每张表存放256个句柄,555-256 = 299,299>256,那么此进程在第三张表中,299-256=0x2B:
fffff8a0`01bdc000+0x2b*F
最终此进程句柄为fffff8a0`01bdc000+0x2B,句柄实例结构体为:_HANDLE_TABLE_ENTRY
kd> dt _HANDLE_TABLE_ENTRY fffff8a0`01bdc000+0x2b*10
nt!_HANDLE_TABLE_ENTRY
+0x000 Object : 0xfffffa80`02a5d061 Void
+0x000 ObAttributes : 0x2a5d061
+0x000 InfoTable : 0xfffffa80`02a5d061 _HANDLE_TABLE_ENTRY_INFO
+0x000 Value : 0xfffffa80`02a5d061
+0x008 GrantedAccess : 0
+0x008 GrantedAccessIndex : 0
+0x00a CreatorBackTraceIndex : 0
+0x008 NextFreeTableEntry : 0
然后使用_EPROCESS结构体就可以查看到进程信息了得到的对象最后一位要-1,因为最后一位为权限位:
kd> dt _EPROCESS 0xfffffa80`02a5d060
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x160 ProcessLock : _EX_PUSH_LOCK
+0x168 CreateTime : _LARGE_INTEGER 0x0001d6d2`8cc51d24
+0x170 ExitTime : _LARGE_INTEGER 0x0
+0x178 RundownProtect : _EX_RUNDOWN_REF
+0x180 UniqueProcessId : 0x48000000`00000008 Void
+0x188 ActiveProcessLinks : _LIST_ENTRY [ 0xb8fffffa`80020483 - 0xf0fffffa`8001977c ]
+0x198 ProcessQuotaUsage : [2] 0xb0000000`00000059
+0x1a8 ProcessQuotaPeak : [2] 0xc0000000`0000005e
+0x1b8 CommitCharge : 0x80000000`00000003
+0x1c0 QuotaBlock : 0x00fffffa`800367bd _EPROCESS_QUOTA_BLOCK
+0x1c8 CpuQuotaBlock : (null)
+0x1d0 PeakVirtualSize : 0x78260
+0x1d8 VirtualSize : 0xa0000000`00076800
+0x1e0 SessionProcessLinks : _LIST_ENTRY [ 0x10fffffa`80020483 - 0x00fffffa`8001977d ]
+0x1f0 DebugPort : 0x40000000`00000000 Void
+0x1f8 ExceptionPortData : 0x90fffffa`8003611c Void
+0x1f8 ExceptionPortValue : 0x90fffffa`8003611c
+0x1f8 ExceptionPortState : 0y100
+0x200 ObjectTable : 0x93fffff8`a0093bcb _HANDLE_TABLE
+0x208 Token : _EX_FAST_REF
+0x210 WorkingSetPage : 0x20e
+0x218 AddressCreationLock : _EX_PUSH_LOCK
+0x220 RotateInProgress : (null)
+0x228 ForkInProgress : (null)
+0x230 HardwareTrigger : 0
+0x238 PhysicalVadRoot : (null)
+0x240 CloneRoot : 0x8d000000`00000000 Void
+0x248 NumberOfPrivatePages : 2
+0x250 NumberOfLockedPages : 0x10000000`00000000
+0x258 Win32Process : 0x00fffff9`00c011c0 Void
+0x260 Job : 0xf0000000`00000000 _EJOB
+0x268 SectionObject : 0x00fffff8`a0084a1a Void
+0x270 SectionBaseAddress : 0x0f000000`00003100 Void
+0x278 Cookie : 0x559554
+0x27c UmsScheduledThreads : 0
+0x280 WorkingSetWatch : 0x58000000`00000000 _PAGEFAULT_HISTORY
+0x288 Win32WindowStation : 0x78000000`00000000 Void
+0x290 InheritedFromUniqueProcessId : 0x00000000`00000007 Void
+0x298 LdtInformation : (null)
+0x2a0 Spare : (null)
+0x2a8 ConsoleHostProcess : 0x40000000`00000000
+0x2b0 DeviceMap : 0x00fffff8`a0015b97 Void
+0x2b8 EtwDataSource : (null)
+0x2c0 FreeTebHint : 0x00000000`007efd50 Void
+0x2c8 FreeUmsTebHint : 0x00000000`01000000 Void
+0x2d0 PageDirectoryPte : _HARDWARE_PTE
+0x2d0 Filler : 0
+0x2d8 Session : 0x73fffff8`80042630 Void
+0x2e0 ImageFileName : [15] "etup_wm.exe"
+0x2ef PriorityClass : 0 ''
+0x2f0 JobLinks : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x300 LockedPagesList : 0x80000000`00000000 Void
+0x308 ThreadListHead : _LIST_ENTRY [ 0x10fffffa`8001fa2f - 0x00fffffa`8002d978 ]
+0x318 SecurityPort : (null)
+0x320 Wow64Process : 0x08000000`007efde0 Void
+0x328 ActiveThreads : 0xc8000000
+0x32c ImagePathHash : 0x10e4cb6
+0x330 DefaultHardErrorProcessing : 0
+0x334 LastThreadExitStatus : 0n0
+0x338 Peb : 0x00000000`007efdf0 _PEB
+0x340 PrefetchTrace : _EX_FAST_REF
+0x348 ReadOperationCount : _LARGE_INTEGER 0x0
+0x350 WriteOperationCount : _LARGE_INTEGER 0xb6000000`00000000
+0x358 OtherOperationCount : _LARGE_INTEGER 0x40000000`00000000
+0x360 ReadTransferCount : _LARGE_INTEGER 0x0
+0x368 WriteTransferCount : _LARGE_INTEGER 0xfc000000`00000000
+0x370 OtherTransferCount : _LARGE_INTEGER 0xc
+0x378 CommitChargeLimit : 0xdf000000`00000000
+0x380 CommitChargePeak : 3
+0x388 AweInfo : 0x90000000`00000000 Void
+0x390 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x398 Vm : _MMSUPPORT
+0x420 MmProcessLinks : _LIST_ENTRY [ 0x50fffffa`80020485 - 0x00fffffa`8001977f ]
+0x430 HighestUserAddress : 0x07000000`007fff00 Void
+0x438 ModifiedPageCount : 1
+0x43c Flags2 : 0x10000d0
+0x43c JobNotReallyActive : 0y0
+0x43c AccountingFolded : 0y0
+0x43c NewProcessReported : 0y0
+0x43c ExitProcessReported : 0y0
+0x43c ReportCommitChanges : 0y1
+0x43c LastReportMemory : 0y0
+0x43c ReportPhysicalPageChanges : 0y1
+0x43c HandleTableRundown : 0y1
+0x43c NeedsHandleRundown : 0y0
+0x43c RefTraceEnabled : 0y0
+0x43c NumaAware : 0y0
+0x43c ProtectedProcess : 0y0
+0x43c DefaultPagePriority : 0y000
+0x43c PrimaryTokenFrozen : 0y0
+0x43c ProcessVerifierTarget : 0y0
+0x43c StackRandomizationDisabled : 0y0
+0x43c AffinityPermanent : 0y0
+0x43c AffinityUpdateEnable : 0y0
+0x43c PropagateNode : 0y0
+0x43c ExplicitAffinity : 0y0
+0x440 Flags : 0x3144d08
+0x440 CreateReported : 0y0
+0x440 NoDebugInherit : 0y0
+0x440 ProcessExiting : 0y0
+0x440 ProcessDelete : 0y1
+0x440 Wow64SplitPages : 0y0
+0x440 VmDeleted : 0y0
+0x440 OutswapEnabled : 0y0
+0x440 Outswapped : 0y0
+0x440 ForkFailed : 0y1
+0x440 Wow64VaSpace4Gb : 0y0
+0x440 AddressSpaceInitialized : 0y11
+0x440 SetTimerResolution : 0y0
+0x440 BreakOnTermination : 0y0
+0x440 DeprioritizeViews : 0y1
+0x440 WriteWatch : 0y0
+0x440 ProcessInSession : 0y0
+0x440 OverrideAddressSpace : 0y0
+0x440 HasAddressSpace : 0y1
+0x440 LaunchPrefetched : 0y0
+0x440 InjectInpageErrors : 0y1
+0x440 VmTopDown : 0y0
+0x440 ImageNotifyDone : 0y0
+0x440 PdeUpdateNeeded : 0y0
+0x440 VdmAllowed : 0y1
+0x440 CrossSessionCreate : 0y1
+0x440 ProcessInserted : 0y0
+0x440 DefaultIoPriority : 0y000
+0x440 ProcessSelfDelete : 0y0
+0x440 SetTimerResolutionLink : 0y0
+0x444 ExitStatus : 0n-1426063359
+0x448 VadRoot : _MM_AVL_TABLE
+0x488 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x4a8 TimerResolutionLink : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x4b8 RequestedTimerResolution : 0xb000000
+0x4bc ActiveThreadsHighWatermark : 0
+0x4c0 SmallestTimerResolution : 0
+0x4c8 TimerResolutionStackRecord : 0x53000000`00000000 _PO_DIAG_STACK_RECORD
如何知道对方是进程还是线程?
在内核中每个对象都有一个结构体_OBJECT_HEADER,在x64下,目标结构体为:
kd> dt _OBJECT_HEADER -v
nt!_OBJECT_HEADER
struct _OBJECT_HEADER, 12 elements, 0x38 bytes
+0x000 PointerCount : Int8B
+0x008 HandleCount : Int8B
+0x008 NextToFree : Ptr64 to Void
+0x010 Lock : struct _EX_PUSH_LOCK, 7 elements, 0x8 bytes
+0x018 TypeIndex : UChar
+0x019 TraceFlags : UChar
+0x01a InfoMask : UChar
+0x01b Flags : UChar
+0x020 ObjectCreateInfo : Ptr64 to struct _OBJECT_CREATE_INFORMATION, 9 elements, 0x40 bytes
+0x020 QuotaBlockCharged : Ptr64 to Void
+0x028 SecurityDescriptor : Ptr64 to Void
+0x030 Body : struct _QUAD, 2 elements, 0x8 bytes
目标大小为38,第30个字节为他的身体,所以我们需要-30:
kd> dt _OBJECT_HEADER 0xfffffa80`02a5d060-30
nt!_OBJECT_HEADER
+0x000 PointerCount : 0n143
+0x008 HandleCount : 0n4
+0x008 NextToFree : 0x00000000`00000004 Void
+0x010 Lock : _EX_PUSH_LOCK
+0x018 TypeIndex : 0x7 ''
+0x019 TraceFlags : 0 ''
+0x01a InfoMask : 0x8 ''
+0x01b Flags : 0 ''
+0x020 ObjectCreateInfo : 0xfffffa80`0367bd80 _OBJECT_CREATE_INFORMATION
+0x020 QuotaBlockCharged : 0xfffffa80`0367bd80 Void
+0x028 SecurityDescriptor : 0xfffff8a0`0177df5d Void
+0x030 Body : _QUAD
其中的TypeIndex就在说明内核对象的类型,说明放在了ObTypeIndexTable中:
kd> dd ObTypeIndexTable
fffff800`04040340 00000000 00000000 bad0b0b0 00000000
fffff800`04040350 0184cca0 fffffa80 0184cb50 fffffa80
fffff800`04040360 0184ca00 fffffa80 018eef10 fffffa80
fffff800`04040370 018eecf0 fffffa80 018eeba0 fffffa80
fffff800`04040380 018eea50 fffffa80 018ee900 fffffa80
fffff800`04040390 018ee7b0 fffffa80 018eff30 fffffa80
fffff800`040403a0 019b4570 fffffa80 01998a30 fffffa80
fffff800`040403b0 019988e0 fffffa80 0196ea50 fffffa80
将ObTypeIndexTable首地址:fffff800`04040340
,取出来然后+7*8(x86为7*4):
kd> dq fffff800`04040340+7*8
fffff800`04040378 fffffa80`018eeba0 fffffa80`018eea50
fffff800`04040388 fffffa80`018ee900 fffffa80`018ee7b0
fffff800`04040398 fffffa80`018eff30 fffffa80`019b4570
fffff800`040403a8 fffffa80`01998a30 fffffa80`019988e0
fffff800`040403b8 fffffa80`0196ea50 fffffa80`0196e900
fffff800`040403c8 fffffa80`01983a50 fffffa80`01983900
fffff800`040403d8 fffffa80`01944a50 fffffa80`01944900
fffff800`040403e8 fffffa80`01936a50 fffffa80`01936900
然后使用_OBJECT_TYPE查看是什么类型:
kd> dt _OBJECT_TYPE fffffa80`018eeba0
nt!_OBJECT_TYPE
+0x000 TypeList : _LIST_ENTRY [ 0xfffffa80`018eeba0 - 0xfffffa80`018eeba0 ]
+0x010 Name : _UNICODE_STRING "Process"
+0x020 DefaultObject : (null)
+0x028 Index : 0x7 ''
+0x02c TotalNumberOfObjects : 0x25
+0x030 TotalNumberOfHandles : 0xd4
+0x034 HighWaterNumberOfObjects : 0x2f
+0x038 HighWaterNumberOfHandles : 0x102
+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x0b0 TypeLock : _EX_PUSH_LOCK
+0x0b8 Key : 0x636f7250
+0x0c0 CallbackList : _LIST_ENTRY [ 0xfffffa80`018eec60 - 0xfffffa80`018eec60 ]
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT driver)
{
if (driver != NULL)
{
DbgPrint("Driver Uninstall");
}
}
DWORD32 GetPspCidTable()
{
UNICODE_STRING uStrName;
DWORD32* pPsLookupProcessByProcessId;
int i = 0;
DWORD32 PspCidTable = 0;
RtlInitUnicodeString(&uStrName, L"PsLookupProcessByProcessId");
pPsLookupProcessByProcessId = (DWORD32*)MmGetSystemRoutineAddress(&uStrName);
if (!pPsLookupProcessByProcessId)
{
return 0;
}
/*
8406f590 ff7508 push dword ptr [ebp+8]
8406f593 8b3d345ff583 mov edi,dword ptr [nt!PspCidTable (83f55f34)]
*/
while (i < 258)
{
if (*((UCHAR*)pPsLookupProcessByProcessId + i) == 0xFF && *((UCHAR*)pPsLookupProcessByProcessId + i + 1) == 0x75 && *((UCHAR*)pPsLookupProcessByProcessId + i + 2) == 0x08)
{
DbgPrint("找到了!找到了!");
PspCidTable = *(DWORD32*)((UCHAR*)pPsLookupProcessByProcessId + i + 5);
DbgPrint("%x", PspCidTable);
break;
}
i++;
}
return PspCidTable;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driverT, PUNICODE_STRING string_path)
{
DbgPrint("Hello Word My Driver");
if (string_path != NULL)
{
DbgPrint("[%s]Driver RegisterPath : %wZ\n", __FUNCTION__, string_path);
}
if (driverT != NULL)
{
DbgPrint("[%s]Driver Object Address : %p\n", __FUNCTION__, driverT);
driverT->DriverUnload = DriverUnload;
}
DWORD32* PspCidTable = (DWORD32*)GetPspCidTable();
DbgPrint("PspCidTable:%x\n", *PspCidTable);
DWORD32 tablecode = *(DWORD32*)(*PspCidTable);
DbgPrint("TableCode:%x\n", tablecode);
UINT8 low = tablecode & 3;
DbgPrint("Level:%x\n", low);
switch (low)
{
case 0x0:
break;
case 0x1:
//DbgPrint("%x", *((DWORD32 *)((tablecode - low)+(sizeof(DWORD32)*1))));
//DbgPrint("%x", (*(DWORD32*)(tablecode - low)));
for (DWORD32 i = 0; i < 1024; i++)
{
if (*((DWORD32*)((tablecode - low) + (sizeof(DWORD32) * i))) == 0)
{
break;
}
DWORD32 Handle_table = *((DWORD32*)((tablecode - low) + (sizeof(DWORD32) * i)));
DbgPrint("句柄表:%x", Handle_table);
for (DWORD32 x = 0x0; x < 0x200; x++) {
DWORD32 ProcessObj = *(DWORD32*)(Handle_table + (x * 0x8));
if (ProcessObj == 0) {
continue;
}
//DbgPrint("%d", *(USHORT*)((DWORD32*)((ProcessObj - 0x1) - 0x18 + 0xC)));
USHORT IndexType = (*(USHORT*)((DWORD32*)((ProcessObj - 0x1) - 0x18 + 0xC)));
//DbgPrint("%d",IndexType);
if (IndexType == 7) {
//DbgPrint("%s", (PCHAR)((DWORD32*)((ProcessObj - 0x1) + 0x16c)));
DbgPrint("ProcessOBJ:%x,对象类型:%x,进程ID:%d,进程名称:%s\n", ProcessObj - 0x1, *(USHORT*)((DWORD32*)((ProcessObj - 0x1) - 0x18 + 0xC)), *(DWORD32*)((ProcessObj - 0x1)+ 0x0b4), (PCHAR)((ProcessObj - 0x1) + 0x16c));
}
}
}
break;
case 0x2:
break;
}
return STATUS_SUCCESS;
}