최근 핸들 테이블 검사 코드를 다시 보다가 잘못된 부분이 있어 수정도 할겸 확인한 내용이다.
직접 확인한 OS 목록
Windows XP x86/x64
Windows 2008(VISTA) x86
Windows 7 x86/x64
Windows 8 x86
Windows 8.1 x86/x64
Windows 10 Technical Preview x86/x64
핸들 테이블의 구조는 핸들 개수에 따라 Top/Middle/Sub Level 3가지로 나뉜다.
핸들 테이블은 하나의 Page 크기(PAGE_SIZE)를 가지며,
Page의 크기는 x86, x64 Processor 모두 0x1000의 크기를 가진다.
(http://msdn.microsoft.com/en-us/library/windows/hardware/ff554138(v=vs.85).aspx)
각 Level은 아래와 같은 개수를 가진다.
Sub 핸들 테이블의 핸들 개수
x86 : (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)) - 1 = 511
x64 : (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)) - 1 = 255
Middle 테이블의 Sub 테이블 포인터 개수
x86 : PAGE_SIZE / sizeof(ULONG_PTR) = 1024
x64 : PAGE_SIZE / sizeof(ULONG_PTR) = 512
Top 테이블의 Middle 테이블 포인터 개수
x86 : 32
x64 : 128
x86과 x64의 테이블 크기나 모양은 차이가 있지만 결국 총 개수는 같다.
32 * 1024 * 512 = 16,777,216
128 * 512 * 256 = 16,777,216
다만 실제 핸들 개수는 차이가 좀 있을 것 같다.
32 * 1024 * 511 = 16,744,448
128 * 512 * 255 = 16,711,680
아래는 프로세스 목록에 있는 프로세스를 오픈한 후,
핸들을 닫지 않는 테스트 프로그램을 켜둔 상태의 핸들 테이블 모양 및 어떤 핸들인지 보는 순서이다.
0: kd> !process 0 1 TestProgram.exe PROCESS 85c23030 SessionId: 1 Cid: 09ac Peb: 7ffd3000 ParentCid: 04e0 DirBase: 3f4aa480 ObjectTable: 94a1a8e0 HandleCount: 4358357. Image: TestProgram.exe VadRoot 85cb5910 Vads 40 Clone 0 Private 137. Modified 199301928. Locked 0. DeviceMap 91621568 Token 94a30c88 ElapsedTime 00:28:13.425 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 0 QuotaPoolUsage[NonPagedPool] 0 Working Set Sizes (now,min,max) (551, 50, 345) (2204KB, 200KB, 1380KB) PeakWorkingSetSize 552 VirtualSize 27 Mb PeakVirtualSize 28 Mb PageFaultCount 199302508 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 207 0: kd> dt nt!_EPROCESS ObjectTable 85c23030 +0x0f4 ObjectTable : 0x94a1a8e0 _HANDLE_TABLE
0: kd> dt 0x94a1a8e0 _HANDLE_TABLE ntdll!_HANDLE_TABLE +0x000 TableCode : 0x9131ec02 +0x004 QuotaProcess : 0x85c23030 _EPROCESS +0x008 UniqueProcessId : 0x000009ac Void +0x00c HandleLock : _EX_PUSH_LOCK +0x010 HandleTableList : _LIST_ENTRY [ 0x912a2758 - 0x92142a08 ] +0x018 HandleContentionEvent : _EX_PUSH_LOCK +0x01c DebugInfo : (null) +0x020 ExtraInfoPages : 0n0 +0x024 Flags : 0 +0x024 StrictFIFO : 0y0 +0x028 FirstFreeHandle : 0x10a889c +0x02c LastFreeHandleEntry : 0xa018bff8 _HANDLE_TABLE_ENTRY +0x030 HandleCount : 0x4280d5 +0x034 NextHandleNeedingPool : 0x10a9000 +0x038 HandleCountHighWatermark : 0x4280d5 - TableCode의 하위 3bit는 Level Index이며 2이므로 Top Level까지 구성된 상태. - 하위 3bit를 제거하면 핸들 테이블의 시작 위치. <Top> 0: kd> dd 0x9131ec00 L30 9131ec00 94a9d000 95462000 95b63000 9e584000 9131ec10 9ed7e000 9f17e000 9f596000 9fbc9000 9131ec20 a0034000 00000000 00000000 00000000 9131ec30 00000000 00000000 00000000 00000000 9131ec40 00000000 00000000 00000000 00000000 9131ec50 00000000 00000000 00000000 00000000 9131ec60 00000000 00000000 00000000 00000000 9131ec70 00000000 00000000 00000000 00000000 9131ec80 06700211 6666744e 00f00702 01000a48 9131ec90 0000500e 00010000 00000000 00000001 9131eca0 00000000 00000000 9131ef3c 9131ef3c 9131ecb0 9131edc0 9131edc0 00000000 85aced50 - 테스트 프로그램을 오래 켜놓지 않아 아직 Top 테이블에 Middle 테이블의 주소가 꽉 차지 않은 상태이다. <Middle> 0: kd> dd 94a9d000 94a9d000 94a94000 94a9e000 94a9f000 94aa2000 94a9d010 94aa3000 94aa4000 94aa5000 94aa6000 94a9d020 94aa7000 94aa8000 94aa9000 94aae000 94a9d030 94aaf000 94ab0000 94ab1000 94ab2000 94a9d040 94ab3000 94ab4000 94ab5000 94ab6000 94a9d050 94ab7000 94ab8000 94ab9000 94aba000 94a9d060 94abb000 94abc000 94abd000 94abe000 94a9d070 94af5000 94af8000 94af9000 94afa000 ... - 하나하나 모두 Sub 테이블의 시작 포인터. <Sub> 0: kd> dd 94a94000 94a94000 00000000 fffffffe 8b8a2e41 00000003 94a94010 85c23dd9 00100020 85c68af1 001f0003 94a94020 92154ea9 00020019 85c3eee9 001f0001 94a94030 85c689c1 001f0001 94a536c9 00000001 94a94040 85cb5b91 00000804 85cb04c9 021f0003 94a94050 8585ea01 000f037f 858774a9 000f01ff 94a94060 8585ea01 000f037f 92154f09 000f003f 94a94070 85cb5841 001f0001 85cb5801 001f0003 ... - 제일 앞에는 핸들테이블값이 아닌 시작위치라고 알려주는 어떤 값?이 있다. 그래서 핸들 개수는 (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)) - 1 이 된다. 0: kd> dt nt!_HANDLE_TABLE_ENTRY 94a94008 +0x000 Object : 0x8b8a2e41 Void +0x000 ObAttributes : 0x8b8a2e41 +0x000 InfoTable : 0x8b8a2e41 _HANDLE_TABLE_ENTRY_INFO +0x000 Value : 0x8b8a2e41 +0x004 GrantedAccess : 3 +0x004 GrantedAccessIndex : 3 +0x006 CreatorBackTraceIndex : 0 +0x004 NextFreeTableEntry : 3 - 하위 1bit를 제거하면 Object Header의 주소가 나온다. - PspCidTable의 핸들 테이블의 경우 이 값이 Object 주소 그자체. - Windows 8부터는 Object 주소가 바로 나오지 않으며 ObjectPointers 필드에 약간의 계산을 하여 Object 주소를 구해야 한다. (http://driverentry.tistory.com/14) 0: kd> dt nt!_OBJECT_HEADER 8b8a2e40 +0x000 PointerCount : 0n72 +0x004 HandleCount : 0n34 +0x004 NextToFree : 0x00000022 Void +0x008 Lock : _EX_PUSH_LOCK +0x00c TypeIndex : 0x3 '' +0x00d TraceFlags : 0 '' +0x00e InfoMask : 0xa '' +0x00f Flags : 0x10 '' +0x010 ObjectCreateInfo : 0x82d78c40 _OBJECT_CREATE_INFORMATION +0x010 QuotaBlockCharged : 0x82d78c40 Void +0x014 SecurityDescriptor : 0x894535b1 Void +0x018 Body : _QUAD 0: kd> dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (3 * @$ptrsize)) +0x000 TypeList : _LIST_ENTRY [ 0x84533c28 - 0x84533c28 ] +0x008 Name : _UNICODE_STRING "Directory" +0x010 DefaultObject : 0x82d85ba0 Void +0x014 Index : 0x3 '' +0x018 TotalNumberOfObjects : 0x25 +0x01c TotalNumberOfHandles : 0x5a +0x020 HighWaterNumberOfObjects : 0x29 +0x024 HighWaterNumberOfHandles : 0x65 +0x028 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x078 TypeLock : _EX_PUSH_LOCK +0x07c Key : 0x65726944 +0x080 CallbackList : _LIST_ENTRY [ 0x84533ca8 - 0x84533ca8 ] |
다음은 x64에서의 핸들 테이블 모양이다.
kd> !process 0 1 TestProgram.exe PROCESS fffffa8003ab3b30 SessionId: 1 Cid: 029c Peb: 7efdf000 ParentCid: 0660 DirBase: 473e6000 ObjectTable: fffff8a0044fa010 HandleCount: 16711680. Image: TestProgram.exe VadRoot fffffa8003aca970 Vads 54 Clone 0 Private 181. Modified 953239932. Locked 0. DeviceMap fffff8a00287f7b0 Token fffff8a0037e6060 ElapsedTime 00:12:51.873 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 0 QuotaPoolUsage[NonPagedPool] 0 Working Set Sizes (now,min,max) (780, 50, 345) (3120KB, 200KB, 1380KB) PeakWorkingSetSize 781 VirtualSize 42 Mb PeakVirtualSize 42 Mb PageFaultCount 953240761 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 277 Job fffffa8003a912e0 kd> dt nt!_EPROCESS ObjectTable fffffa8003ab3b30 +0x200 ObjectTable : 0xfffff8a0`044fa010 _HANDLE_TABLE kd> dt 0xfffff8a0`044fa010 _HANDLE_TABLE ntdll!_HANDLE_TABLE +0x000 TableCode : 0xfffff8a0`029d6512 +0x008 QuotaProcess : 0xfffffa80`03ab3b30 _EPROCESS +0x010 UniqueProcessId : 0x00000000`0000029c Void +0x018 HandleLock : _EX_PUSH_LOCK +0x020 HandleTableList : _LIST_ENTRY [ 0xfffff8a0`03db1590 - 0xfffff8a0`02b89cd0 ] +0x030 HandleContentionEvent : _EX_PUSH_LOCK +0x038 DebugInfo : (null) +0x040 ExtraInfoPages : 0n0 +0x044 Flags : 0 +0x044 StrictFIFO : 0y0 +0x048 FirstFreeHandle : 0 +0x050 LastFreeHandleEntry : (null) +0x058 HandleCount : 0xff0000 +0x05c NextHandleNeedingPool : 0x4000000 +0x060 HandleCountHighWatermark : 0xff0000 <Top> kd> dq 0xfffff8a0`029d6510 L100 fffff8a0`029d6510 fffff8a0`0457c000 fffff8a0`04761000 fffff8a0`029d6520 fffff8a0`048bd000 fffff8a0`04cfd000 fffff8a0`029d6530 fffff8a0`04ff4000 fffff8a0`04ec6000 fffff8a0`029d6540 fffff8a0`049a6000 fffff8a0`08817000 fffff8a0`029d6550 fffff8a0`05248000 fffff8a0`0897a000 fffff8a0`029d6560 fffff8a0`08dfc000 fffff8a0`08beb000 fffff8a0`029d6570 fffff8a0`091fd000 fffff8a0`093fe000 fffff8a0`029d6580 fffff8a0`095ff000 fffff8a0`096da000 fffff8a0`029d6590 fffff8a0`099f9000 fffff8a0`09bfa000 fffff8a0`029d65a0 fffff8a0`08b6a000 fffff8a0`09d6c000 fffff8a0`029d65b0 fffff8a0`0a1fd000 fffff8a0`09e38000 fffff8a0`029d65c0 fffff8a0`0a04d000 fffff8a0`0a801000 fffff8a0`029d65d0 fffff8a0`0aa02000 fffff8a0`0a67e000 fffff8a0`029d65e0 fffff8a0`0ad47000 fffff8a0`0af48000 fffff8a0`029d65f0 fffff8a0`0b21a000 fffff8a0`0ab60000 fffff8a0`029d6600 fffff8a0`0b069000 fffff8a0`0b819000 fffff8a0`029d6610 fffff8a0`0ba19000 fffff8a0`0b641000 fffff8a0`029d6620 fffff8a0`0be2a000 fffff8a0`0bb03000 fffff8a0`029d6630 fffff8a0`0c22b000 fffff8a0`0bbc0000 fffff8a0`029d6640 fffff8a0`0c3b8000 fffff8a0`0c849000 fffff8a0`029d6650 fffff8a0`0caa9000 fffff8a0`0ce12000 fffff8a0`029d6660 fffff8a0`0d004000 fffff8a0`0d25a000 fffff8a0`029d6670 fffff8a0`0d4c2000 fffff8a0`0c61b000 fffff8a0`029d6680 fffff8a0`0d878000 fffff8a0`0da7c000 fffff8a0`029d6690 fffff8a0`0dc80000 fffff8a0`0de83000 fffff8a0`029d66a0 fffff8a0`0c4c0000 fffff8a0`0d801000 fffff8a0`029d66b0 fffff8a0`0e4e2000 fffff8a0`0e6e2000 fffff8a0`029d66c0 fffff8a0`0e38b000 fffff8a0`0e9ef000 fffff8a0`029d66d0 fffff8a0`0ebf5000 fffff8a0`0eeee000 fffff8a0`029d66e0 fffff8a0`0f0ef000 fffff8a0`0ed23000 fffff8a0`029d66f0 fffff8a0`0f4f4000 fffff8a0`0f704000 fffff8a0`029d6700 fffff8a0`0f31f000 fffff8a0`0fb07000 fffff8a0`029d6710 fffff8a0`0fd1c000 fffff8a0`0f941000 fffff8a0`029d6720 fffff8a0`0fe8f000 fffff8a0`10371000 fffff8a0`029d6730 fffff8a0`10002000 fffff8a0`10598000 fffff8a0`029d6740 fffff8a0`108e2000 fffff8a0`10b5e000 fffff8a0`029d6750 fffff8a0`10daa000 fffff8a0`10fd4000 fffff8a0`029d6760 fffff8a0`1124a000 fffff8a0`10ad8000 fffff8a0`029d6770 fffff8a0`11689000 fffff8a0`11899000 fffff8a0`029d6780 fffff8a0`0e0c7000 fffff8a0`11c80000 fffff8a0`029d6790 fffff8a0`11e8b000 fffff8a0`11abb000 fffff8a0`029d67a0 fffff8a0`12004000 fffff8a0`12496000 fffff8a0`029d67b0 fffff8a0`120af000 fffff8a0`1265d000 fffff8a0`029d67c0 fffff8a0`12aee000 fffff8a0`12d0d000 fffff8a0`029d67d0 fffff8a0`12914000 fffff8a0`1307a000 fffff8a0`029d67e0 fffff8a0`1327c000 fffff8a0`134da000 fffff8a0`029d67f0 fffff8a0`13756000 fffff8a0`13957000 fffff8a0`029d6800 fffff8a0`13b58000 fffff8a0`13d59000 fffff8a0`029d6810 fffff8a0`13f84000 fffff8a0`12f05000 fffff8a0`029d6820 fffff8a0`136dd000 fffff8a0`14587000 fffff8a0`029d6830 fffff8a0`14776000 fffff8a0`143cb000 fffff8a0`029d6840 fffff8a0`14b99000 fffff8a0`14da3000 fffff8a0`029d6850 fffff8a0`14adc000 fffff8a0`1518c000 fffff8a0`029d6860 fffff8a0`15493000 fffff8a0`156e7000 fffff8a0`029d6870 fffff8a0`158ea000 fffff8a0`15129000 fffff8a0`029d6880 fffff8a0`15d32000 fffff8a0`15f33000 fffff8a0`029d6890 fffff8a0`15bee000 fffff8a0`15a45000 fffff8a0`029d68a0 fffff8a0`1648a000 fffff8a0`1676c000 fffff8a0`029d68b0 fffff8a0`1696e000 fffff8a0`16595000 fffff8a0`029d68c0 fffff8a0`16d7a000 fffff8a0`16f87000 fffff8a0`029d68d0 fffff8a0`16b98000 fffff8a0`1710b000 fffff8a0`029d68e0 fffff8a0`1760e000 fffff8a0`171af000 fffff8a0`029d68f0 fffff8a0`177c8000 fffff8a0`17879000 fffff8a0`029d6900 fffff8a0`17d09000 fffff8a0`1806d000 fffff8a0`029d6910 3066744e`03030141 ffffffff`ffffffff fffff8a0`029d6920 00000000`00000000 fffff8a0`02a9db28 fffff8a0`029d6930 0000002a`1832e052 0000005c`00730074 fffff8a0`029d6940 6366744e`03090103 00004000`10000000 fffff8a0`029d6950 00008003`00780709 00000000`00000001 fffff8a0`029d6960 00000000`00780046 fffff8a0`02ab4300 - 이 놈은 오래 켜놔서 Top Level까지 꽉 찬 상태. <Middle> kd> dq fffff8a0`0457c000 fffff8a0`0457c000 fffff8a0`0457b000 fffff8a0`04584000 fffff8a0`0457c010 fffff8a0`0456f000 fffff8a0`0457f000 fffff8a0`0457c020 fffff8a0`04560000 fffff8a0`0457e000 fffff8a0`0457c030 fffff8a0`04565000 fffff8a0`04569000 fffff8a0`0457c040 fffff8a0`0454f000 fffff8a0`04585000 fffff8a0`0457c050 fffff8a0`043e0000 fffff8a0`04517000 fffff8a0`0457c060 fffff8a0`04532000 fffff8a0`04538000 fffff8a0`0457c070 fffff8a0`04539000 fffff8a0`0453e000 ... <Sub> kd> dq fffff8a0`0457b000 fffff8a0`0457b000 00000000`00000000 00e90000`fffffffe fffff8a0`0457b010 fffff8a0`03f14f71 00000000`00000009 fffff8a0`0457b020 fffff8a0`085de911 00000000`00000003 fffff8a0`0457b030 fffff8a0`02234b01 00000000`00000003 fffff8a0`0457b040 fffffa80`03ae4cd1 00000000`00100020 fffff8a0`0457b050 fffff8a0`04201d61 00000000`00000009 fffff8a0`0457b060 fffff8a0`02234b01 00000000`00000003 fffff8a0`0457b070 fffffa80`051dfdc1 00000000`00100020 ... kd> dt nt!_HANDLE_TABLE_ENTRY fffff8a0`0457b010 +0x000 Object : 0xfffff8a0`03f14f71 Void +0x000 ObAttributes : 0x3f14f71 +0x000 InfoTable : 0xfffff8a0`03f14f71 _HANDLE_TABLE_ENTRY_INFO +0x000 Value : 0xfffff8a0`03f14f71 +0x008 GrantedAccess : 9 +0x008 GrantedAccessIndex : 9 +0x00a CreatorBackTraceIndex : 0 +0x008 NextFreeTableEntry : 9
kd> dt nt!_OBJECT_HEADER fffff8a0`03f14f70 +0x000 PointerCount : 0n1 +0x008 HandleCount : 0n1 +0x008 NextToFree : 0x00000000`00000001 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : 0x23 '#' +0x019 TraceFlags : 0 '' +0x01a InfoMask : 0x8 '' +0x01b Flags : 0 '' +0x020 ObjectCreateInfo : 0xfffffa80`05763400 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : 0xfffffa80`05763400 Void +0x028 SecurityDescriptor : (null) +0x030 Body : _QUAD
kd> dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (0x23 * @$ptrsize)) +0x000 TypeList : _LIST_ENTRY [ 0xfffffa80`03967260 - 0xfffffa80`03967260 ] +0x010 Name : _UNICODE_STRING "Key" +0x020 DefaultObject : 0xfffff800`0342a3e0 Void +0x028 Index : 0x23 '#' +0x02c TotalNumberOfObjects : 0x313 +0x030 TotalNumberOfHandles : 0x30e +0x034 HighWaterNumberOfObjects : 0x3aa +0x038 HighWaterNumberOfHandles : 0x3a5 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b0 TypeLock : _EX_PUSH_LOCK +0x0b8 Key : 0x2079654b +0x0c0 CallbackList : _LIST_ENTRY [ 0xfffffa80`03967320 - 0xfffffa80`03967320 ] |
이렇게 한번 찾아가면서 정리하고 나니 확실히 정리가 되는듯.
'Kernel mode' 카테고리의 다른 글
Windows 10 RS2 - 1394 커널 디버깅 지원 제거 (0) | 2016.09.22 |
---|---|
[펌] Windbg 메모리 추척 (0) | 2015.11.20 |
PspLoadImageNotifyRoutine Maximum (0) | 2014.10.08 |
TESTSIGNING, DISABLE_INTEGRITY_CHECKS 환경 검사 (CI!g_CiOptions) (0) | 2014.09.17 |
PspCreateProcessNotifyRoutine Maximum (0) | 2014.07.01 |