Objects and Handles
- Object
- A single, run-time instance of a statically defined object type (File, Process..)
- Object attribute
- A field of data in an object that partially defines the object's state
- Object methods
- The means for manipulating objects, usually read or change the object attributes
- Open method for a process would accept a process identifier as input and return a pointer to the object as output
- Handle
- A reference to an instance of an object
- All user-mode processes must own a handle to an object before their threads can use the object
- A process is an instance of the process object type; a file is an instance of the file object type, and so on
- Objects provide a convenient means for accomplishing the following four important operating system tasks:
- Providing human-readable names for system resources
- Sharing resources and data among processes
- Protecting resources from unauthorized access
- Reference tracking, which allows the system to know when an object is no longer in use so that it can be automatically de-allocated
- When a process creates or opens an object by name, it receives a handle that represents its access to the object
- Referring to an object by its handle is faster than using its name because the object manager can skip the name lookup and find the object directly
- Processes can also acquire handles to objects by
- Inheriting handles at process creation time
- Receiving a duplicated handle from another process
Handle API examples
BOOL CreateProcessA( [in, optional] LPCSTR lpApplicationName, [in, out, optional] LPSTR lpCommandLine, [in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes, [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes, [in] BOOL bInheritHandles, [in] DWORD dwCreationFlags, [in, optional] LPVOID lpEnvironment, [in, optional] LPCSTR lpCurrentDirectory, [in] LPSTARTUPINFOA lpStartupInfo, [out] LPPROCESS_INFORMATION lpProcessInformation ); [out] lpProcessInformation A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process. Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed. ### <--- #include <windows.h> #include <stdio.h> #include <tchar.h> void _tmain( int argc, TCHAR *argv[] ) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if( argc != 2 ) { printf("Usage: %s [cmdline]\n", argv[0]); return; } // Start the child process. if( !CreateProcess( NULL, // No module name (use command line) argv[1], // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi ) // Pointer to PROCESS_INFORMATION structure ) { printf( "CreateProcess failed (%d).\n", GetLastError() ); return; } // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); } HANDLE CreateFileA( [in] LPCSTR lpFileName, [in] DWORD dwDesiredAccess, [in] DWORD dwShareMode, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, [in] DWORD dwCreationDisposition, [in] DWORD dwFlagsAndAttributes, [in, optional] HANDLE hTemplateFile ); BOOL DuplicateHandle( [in] HANDLE hSourceProcessHandle, [in] HANDLE hSourceHandle, [in] HANDLE hTargetProcessHandle, [out] LPHANDLE lpTargetHandle, [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwOptions ); #include <windows.h> DWORD CALLBACK ThreadProc(PVOID pvParam); int main() { HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); HANDLE hMutexDup, hThread; DWORD dwThreadId; DuplicateHandle(GetCurrentProcess(), hMutex, GetCurrentProcess(), &hMutexDup, 0, FALSE, DUPLICATE_SAME_ACCESS); hThread = CreateThread(NULL, 0, ThreadProc, (LPVOID) hMutexDup, 0, &dwThreadId); // Perform work here, closing the handle when finished with the // mutex. If the reference count is zero, the object is destroyed. CloseHandle(hMutex); // Wait for the worker thread to terminate and clean up. WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); return 0; } DWORD CALLBACK ThreadProc(PVOID pvParam) { HANDLE hMutex = (HANDLE)pvParam; // Perform work here, closing the handle when finished with the // mutex. If the reference count is zero, the object is destroyed. CloseHandle(hMutex); return 0; } |
Object는 Resource의 추상화 개체
예를 들어, Harddisk Device는 Device의 특성과 Device에 대해서 수행될 수 있는 Operation을 Object에 기술
Object Manager는 이러한 Object를 관리하며, "Ob"는 Object Manager의 Prefix
Object는 named와 un-named가 있으며,
- named object는 Object Manager에 의해서 global namespace에 위치
- un-named object의 경우에는 user-mode에서 직접 접근이 불가하며, kernel-mode에서 실제 주소를 알고 있는 component가 접근 가능
- 하지만 user-mode에서 명시적으로 Win32 API를 이용하여(CreateEvent, CreateMutex...) un-named object를 만든 경우에는 user-mode에서 접근 가능(Handle을 획득했기 때문에)
Object Namespace는 filesystem 계층 구조와 유사하며, System Startup 시점에 In-memory에 구성
Object Namespace 구성 항목
- Root(\)
- Directories
- Symbolic links
- Objects
Object Namespace는 Sysinternals의 WinObj 도구를 이용하여 다음 화면과 같이 확인 가능
https://learn.microsoft.com/en-us/sysinternals/downloads/winobj
Object Namespace는 System-wide 측면의 Container와 Session 측면의 Container로 분류
- System-wide Container
- \Driver
- \Device
- \Filesystem
- \ObjectType
- Session Container
- \Windows
- \DosDevices
- \BaseNamedObjects
Windbg를 통해 Object Namespace 확인 방법
object namespace from root
3: kd> !object \ Object: ffffd60166c08060 Type: (ffffe60d7ae92a60) Directory ObjectHeader: ffffd60166c08030 (new version) HandleCount: 0 PointerCount: 57 Directory Object: 00000000 Name: \ Hash Address Type Name ---- ------- ---- ---- 01 ffffe60d7bc97d50 Mutant PendingRenameMutex ffffd60166c07ba0 Directory ObjectTypes 02 ffffe60d7e6d4260 FilterConnectionPort storqosfltport 03 ffffe60d7b6ddd10 FilterConnectionPort MicrosoftMalwareProtectionRemoteIoPortWD 05 ffffd60166c2e490 SymbolicLink SystemRoot 06 ffffd60168304a20 Directory Sessions ffffe60d7b6dd8f0 FilterConnectionPort MicrosoftMalwareProtectionVeryLowIoPortWD 08 ffffd60166c09d80 Directory ArcName 09 ffffe60d7e6d2a50 FilterConnectionPort WcifsPort ffffd60166cac5e0 Directory NLS 10 ffffe60d7ea5de60 Event LanmanServerAnnounceEvent ffffe60d7e75ddb0 ALPC Port ThemeApiPort ffffe60d7d1c1d00 Device UdfsCdRom ffffd60168304480 Directory Windows ffffd60166c075b0 Directory GLOBAL?? 11 ffffd60168305920 Directory RPC Control ffffe60d7b73f530 ALPC Port PdcPort 13 ffffe60d7dd5fbc0 Event DSYSDBG.Debug.Trace.Memory.2b4 ffffe60d7bcae7e0 Event EFSInitEvent 14 ffffd60168303340 SymbolicLink Dfs ffffe60d7b7eed80 Device clfs 15 ffffe60d7d585670 Event CsrSbSyncEvent ffffe60d7b972d70 ALPC Port SeRmCommandPort 16 ffffd60166c09540 SymbolicLink DosDevices 17 ffffd60168305560 Directory KnownDlls32 18 ffffd60166c10e40 Key \REGISTRY 19 ffffd6016a8670c0 Directory BaseNamedObjects 20 ffffd60168484e10 Section Win32kCrossSessionGlobals ffffe60d7af68d30 ALPC Port PowerPort 21 ffffe60d7e516310 ALPC Port SmSsWinStationApiPort ffffe60d7d52e530 Event UniqueInteractiveSessionIdEvent ffffd60166cce3e0 Directory UMDFCommunicationPorts 22 ffffd601683040c0 Directory KnownDlls ffffe60d7b958b20 Device FatCdrom ffffe60d7b9588f0 Device Fat ffffe60d7aecfd30 ALPC Port PowerMonitorPort 23 ffffe60d7b7aedc0 Device Ntfs ffffd60166cac960 Directory FileSystem ffffd60166c05830 Directory KernelObjects 24 ffffe60d7b6dd4d0 FilterConnectionPort MicrosoftMalwareProtectionControlPortWD 26 ffffe60d7d155d30 ALPC Port SeLsaCommandPort ffffd60166c09230 Directory Callback 28 ffffd60166c08820 Directory Security 29 ffffe60d7d1b0d00 Device UdfsDisk 30 ffffe60d7b6dd580 FilterConnectionPort MicrosoftMalwareProtectionAsyncPortWD ffffd60166c08ae0 Directory Device 32 ffffd60166c88e30 SymbolicLink DriverData 34 ffffd6016a843c90 Section LsaPerformance ffffe60d7bcebc70 ALPC Port SmApiPort 35 ffffe60d7e6d47e0 FilterConnectionPort CLDMSGPORT ffffe60d7b6ddf20 FilterConnectionPort MicrosoftMalwareProtectionPortWD ffffd60166c2eb50 SymbolicLink OSDataRoot 36 ffffe60d7dd608e0 Event SAM_SERVICE_STARTED ffffd60166cac7a0 Directory Driver ffffd60166c79d80 Directory DriverStores |
object namespace from filesystem
3: kd> !object \Filesystem Object: ffffd60166cac960 Type: (ffffe60d7ae92a60) Directory ObjectHeader: ffffd60166cac930 (new version) HandleCount: 0 PointerCount: 34 Directory Object: ffffd60166c08060 Name: FileSystem Hash Address Type Name ---- ------- ---- ---- 02 ffffe60d7eb16df0 Driver mrxsmb 03 ffffe60d7eb19e30 Driver mrxsmb20 ffffe60d7e822e50 Driver storqosflt 04 ffffe60d7e5cb060 Driver luafv ffffe60d7b7ea5a0 Driver Wof 11 ffffe60d7b9428f0 Driver rdbss ffffe60d7b8022e0 Device CdfsRecognizer 12 ffffe60d7b7f2b00 Device UdfsDiskRecognizer ffffe60d7af020a0 Driver Fs_Rec 13 ffffe60d7b8ee8f0 Driver Msfs 15 ffffe60d7b970c30 Driver Dfsc 17 ffffe60d7af27e30 Driver srvnet 19 ffffe60d7e747e10 Driver wcifs ffffd60166cceae0 Directory Filters 21 ffffe60d7eab8df0 Driver bowser ffffe60d7b7ccc80 Driver FltMgr 22 ffffe60d7b7f2d40 Device FatCdRomRecognizer 23 ffffe60d7aeeeb60 Driver Ntfs 24 ffffe60d7e7e2e30 Driver CldFlt ffffe60d7b90cba0 Driver Npfs ffffe60d7b86de10 Driver Mup ffffe60d7af15970 Driver RAW 25 ffffe60d7b802b80 Device ReFSRecognizer ffffe60d7b7edd80 Driver WdFilter 27 ffffe60d7b749d20 Driver fastfat 31 ffffe60d7b7f1d80 Device FatDiskRecognizer 32 ffffe60d7b802dc0 Device ReFSv1Recognizer 33 ffffe60d7ae80e30 Driver srv2 ffffe60d7b9368f0 Driver NetBIOS ffffe60d7ba64e20 Driver FileCrypt ffffe60d7b7f3cf0 Device ExFatRecognizer 34 ffffe60d7d4c2e30 Driver udfs 35 ffffe60d7b8020a0 Device UdfsCdRomRecognizer |
object namespace for C drive
3: kd> !object \Global??\c: Object: ffffd60168185380 Type: (ffffe60d7ae927a0) SymbolicLink ### <-- ObjectHeader: ffffd60168185350 (new version) HandleCount: 0 PointerCount: 1 Directory Object: ffffd60166c075b0 Name: C: Flags: 00000000 ( Local ) Target String is '\Device\HarddiskVolume4' ### <-- Drive Letter Index is 3 (C:) |
Object는 Object Header와 Object Body로 구성
Object Manager는 Object Header를 관리하고, Object Body는 Object를 실제로 사용하는 Component가 소유
Object가 Memory Manager가 관리하는 Pool(Paged or Non-paged)에 공간을 할당해야 하기 때문에, Pool에 할당하는 Memory Block은 Pool Header + Object Header + Object Body Size(EPROCESS, ...)
object allocation
1: kd> bl 0 e Disable Clear fffff807`390b4f50 0001 (0001) nt!ObCreateObject 1: kd> g Breakpoint 0 hit nt!ObCreateObject: fffff807`390b4f50 4883ec58 sub rsp,58h 4: kd> k # Child-SP RetAddr Call Site 00 ffffab0a`f239f1a8 ffffac55`c67d11f2 nt!ObCreateObject 01 ffffab0a`f239f1b0 ffffac55`c67c40b1 win32kbase!CompositionObject::Create+0x5e 02 ffffab0a`f239f220 ffffac55`c67c3f3a win32kbase!CreateSharedResourceObject+0x9d 03 ffffab0a`f239f2c0 ffffac55`c677a2c5 win32kbase!DirectComposition::CApplicationChannel::CreateInternalSharedResource+0x46 04 ffffab0a`f239f320 ffffac55`c67798ed win32kbase!DirectComposition::CApplicationChannel::ProcessCommandBufferIterator+0x925 05 ffffab0a`f239f420 fffff807`38bd5c05 win32kbase!NtDCompositionProcessChannelBatchBuffer+0x19d 06 ffffab0a`f239f4c0 00007ff8`25d23724 nt!KiSystemServiceCopyEnd+0x25 07 00000089`695cf2a8 00007ff8`2292a2bc 0x00007ff8`25d23724 08 00000089`695cf2b0 00000000`00000000 0x00007ff8`2292a2bc 4: kd> bp nt!ObpAllocateObject 4: kd> bl 0 e Disable Clear fffff807`390b4f50 0001 (0001) nt!ObCreateObject 1 e Disable Clear fffff807`3908f7c0 0001 (0001) nt!ObpAllocateObject 4: kd> gu WARNING: Software breakpoints on session addresses can cause bugchecks. Use hardware execution breakpoints (ba e) if possible. Breakpoint 1 hit nt!ObpAllocateObject: fffff807`3908f7c0 4c894c2420 mov qword ptr [rsp+20h],r9 4: kd> k # Child-SP RetAddr Call Site 00 ffffab0a`f239f0d8 fffff807`390593b1 nt!ObpAllocateObject 01 ffffab0a`f239f0e0 fffff807`390b4f8d nt!ObCreateObjectEx+0xf1 02 ffffab0a`f239f150 ffffac55`c67d11f2 nt!ObCreateObject+0x3d 03 ffffab0a`f239f1b0 ffffac55`c67c40b1 win32kbase!CompositionObject::Create+0x5e 04 ffffab0a`f239f220 ffffac55`c67c3f3a win32kbase!CreateSharedResourceObject+0x9d 05 ffffab0a`f239f2c0 ffffac55`c677a2c5 win32kbase!DirectComposition::CApplicationChannel::CreateInternalSharedResource+0x46 06 ffffab0a`f239f320 ffffac55`c67798ed win32kbase!DirectComposition::CApplicationChannel::ProcessCommandBufferIterator+0x925 07 ffffab0a`f239f420 fffff807`38bd5c05 win32kbase!NtDCompositionProcessChannelBatchBuffer+0x19d 08 ffffab0a`f239f4c0 00007ff8`25d23724 nt!KiSystemServiceCopyEnd+0x25 09 00000089`695cf2a8 00007ff8`2292a2bc 0x00007ff8`25d23724 0a 00000089`695cf2b0 00000000`00000000 0x00007ff8`2292a2bc 4: kd> bp nt!ExAllocatePoolWithTag 4: kd> bl 0 e Disable Clear fffff807`390b4f50 0001 (0001) nt!ObCreateObject 1 e Disable Clear fffff807`3908f7c0 0001 (0001) nt!ObpAllocateObject 2 e Disable Clear fffff807`38d56030 0001 (0001) nt!ExAllocatePoolWithTag 4: kd> gu Breakpoint 2 hit nt!ExAllocatePoolWithTag: fffff807`38d56030 48895c2408 mov qword ptr [rsp+8],rbx 4: kd> k # Child-SP RetAddr Call Site 00 ffffab0a`f239f058 fffff807`3908f960 nt!ExAllocatePoolWithTag ## Allocation Size + POOL_HEADER 01 ffffab0a`f239f060 fffff807`390593b1 nt!ObpAllocateObject+0x1a0 ## Allocation Size of Object Header + Object Body 02 ffffab0a`f239f0e0 fffff807`390b4f8d nt!ObCreateObjectEx+0xf1 03 ffffab0a`f239f150 ffffac55`c67d11f2 nt!ObCreateObject+0x3d 04 ffffab0a`f239f1b0 ffffac55`c67c40b1 win32kbase!CompositionObject::Create+0x5e 05 ffffab0a`f239f220 ffffac55`c67c3f3a win32kbase!CreateSharedResourceObject+0x9d 06 ffffab0a`f239f2c0 ffffac55`c677a2c5 win32kbase!DirectComposition::CApplicationChannel::CreateInternalSharedResource+0x46 07 ffffab0a`f239f320 ffffac55`c67798ed win32kbase!DirectComposition::CApplicationChannel::ProcessCommandBufferIterator+0x925 08 ffffab0a`f239f420 fffff807`38bd5c05 win32kbase!NtDCompositionProcessChannelBatchBuffer+0x19d 09 ffffab0a`f239f4c0 00007ff8`25d23724 nt!KiSystemServiceCopyEnd+0x25 0a 00000089`695cf2a8 00007ff8`2292a2bc 0x00007ff8`25d23724 0b 00000089`695cf2b0 00000000`00000000 0x00007ff8`2292a2bc |
Object Header는 Pool Header 다음에 위치하고, Object Header 다음에 Object Body가 위치
Object Header 구성
- Object 유형
- Object Retention 정보
- Security Descriptor
nt!_OBJECT_HEADER
1: kd> dt nt!_POOL_HEADER +0x000 PreviousSize : Pos 0, 8 Bits +0x000 PoolIndex : Pos 8, 8 Bits +0x002 BlockSize : Pos 0, 8 Bits +0x002 PoolType : Pos 8, 8 Bits +0x000 Ulong1 : Uint4B +0x004 PoolTag : Uint4B +0x008 ProcessBilled : Ptr64 _EPROCESS +0x008 AllocatorBackTraceIndex : Uint2B +0x00a PoolTagHash : Uint2B 1: kd> dt nt!_OBJECT_HEADER +0x000 PointerCount : Int8B +0x008 HandleCount : Int8B +0x008 NextToFree : Ptr64 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : UChar +0x019 TraceFlags : UChar +0x019 DbgRefTrace : Pos 0, 1 Bit +0x019 DbgTracePermanent : Pos 1, 1 Bit +0x01a InfoMask : UChar +0x01b Flags : UChar +0x01b NewObject : Pos 0, 1 Bit +0x01b KernelObject : Pos 1, 1 Bit +0x01b KernelOnlyAccess : Pos 2, 1 Bit +0x01b ExclusiveObject : Pos 3, 1 Bit +0x01b PermanentObject : Pos 4, 1 Bit +0x01b DefaultSecurityQuota : Pos 5, 1 Bit +0x01b SingleHandleEntry : Pos 6, 1 Bit +0x01b DeletedInline : Pos 7, 1 Bit +0x01c Reserved : Uint4B +0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : Ptr64 Void +0x028 SecurityDescriptor : Ptr64 Void +0x030 Body : _QUAD |
할당된 Pool된 정보와 이와 연관된 Object Header 정보
Object Header Address = Object Address - sizeof(_OBJECT_HEADER)
example : Process Object Header
!process 0 0 ... ... ... PROCESS ffffd88e78cc6080 ### <-- Object Address SessionId: 0 Cid: 0a98 Peb: 36affa000 ParentCid: 0344 DirBase: 18f151000 ObjectTable: ffffc68a84177d40 HandleCount: 169. Image: WmiPrvSE.exe 3: kd> !pool ffffd88e78cc6080 2 ### <-- Pool page ffffd88e78cc6080 region is Nonpaged pool *ffffd88e78cc6000 size: 900 previous size: 0 (Allocated) *Proc ### <-- Pooltag Proc : Process objects, Binary : nt!ps 3: kd> !object ffffd88e78cc6080 Object: ffffd88e78cc6080 Type: (ffffd88e75294e80) Process ObjectHeader: ffffd88e78cc6050 (new version) HandleCount: 6 PointerCount: 196603 3: kd> dt nt!_OBJECT_HEADER ffffd88e78cc6050 +0x000 PointerCount : 0n196603 +0x008 HandleCount : 0n6 +0x008 NextToFree : 0x00000000`00000006 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : 0xe '' +0x019 TraceFlags : 0 '' +0x019 DbgRefTrace : 0y0 +0x019 DbgTracePermanent : 0y0 +0x01a InfoMask : 0x88 '' +0x01b Flags : 0 '' +0x01b NewObject : 0y0 +0x01b KernelObject : 0y0 +0x01b KernelOnlyAccess : 0y0 +0x01b ExclusiveObject : 0y0 +0x01b PermanentObject : 0y0 +0x01b DefaultSecurityQuota : 0y0 +0x01b SingleHandleEntry : 0y0 +0x01b DeletedInline : 0y0 +0x01c Reserved : 0xfeb948d9 +0x020 ObjectCreateInfo : 0xfffff807`47c517c0 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : 0xfffff807`47c517c0 Void +0x028 SecurityDescriptor : 0xffffc68a`8472c4e4 Void +0x030 Body : _QUAD |
※ Windows Server 2016 기준
Object Type을 확인하려면 Object Header의 TypeIndex field 값을 이용해야 합니다.
TypeIndex field를 이용하여 Index 값을 구해야 하는데 공식은 다음과 같습니다.
Index = TypeIndex ^ 2nd least significate byte of OBJECT_HEADER address ^ nt!ObHeaderCookie
https://medium.com/@ashabdalhalim/a-light-on-windows-10s-object-header-typeindex-value-e8f907e7073a
아래 예제를 통해 계산하는 방법을 살펴보겠습니다.
TypeIndex field는 0xe
OBJECT_HEADER address는 ffffd88e78cc6050, 하위 두 번째 byte는 60
nt!ObHeaderCookie의 byte 값은 69
이 값들을 XOR 연산 : e ^ 60 ^ 69 = 00000000`00000007
이제 이 계산된 Index 값을 nt!ObTypeIndexTable의 Index로 활용하여 Object Type을 확인합니다.
$ptrsize는 Pseudo-Register
$ptrsize : The size of a pointer. In kernel mode, this size is the pointer size on the target computer.
poi : 주소 안의 값을 참조
nt!_OBJECT_TYPE
3: kd> dt nt!_OBJECT_HEADER ffffd88e78cc6050 TypeIndex +0x018 TypeIndex : 0xe '' 3: kd> db nt!ObHeaderCookie L1 fffff807`47d545dc 69 3: kd> ? e ^ 60 ^ 69 Evaluate expression: 7 = 00000000`00000007 3: kd> dt nt!_OBJECT_TYPE poi(nt!ObTypeIndexTable + (0x7 * @$ptrsize )) +0x000 TypeList : _LIST_ENTRY [ 0xffffd88e`75294e80 - 0xffffd88e`75294e80 ] +0x010 Name : _UNICODE_STRING "Process" ### <-- Object Type +0x020 DefaultObject : (null) +0x028 Index : 0x7 '' +0x02c TotalNumberOfObjects : 0x46 +0x030 TotalNumberOfHandles : 0x22b +0x034 HighWaterNumberOfObjects : 0x4b +0x038 HighWaterNumberOfHandles : 0x24b +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER ### <--- +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x636f7250 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffffc68a`80cb1200 - 0xffffc68a`80cb1200 ] 3: kd> dt _OBJECT_TYPE_INITIALIZER (poi(nt!ObTypeIndexTable + (0x7 * @$ptrsize )) + 0x40) nt!_OBJECT_TYPE_INITIALIZER +0x000 Length : 0x78 +0x002 ObjectTypeFlags : 0xca +0x002 CaseInsensitive : 0y0 +0x002 UnnamedObjectsOnly : 0y1 +0x002 UseDefaultObject : 0y0 +0x002 SecurityRequired : 0y1 +0x002 MaintainHandleCount : 0y0 +0x002 MaintainTypeList : 0y0 +0x002 SupportsObjectCallbacks : 0y1 +0x002 CacheAligned : 0y1 +0x003 UseExtendedParameters : 0y0 +0x003 Reserved : 0y0000000 (0) +0x004 ObjectTypeCode : 0x20 +0x008 InvalidAttributes : 0xb0 +0x00c GenericMapping : _GENERIC_MAPPING +0x01c ValidAccessMask : 0x1fffff +0x020 RetainAccess : 0x101000 +0x024 PoolType : 200 ( NonPagedPoolNx ) +0x028 DefaultPagedPoolCharge : 0x1000 +0x02c DefaultNonPagedPoolCharge : 0x8a8 +0x030 DumpProcedure : (null) +0x038 OpenProcedure : 0xfffff807`47d99140 long nt!PspProcessOpen+0 ### <--- +0x040 CloseProcedure : 0xfffff807`47e04c50 void nt!PspProcessClose+0 ### <--- +0x048 DeleteProcedure : 0xfffff807`47de0cb0 void nt!PspProcessDelete+0 ### <--- +0x050 ParseProcedure : (null) +0x050 ParseProcedureEx : (null) +0x058 SecurityProcedure : 0xfffff807`47db7bc0 long nt!SeDefaultObjectMethod+0 ### <--- +0x060 QueryNameProcedure : (null) +0x068 OkayToCloseProcedure : (null) +0x070 WaitObjectFlagMask : 0 +0x074 WaitObjectFlagOffset : 0 +0x076 WaitObjectPointerOffset : 0 |
이제 Object가 Process Type인 것을 확인하였으니, 실제 구조체도 조회해보겠습니다.
Object Type별 구조체 예제
- File: _FILE_OBJECT
- Process: _EPROCESS
- SymbolicLink: _OBJECT_SYMBOLIC_LINK
- Token: _TOKEN
- Thread: _ETHREAD
- Mutant: _KMUTANT
- Driver: _DRIVER_OBJECT
- Key: _CM_KEY_BODY
- Type: _OBJECT_TYPE
nt!_EPROCESS
3: kd> dt nt!_EPROCESS ffffd88e78cc6080 +0x000 Pcb : _KPROCESS +0x2d8 ProcessLock : _EX_PUSH_LOCK +0x2e0 UniqueProcessId : 0x00000000`00000a98 Void +0x2e8 ActiveProcessLinks : _LIST_ENTRY [ 0xfffff807`47c205e0 - 0xffffd88e`78f5f368 ] +0x2f8 RundownProtect : _EX_RUNDOWN_REF +0x300 Flags2 : 0xd014 +0x300 JobNotReallyActive : 0y0 +0x300 AccountingFolded : 0y0 +0x300 NewProcessReported : 0y1 +0x300 ExitProcessReported : 0y0 +0x300 ReportCommitChanges : 0y1 +0x300 LastReportMemory : 0y0 +0x300 ForceWakeCharge : 0y0 +0x300 CrossSessionCreate : 0y0 +0x300 NeedsHandleRundown : 0y0 +0x300 RefTraceEnabled : 0y0 +0x300 PicoCreated : 0y0 +0x300 EmptyJobEvaluated : 0y0 +0x300 DefaultPagePriority : 0y101 +0x300 PrimaryTokenFrozen : 0y1 +0x300 ProcessVerifierTarget : 0y0 +0x300 RestrictSetThreadContext : 0y0 +0x300 AffinityPermanent : 0y0 +0x300 AffinityUpdateEnable : 0y0 +0x300 PropagateNode : 0y0 +0x300 ExplicitAffinity : 0y0 +0x300 ProcessExecutionState : 0y00 +0x300 EnableReadVmLogging : 0y0 +0x300 EnableWriteVmLogging : 0y0 +0x300 FatalAccessTerminationRequested : 0y0 +0x300 DisableSystemAllowedCpuSet : 0y0 +0x300 ProcessStateChangeRequest : 0y00 +0x300 ProcessStateChangeInProgress : 0y0 +0x300 InPrivate : 0y0 +0x304 Flags : 0x144d0c01 +0x304 CreateReported : 0y1 +0x304 NoDebugInherit : 0y0 +0x304 ProcessExiting : 0y0 +0x304 ProcessDelete : 0y0 +0x304 ManageExecutableMemoryWrites : 0y0 +0x304 VmDeleted : 0y0 +0x304 OutswapEnabled : 0y0 +0x304 Outswapped : 0y0 +0x304 FailFastOnCommitFail : 0y0 +0x304 Wow64VaSpace4Gb : 0y0 +0x304 AddressSpaceInitialized : 0y11 +0x304 SetTimerResolution : 0y0 +0x304 BreakOnTermination : 0y0 +0x304 DeprioritizeViews : 0y0 +0x304 WriteWatch : 0y0 +0x304 ProcessInSession : 0y1 +0x304 OverrideAddressSpace : 0y0 +0x304 HasAddressSpace : 0y1 +0x304 LaunchPrefetched : 0y1 +0x304 Background : 0y0 +0x304 VmTopDown : 0y0 +0x304 ImageNotifyDone : 0y1 +0x304 PdeUpdateNeeded : 0y0 +0x304 VdmAllowed : 0y0 +0x304 ProcessRundown : 0y0 +0x304 ProcessInserted : 0y1 +0x304 DefaultIoPriority : 0y010 +0x304 ProcessSelfDelete : 0y0 +0x304 SetTimerResolutionLink : 0y0 +0x308 CreateTime : _LARGE_INTEGER 0x01d967d0`44de3e44 +0x310 ProcessQuotaUsage : [2] 0x2bf8 +0x320 ProcessQuotaPeak : [2] 0x34c8 +0x330 PeakVirtualSize : 0x00000201`04bb3000 +0x338 VirtualSize : 0x00000201`047d2000 +0x340 SessionProcessLinks : _LIST_ENTRY [ 0xffffb600`2e1c5010 - 0xffffd88e`78f5f3c0 ] +0x350 ExceptionPortData : 0xffffd88e`7722dd30 Void +0x350 ExceptionPortValue : 0xffffd88e`7722dd30 +0x350 ExceptionPortState : 0y000 +0x358 Token : _EX_FAST_REF +0x360 MmReserved : 0 +0x368 AddressCreationLock : _EX_PUSH_LOCK +0x370 PageTableCommitmentLock : _EX_PUSH_LOCK +0x378 RotateInProgress : (null) +0x380 ForkInProgress : (null) +0x388 CommitChargeJob : 0xffffd88e`79111990 _EJOB +0x390 CloneRoot : _RTL_AVL_TREE +0x398 NumberOfPrivatePages : 0x192 +0x3a0 NumberOfLockedPages : 0 +0x3a8 Win32Process : 0xffffc617`82802050 Void +0x3b0 Job : 0xffffd88e`79111990 _EJOB +0x3b8 SectionObject : 0xffffc68a`853a6600 Void +0x3c0 SectionBaseAddress : 0x00007ff7`b8860000 Void +0x3c8 Cookie : 0x907252e +0x3d0 WorkingSetWatch : (null) +0x3d8 Win32WindowStation : 0x00000000`00000164 Void +0x3e0 InheritedFromUniqueProcessId : 0x00000000`00000344 Void +0x3e8 Spare0 : (null) +0x3f0 OwnerProcessId : 0x344 +0x3f8 Peb : 0x00000003`6affa000 _PEB +0x400 Session : 0xffffb600`2e1c5000 _MM_SESSION_SPACE +0x408 Spare1 : (null) +0x410 QuotaBlock : 0xfffff807`47c517c0 _EPROCESS_QUOTA_BLOCK +0x418 ObjectTable : 0xffffc68a`84177d40 _HANDLE_TABLE +0x420 DebugPort : (null) +0x428 WoW64Process : (null) +0x430 DeviceMap : 0xffffc68a`808137e0 Void +0x438 EtwDataSource : 0xffffd88e`791914d0 Void +0x440 PageDirectoryPte : 0 +0x448 ImageFilePointer : 0xffffd88e`78d587c0 _FILE_OBJECT +0x450 ImageFileName : [15] "WmiPrvSE.exe" +0x45f PriorityClass : 0x2 '' +0x460 SecurityPort : (null) +0x468 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO +0x470 JobLinks : _LIST_ENTRY [ 0xffffd88e`791119b8 - 0xffffd88e`791119b8 ] +0x480 HighestUserAddress : 0x00007fff`ffff0000 Void +0x488 ThreadListHead : _LIST_ENTRY [ 0xffffd88e`78fe4728 - 0xffffd88e`79058728 ] +0x498 ActiveThreads : 4 +0x49c ImagePathHash : 0 +0x4a0 DefaultHardErrorProcessing : 0 +0x4a4 LastThreadExitStatus : 0n0 +0x4a8 PrefetchTrace : _EX_FAST_REF +0x4b0 LockedPagesList : (null) +0x4b8 ReadOperationCount : _LARGE_INTEGER 0x0 +0x4c0 WriteOperationCount : _LARGE_INTEGER 0x0 +0x4c8 OtherOperationCount : _LARGE_INTEGER 0x6f +0x4d0 ReadTransferCount : _LARGE_INTEGER 0x0 +0x4d8 WriteTransferCount : _LARGE_INTEGER 0x0 +0x4e0 OtherTransferCount : _LARGE_INTEGER 0x5a0 +0x4e8 CommitChargeLimit : 0x21e84 +0x4f0 CommitCharge : 0x1f0 +0x4f8 CommitChargePeak : 0x4ec +0x500 Vm : _MMSUPPORT_FULL +0x610 MmProcessLinks : _LIST_ENTRY [ 0xfffff807`47c4c0e0 - 0xffffd88e`78f5f690 ] +0x620 ModifiedPageCount : 1 +0x624 ExitStatus : 0n259 +0x628 VadRoot : _RTL_AVL_TREE +0x630 VadHint : 0xffffd88e`79516210 Void +0x638 VadCount : 0x44 +0x640 VadPhysicalPages : 0 +0x648 VadPhysicalPagesLimit : 0 +0x650 AlpcContext : _ALPC_PROCESS_CONTEXT +0x670 TimerResolutionLink : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ] +0x680 TimerResolutionStackRecord : (null) +0x688 RequestedTimerResolution : 0 +0x68c SmallestTimerResolution : 0 +0x690 ExitTime : _LARGE_INTEGER 0x0 +0x698 InvertedFunctionTable : (null) +0x6a0 InvertedFunctionTableLock : _EX_PUSH_LOCK +0x6a8 ActiveThreadsHighWatermark : 9 +0x6ac LargePrivateVadCount : 0 +0x6b0 ThreadListLock : _EX_PUSH_LOCK +0x6b8 WnfContext : 0xffffc68a`853a88b0 Void +0x6c0 ServerSilo : (null) +0x6c8 SignatureLevel : 0 '' +0x6c9 SectionSignatureLevel : 0 '' +0x6ca Protection : _PS_PROTECTION +0x6cb HangCount : 0y000 +0x6cb GhostCount : 0y000 +0x6cb PrefilterException : 0y0 +0x6cc Flags3 : 0x40c008 +0x6cc Minimal : 0y0 +0x6cc ReplacingPageRoot : 0y0 +0x6cc Crashed : 0y0 +0x6cc JobVadsAreTracked : 0y1 +0x6cc VadTrackingDisabled : 0y0 +0x6cc AuxiliaryProcess : 0y0 +0x6cc SubsystemProcess : 0y0 +0x6cc IndirectCpuSets : 0y0 +0x6cc RelinquishedCommit : 0y0 +0x6cc HighGraphicsPriority : 0y0 +0x6cc CommitFailLogged : 0y0 +0x6cc ReserveFailLogged : 0y0 +0x6cc SystemProcess : 0y0 +0x6cc HideImageBaseAddresses : 0y0 +0x6cc AddressPolicyFrozen : 0y1 +0x6cc ProcessFirstResume : 0y1 +0x6cc ForegroundExternal : 0y0 +0x6cc ForegroundSystem : 0y0 +0x6cc HighMemoryPriority : 0y0 +0x6cc EnableProcessSuspendResumeLogging : 0y0 +0x6cc EnableThreadSuspendResumeLogging : 0y0 +0x6cc SecurityDomainChanged : 0y0 +0x6cc SecurityFreezeComplete : 0y1 +0x6cc VmProcessorHost : 0y0 +0x6d0 DeviceAsid : 0n0 +0x6d8 SvmData : (null) +0x6e0 SvmProcessLock : _EX_PUSH_LOCK +0x6e8 SvmLock : 0 +0x6f0 SvmProcessDeviceListHead : _LIST_ENTRY [ 0xffffd88e`78cc6770 - 0xffffd88e`78cc6770 ] +0x700 LastFreezeInterruptTime : 0 +0x708 DiskCounters : (null) +0x710 PicoContext : (null) +0x718 EnclaveTable : (null) +0x720 EnclaveNumber : 0 +0x728 EnclaveLock : _EX_PUSH_LOCK +0x730 HighPriorityFaultsAllowed : 0 +0x738 EnergyContext : (null) +0x740 VmContext : (null) +0x748 SequenceNumber : 0x61 +0x750 CreateInterruptTime : 0x962238fb +0x758 CreateUnbiasedInterruptTime : 0x962238fb +0x760 TotalUnbiasedFrozenTime : 0 +0x768 LastAppStateUpdateTime : 0x962238fb +0x770 LastAppStateUptime : 0y0000000000000000000000000000000000000000000000000000000000000 (0) +0x770 LastAppState : 0y000 +0x778 SharedCommitCharge : 0x1f5 +0x780 SharedCommitLock : _EX_PUSH_LOCK +0x788 SharedCommitLinks : _LIST_ENTRY [ 0xffffc68a`84ea3808 - 0xffffc68a`851a59c8 ] +0x798 AllowedCpuSets : 0 +0x7a0 DefaultCpuSets : 0 +0x798 AllowedCpuSetsIndirect : (null) +0x7a0 DefaultCpuSetsIndirect : (null) +0x7a8 DiskIoAttribution : (null) +0x7b0 DxgProcess : 0xffffc68a`85679b80 Void +0x7b8 Win32KFilterSet : 0 +0x7c0 ProcessTimerDelay : _PS_INTERLOCKED_TIMER_DELAY_VALUES +0x7c8 KTimerSets : 0 +0x7cc KTimer2Sets : 0 +0x7d0 ThreadTimerSets : 3 +0x7d8 VirtualTimerListLock : 0 +0x7e0 VirtualTimerListHead : _LIST_ENTRY [ 0xffffd88e`78cc6860 - 0xffffd88e`78cc6860 ] +0x7f0 WakeChannel : _WNF_STATE_NAME +0x7f0 WakeInfo : _PS_PROCESS_WAKE_INFORMATION +0x820 MitigationFlags : 0x21 +0x820 MitigationFlagsValues : <unnamed-tag> +0x824 MitigationFlags2 : 0 +0x824 MitigationFlags2Values : <unnamed-tag> +0x828 PartitionObject : 0xffffd88e`75274420 Void +0x830 SecurityDomain : 0 +0x838 ParentSecurityDomain : 0 +0x840 CoverageSamplerContext : (null) +0x848 MmHotPatchContext : (null) 3: kd> dt nt!_EPROCESS ffffd88e78cc6080 ImageFileName +0x450 ImageFileName : [15] "WmiPrvSE.exe" |
위에서 살펴본 ObjectType은 Object Namespace에 ObjectTypes Container로 존재하며, 해당 Container에 다양한 Object Type이 위치합니다.
!object \ObjectTypes
3: kd> !object \ObjectTypes Object: ffffc68a80807ba0 Type: (ffffd88e75294640) Directory ObjectHeader: ffffc68a80807b70 (new version) HandleCount: 0 PointerCount: 67 Directory Object: ffffc68a80808060 Name: ObjectTypes Hash Address Type Name ---- ------- ---- ---- 00 ffffd88e752f42a0 Type TmTm 01 ffffd88e7529ec40 Type Desktop ffffd88e75294e80 Type Process 02 ffffd88e752f37a0 Type RegistryTransaction 03 ffffd88e7529da60 Type DebugObject 04 ffffd88e75a26bc0 Type VRegConfigurationContext ffffd88e7529d4e0 Type TpWorkerFactory 05 ffffd88e752f3a60 Type Adapter ffffd88e75294bc0 Type Token 06 ffffd88e753fcc40 Type DxgkSharedResource 07 ffffd88e7529e2a0 Type PsSiloContextPaged 08 ffffd88e753fc400 Type NdisCmState ffffd88e7529e140 Type ActivityReference 09 ffffd88e753fcae0 Type PcwObject ffffd88e752f4c40 Type WmiGuid 11 ffffd88e753fbbc0 Type DmaAdapter ffffd88e753fba60 Type EtwRegistration 12 ffffd88e75a27ae0 Type DxgkSharedBundleObject ffffd88e752f3640 Type Session ffffd88e7529eda0 Type RawInputManager ffffd88e7529e6c0 Type Timer 13 ffffd88e7529d0c0 Type Mutant 14 ffffd88e7529eae0 Type IRTimer 16 ffffd88e75a27da0 Type DxgkCurrentDxgProcessObject ffffd88e752f4140 Type IoCompletion 17 ffffd88e75a27c40 Type DxgkSharedProtectedSessionObject ffffd88e753fcf00 Type DxgkSharedSyncObject ffffd88e7529e820 Type WindowStation ffffd88e7529dd20 Type Profile 18 ffffd88e752f3e80 Type File 20 ffffd88e7529d640 Type Partition 21 ffffd88e753fb4e0 Type DxgkSharedKeyedMutexObject ffffd88e7529d900 Type Semaphore 22 ffffd88e7529e560 Type PsSiloContextNonPaged 23 ffffd88e753fb380 Type EtwConsumer ffffd88e7529dbc0 Type Composition 24 ffffd88e753fcda0 Type CoverageSampler ffffd88e753fc2a0 Type EtwSessionDemuxEntry ffffd88e7529ef00 Type CoreMessaging 25 ffffd88e752f4820 Type TmTx ffffd88e752947a0 Type SymbolicLink 26 ffffd88e753fb7a0 Type FilterConnectionPort ffffd88e752f4980 Type Key ffffd88e7529d380 Type KeyedEvent ffffd88e7529e400 Type Callback 27 ffffd88e752f3220 Type WaitCompletionPacket 28 ffffd88e7529d7a0 Type UserApcReserve ffffd88e752944e0 Type Job 29 ffffd88e75a27140 Type DxgkDisplayManagerObject ffffd88e75a26e80 Type DxgkSharedSwapChainObject ffffd88e752f46c0 Type Controller ffffd88e7529d220 Type IoCompletionReserve 30 ffffd88e752f3d20 Type Device ffffd88e75294640 Type Directory 31 ffffd88e752f4560 Type Section ffffd88e752f4400 Type TmEn ffffd88e7529de80 Type Thread 32 ffffd88e75a27f00 Type DxgkCompositionObject ffffd88e752940c0 Type Type 33 ffffd88e753fb640 Type FilterCommunicationPort ffffd88e752f4ae0 Type PowerRequest 35 ffffd88e752f4f00 Type TmRm ffffd88e7529e980 Type Event 36 ffffd88e752f3bc0 Type ALPC Port ffffd88e752f4da0 Type Driver |
Object Body
Object Body는 해당 Object를 사용하는 Component가 소유
주로 Object는 Object Body를 의미
Object Body의 크기와 Object Body 안에 들어가는 Field 값들은 Object Type에 따라 상이
Handle Table
Handle Table은 Handle을 참조하고 있는 Object로 변환하기 위해 사용
Handle Table은 Kernel mode 자료 구조
Handle Table은 프로세스별로 존재하며, 모든 프로세스는 자기 자신의 Handle Table을 이용하여, Handle을 Object로 변환
Handle Table은 HANDLE_TABLE_ENTRY 유형 Entry의 배열
따라서, Handle은 Handle Table의 Index
※ OS Version 별로 상이
Handle Table Entry에는 Object Header를 가리키는 Pointer와 Access Mask 그리고 몇 가지 추가 flag bit 위치
- Audit on Close
- Inheritable flag : 자식 프로세스에 상속 가능한 Handle 속성 설정을 위한 flag
- Lock bit : Handle Entry 수정할 때 사용
- Protect on close
!handle 0 3 <EPROCESS 주소> 를 이용하여 특정 프로세스의 전체 Handle 목록을 확인할 수 있습니다.
!handle 0 3 <EPROCESS>
7: kd> !process 0 1 notepad.exe PROCESS ffffc503fd5cc080 SessionId: 1 Cid: 1470 Peb: e17dcdc000 ParentCid: 13f0 DirBase: 11ba9a000 ObjectTable: ffff990294373cc0 HandleCount: 257. Image: notepad.exe VadRoot ffffc503fd4d4220 Vads 114 Clone 0 Private 672. Modified 20. Locked 0. DeviceMap ffff99028cbb58a0 Token ffff990295e71770 ElapsedTime 00:00:06.592 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 289248 QuotaPoolUsage[NonPagedPool] 16024 Working Set Sizes (now,min,max) (4528, 50, 345) (18112KB, 200KB, 1380KB) PeakWorkingSetSize 4423 VirtualSize 2101430 Mb PeakVirtualSize 2101430 Mb PageFaultCount 4609 MemoryPriority FOREGROUND BasePriority 8 CommitCharge 856 7: kd> !handle 0 3 ffffc503fd5cc080 PROCESS ffffc503fd5cc080 SessionId: 1 Cid: 1470 Peb: e17dcdc000 ParentCid: 13f0 DirBase: 11ba9a000 ObjectTable: ffff990294373cc0 HandleCount: 255. Image: notepad.exe Handle table at ffff990294373cc0 with 255 entries in use 0004: Object: ffffc503fd4a29e0 GrantedAccess: 001f0003 (Protected) (Inherit) Entry: ffff99029215b010 Object: ffffc503fd4a29e0 Type: (ffffc503f809c4e0) Event ObjectHeader: ffffc503fd4a29b0 (new version) HandleCount: 1 PointerCount: 32764 0008: Object: ffffc503fd4a2a60 GrantedAccess: 001f0003 (Protected) (Inherit) Entry: ffff99029215b020 Object: ffffc503fd4a2a60 Type: (ffffc503f809c4e0) Event ObjectHeader: ffffc503fd4a2a30 (new version) HandleCount: 1 PointerCount: 32765 <snip> 00c0: Object: ffffc503fd4457e0 GrantedAccess: 00100001 (Protected) (Inherit) Entry: ffff99029215b300 Object: ffffc503fd4457e0 Type: (ffffc503f80f4560) File ObjectHeader: ffffc503fd4457b0 (new version) HandleCount: 1 PointerCount: 32764 |
Process Explorer를 통해서도 동일한 내용을 확인할 수 있습니다.
Process Explorer에서 Handle을 보기 위해서는 View > Show Lower Pane 옵션을 Check 해줘야 특정 프로세스 선택 시, Lower Pane에 Handle / DLL / Thread를 확인할 수 있습니다.
Windbg와 Process Explorer에서 확인한 Handle 하나를 예를 들어, 좀 더 자세히 살펴 보도록 하겠습니다.
- 00c0는 Handle Number
- ffff99029215b300는 Handle Table Entry의 주소
- ffff990294373cc0는 Handle Table 주소
- ffffc503fd4457e0는 Object 주소
Handle Table Entry
Handle table at ffff990294373cc0 with 255 entries in use 00c0: Object: ffffc503fd4457e0 GrantedAccess: 00100001 (Protected) (Inherit) Entry: ffff99029215b300 Object: ffffc503fd4457e0 Type: (ffffc503f80f4560) File ObjectHeader: ffffc503fd4457b0 (new version) HandleCount: 1 PointerCount: 32764 7: kd> dt nt!_HANDLE_TABLE_ENTRY ffff99029215b300 +0x000 VolatileLowValue : 0n-4250275153336795145 +0x000 LowValue : 0n-4250275153336795145 +0x000 InfoTable : 0xc503fd44`57b0fff7 _HANDLE_TABLE_ENTRY_INFO +0x008 HighValue : 0n1048577 +0x008 NextFreeHandleEntry : 0x00000000`00100001 _HANDLE_TABLE_ENTRY +0x008 LeafHandleValue : _EXHANDLE +0x000 RefCountField : 0n-4250275153336795145 +0x000 Unlocked : 0y1 +0x000 RefCnt : 0y0111111111111011 (0x7ffb) +0x000 Attributes : 0y000 +0x000 ObjectPointerBits : 0y11000101000000111111110101000100010101111011 (0xc503fd4457b) +0x008 GrantedAccessBits : 0y0000100000000000000000001 (0x100001) +0x008 NoRightsUpgrade : 0y0 +0x008 Spare1 : 0y000000 (0) +0x00c Spare2 : 0 7: kd> !object ffffc503fd4457e0 Object: ffffc503fd4457e0 Type: (ffffc503f80f4560) File ObjectHeader: ffffc503fd4457b0 (new version) HandleCount: 1 PointerCount: 32763 ObjectHeader: ffffc503fd4457b0 + 0x30(size of nt!_OBJECT_HEADER in x64) = Object: ffffc503fd4457e0 |
추가로 Resource Monitor를 이용해서도 동일한 내용을 확인할 수 있습니다.
Handle Type
Handle에는 일반 Process Handle과 Kernel Handle로 구분할 수 있습니다.
Process Handle은 개별 Process마다 별도로 존재합니다. 즉, A 프로세스와 B 프로세스에서 확인되는 Handle의 값이 같더라도 서로 다른 Handle 입니다.
따라서, Process Handle은 해당 Process의 Context 내에서만 존재하게 됩니다.
Process Handle
7: kd> !process 0 0 lsass.exe PROCESS ffffc503fa6e9140 SessionId: 0 Cid: 02d4 Peb: bb7c7e8000 ParentCid: 022c DirBase: 40a82d000 ObjectTable: ffff9902900becc0 HandleCount: 1185. Image: lsass.exe 7: kd> !handle 00d0 3 ffffc503fa6e9140 PROCESS ffffc503fa6e9140 SessionId: 0 Cid: 02d4 Peb: bb7c7e8000 ParentCid: 022c DirBase: 40a82d000 ObjectTable: ffff9902900becc0 HandleCount: 1185. Image: lsass.exe Handle table at ffff9902900becc0 with 1185 entries in use 00d0: Object: ffffc503faeab8e0 GrantedAccess: 001f0003 (Protected) (Inherit) Entry: ffff9902900fb340 Object: ffffc503faeab8e0 Type: (ffffc503f809c4e0) Event ObjectHeader: ffffc503faeab8b0 (new version) HandleCount: 1 PointerCount: 1 7: kd> !process 0 0 notepad.exe PROCESS ffffc503fd5cc080 SessionId: 1 Cid: 1470 Peb: e17dcdc000 ParentCid: 13f0 DirBase: 11ba9a000 ObjectTable: ffff990294373cc0 HandleCount: 254. Image: notepad.exe 7: kd> !handle 00d0 3 ffffc503fd5cc080 PROCESS ffffc503fd5cc080 SessionId: 1 Cid: 1470 Peb: e17dcdc000 ParentCid: 13f0 DirBase: 11ba9a000 ObjectTable: ffff990294373cc0 HandleCount: 254. Image: notepad.exe Handle table at ffff990294373cc0 with 254 entries in use 00d0: Object: ffffc503fd4a2e60 GrantedAccess: 001f0003 (Protected) (Inherit) Entry: ffff99029215b340 Object: ffffc503fd4a2e60 Type: (ffffc503f809c4e0) Event ObjectHeader: ffffc503fd4a2e30 (new version) HandleCount: 1 PointerCount: 32759 |
일반 Process와 달리 Kernel Component들은 특정 Process Context 에서만 실행되지 않습니다.
만약 한 Process Context에서 생성된 Handle이 있다면, 다른 Process Context에서 실행되던 Kernel Mode Component는 그 Handle을 참조할 수가 없게 됩니다.
이러한 이유 때문에, 모든 Process Context에서 접근 가능한 Handle의 필요성이 생기게 되고, 이로 인해 Windows는 Kernel Handle이라는 것을 제공합니다
Object Manager는 Kernel Mode Component가 생성 요청한 Handle을 System Process와 연관된 Global Handle Table에 Reference를 위치시키게 됩니다.
Kernel Handle Table
7: kd> !process 4 0 Searching for Process with Cid == 4 PROCESS ffffc503f8075600 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001ad000 ObjectTable: ffff99028c604ac0 HandleCount: 2510. Image: System 7: kd> dt nt!_EPROCESS ffffc503f8075600 ObjectTable +0x418 ObjectTable : 0xffff9902`8c604ac0 _HANDLE_TABLE ### <-- 7: kd> dx -id 0,0,ffffc503f8075600 -r1 ((ntkrnlmp!_HANDLE_TABLE *)0xffff99028c604ac0) ((ntkrnlmp!_HANDLE_TABLE *)0xffff99028c604ac0) : 0xffff99028c604ac0 [Type: _HANDLE_TABLE *] [+0x000] NextHandleNeedingPool : 0x3000 [Type: unsigned long] [+0x004] ExtraInfoPages : 0 [Type: long] [+0x008] TableCode : 0xffff99028ff53001 [Type: unsigned __int64] [+0x010] QuotaProcess : 0x0 [Type: _EPROCESS *] [+0x018] HandleTableList [Type: _LIST_ENTRY] ### <-- [+0x028] UniqueProcessId : 0x4 [Type: unsigned long] [+0x02c] Flags : 0x0 [Type: unsigned long] [+0x02c ( 0: 0)] StrictFIFO : 0x0 [Type: unsigned char] [+0x02c ( 1: 1)] EnableHandleExceptions : 0x0 [Type: unsigned char] [+0x02c ( 2: 2)] Rundown : 0x0 [Type: unsigned char] [+0x02c ( 3: 3)] Duplicated : 0x0 [Type: unsigned char] [+0x02c ( 4: 4)] RaiseUMExceptionOnInvalidHandleClose : 0x0 [Type: unsigned char] [+0x030] HandleContentionEvent [Type: _EX_PUSH_LOCK] [+0x038] HandleTableLock [Type: _EX_PUSH_LOCK] [+0x040] FreeLists [Type: _HANDLE_TABLE_FREE_LIST [1]] [+0x040] ActualEntry [Type: unsigned char [32]] [+0x060] DebugInfo : 0x0 [Type: _HANDLE_TRACE_DEBUG_INFO *] 7: kd> x nt!ObpKernelHandleTable fffff807`38e27020 nt!ObpKernelHandleTable = <no type information> 7: kd> ? poi(ObpKernelHandleTable) Evaluate expression: -113238752605504 = ffff9902`8c604ac0 7: kd> dq fffff807`38e27020 L1 fffff807`38e27020 ffff9902`8c604ac0 7: kd> dt nt!_HANDLE_TABLE poi(ObpKernelHandleTable) +0x000 NextHandleNeedingPool : 0x3000 +0x004 ExtraInfoPages : 0n0 +0x008 TableCode : 0xffff9902`8ff53001 +0x010 QuotaProcess : (null) +0x018 HandleTableList : _LIST_ENTRY [ 0xffff9902`8c60ecd8 - 0xfffff807`3937ba88 ] ### <-- +0x028 UniqueProcessId : 4 +0x02c Flags : 0 +0x02c StrictFIFO : 0y0 +0x02c EnableHandleExceptions : 0y0 +0x02c Rundown : 0y0 +0x02c Duplicated : 0y0 +0x02c RaiseUMExceptionOnInvalidHandleClose : 0y0 +0x030 HandleContentionEvent : _EX_PUSH_LOCK +0x038 HandleTableLock : _EX_PUSH_LOCK +0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST +0x040 ActualEntry : [32] "" +0x060 DebugInfo : (null) 7: kd> dt nt!_HANDLE_TABLE ffff9902`8c604ac0 +0x000 NextHandleNeedingPool : 0x3000 +0x004 ExtraInfoPages : 0n0 +0x008 TableCode : 0xffff9902`8ff53001 +0x010 QuotaProcess : (null) +0x018 HandleTableList : _LIST_ENTRY [ 0xffff9902`8c60ecd8 - 0xfffff807`3937ba88 ] ### <-- +0x028 UniqueProcessId : 4 +0x02c Flags : 0 +0x02c StrictFIFO : 0y0 +0x02c EnableHandleExceptions : 0y0 +0x02c Rundown : 0y0 +0x02c Duplicated : 0y0 +0x02c RaiseUMExceptionOnInvalidHandleClose : 0y0 +0x030 HandleContentionEvent : _EX_PUSH_LOCK +0x038 HandleTableLock : _EX_PUSH_LOCK +0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST +0x040 ActualEntry : [32] "" +0x060 DebugInfo : (null) 7: kd> dt nt!_HANDLE_TABLE 0xffff9902`8c60ecd8-0x18 +0x000 NextHandleNeedingPool : 0x400 +0x004 ExtraInfoPages : 0n0 +0x008 TableCode : 0xffff9902`8c64d000 +0x010 QuotaProcess : 0xffffc503`f80c9080 _EPROCESS +0x018 HandleTableList : _LIST_ENTRY [ 0xffff9902`8cd0dd18 - 0xffff9902`8c604ad8 ] +0x028 UniqueProcessId : 0x88 +0x02c Flags : 0x10 +0x02c StrictFIFO : 0y0 +0x02c EnableHandleExceptions : 0y0 +0x02c Rundown : 0y0 +0x02c Duplicated : 0y0 +0x02c RaiseUMExceptionOnInvalidHandleClose : 0y1 +0x030 HandleContentionEvent : _EX_PUSH_LOCK +0x038 HandleTableLock : _EX_PUSH_LOCK +0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST +0x040 ActualEntry : [32] "" +0x060 DebugInfo : (null) 7: kd> dt nt!_EPROCESS 0xffffc503`f80c9080 ImageFileName +0x450 ImageFileName : [15] "Registry" |
System 프로세스의 Handle Table에 있는 Handle Table Entry를 이용하여, 관련된 Object의 주소를 획득할 수 있습니다.
Handle Table Entry
7: kd> !process 4 0 Searching for Process with Cid == 4 PROCESS ffffc503f8075600 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001ad000 ObjectTable: ffff99028c604ac0 HandleCount: 2510. Image: System 7: kd> !handle 0 3 ffffc503f8075600 PROCESS ffffc503f8075600 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001ad000 ObjectTable: ffff99028c604ac0 HandleCount: 2510. Image: System Kernel handle table at ffff99028c604ac0 with 2510 entries in use 0004: Object: ffffc503f8075600 GrantedAccess: 001fffff (Protected) (Audit) Entry: ffff99028c625010 ### <-- Object: ffffc503f8075600 Type: (ffffc503f8093220) Process ObjectHeader: ffffc503f80755d0 (new version) HandleCount: 5 PointerCount: 180602 0008: Object: ffffc503f81c1140 GrantedAccess: 001fffff (Protected) Entry: ffff99028c625020 ### <-- Object: ffffc503f81c1140 Type: (ffffc503f809dda0) Thread ObjectHeader: ffffc503f81c1110 (new version) HandleCount: 1 PointerCount: 2 000c: Object: ffffc503fa668dc0 GrantedAccess: 0012019f (Protected) Entry: ffff99028c625030 ### <-- Object: ffffc503fa668dc0 Type: (ffffc503f80f4560) File ObjectHeader: ffffc503fa668d90 (new version) HandleCount: 1 PointerCount: 32638 Directory Object: 00000000 Name: \Windows\bootstat.dat {HarddiskVolume4} <snip> 7: kd> dp poi(0xffff9902`8ff53001&0xfffffffffffffffc) ### <-- 0xc == 1100 ffff9902`8c625000 00000000`00000000 00000000`00000000 ffff9902`8c625010 c503f807`55d0fd89 00000000`001fffff ### <-- ffff9902`8c625020 c503f81c`11100001 00000000`001fffff ### <-- ffff9902`8c625030 c503fa66`8d90fefb 00000000`0012019f ### <-- ffff9902`8c625040 c503f809`1070fe85 00000000`001f0001 ffff9902`8c625050 99028c60`89900001 00000000`000f000f ffff9902`8c625060 99028c63`1510fbf3 00000000`000f000f ffff9902`8c625070 c503f809`9e700001 00000000`001f0003 7: kd> dt _HANDLE_TABLE_ENTRY ffff9902`8c625010 nt!_HANDLE_TABLE_ENTRY +0x000 VolatileLowValue : 0n-4250280912919396983 +0x000 LowValue : 0n-4250280912919396983 +0x000 InfoTable : 0xc503f807`55d0fd89 _HANDLE_TABLE_ENTRY_INFO ### <-- +0x008 HighValue : 0n2097151 +0x008 NextFreeHandleEntry : 0x00000000`001fffff _HANDLE_TABLE_ENTRY +0x008 LeafHandleValue : _EXHANDLE +0x000 RefCountField : 0n-4250280912919396983 +0x000 Unlocked : 0y1 +0x000 RefCnt : 0y0111111011000100 (0x7ec4) +0x000 Attributes : 0y000 +0x000 ObjectPointerBits : 0y11000101000000111111100000000111010101011101 (0xc503f80755d) +0x008 GrantedAccessBits : 0y0000111111111111111111111 (0x1fffff) +0x008 NoRightsUpgrade : 0y0 +0x008 Spare1 : 0y000000 (0) +0x00c Spare2 : 0 7: kd> ? (0xc503f807`55d0fd89>>>10)&fffffffffffffff0 Evaluate expression: -64854139906608 = ffffc503`f80755d0 ### <-- 7: kd> dt _OBJECT_HEADER ffffc503`f80755d0 nt!_OBJECT_HEADER +0x000 PointerCount : 0n180602 +0x008 HandleCount : 0n5 +0x008 NextToFree : 0x00000000`00000005 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : 0x66 'f' +0x019 TraceFlags : 0 '' +0x019 DbgRefTrace : 0y0 +0x019 DbgTracePermanent : 0y0 +0x01a InfoMask : 0x80 '' +0x01b Flags : 0x2 '' +0x01b NewObject : 0y0 +0x01b KernelObject : 0y1 +0x01b KernelOnlyAccess : 0y0 +0x01b ExclusiveObject : 0y0 +0x01b PermanentObject : 0y0 +0x01b DefaultSecurityQuota : 0y0 +0x01b SingleHandleEntry : 0y0 +0x01b DeletedInline : 0y0 +0x01c Reserved : 0x1aff +0x020 ObjectCreateInfo : 0xfffff807`38e4c7c0 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : 0xfffff807`38e4c7c0 Void +0x028 SecurityDescriptor : 0xffff9902`8c60706f Void +0x030 Body : _QUAD 7: kd> !object ffffc503`f80755d0+0x30 ### <-- Object: ffffc503f8075600 Type: (ffffc503f8093220) Process ObjectHeader: ffffc503f80755d0 (new version) HandleCount: 5 PointerCount: 180602 7: kd> dt nt!_EPROCESS ffffc503f8075600 ImageFileName +0x450 ImageFileName : [15] "System" 7: kd> dt _HANDLE_TABLE_ENTRY ffff9902`8c625030 ### <-- nt!_HANDLE_TABLE_ENTRY +0x000 VolatileLowValue : 0n-4250278304938918149 +0x000 LowValue : 0n-4250278304938918149 +0x000 InfoTable : 0xc503fa66`8d90fefb _HANDLE_TABLE_ENTRY_INFO +0x008 HighValue : 0n1180063 +0x008 NextFreeHandleEntry : 0x00000000`0012019f _HANDLE_TABLE_ENTRY +0x008 LeafHandleValue : _EXHANDLE +0x000 RefCountField : 0n-4250278304938918149 +0x000 Unlocked : 0y1 +0x000 RefCnt : 0y0111111101111101 (0x7f7d) +0x000 Attributes : 0y000 +0x000 ObjectPointerBits : 0y11000101000000111111101001100110100011011001 (0xc503fa668d9) +0x008 GrantedAccessBits : 0y0000100100000000110011111 (0x12019f) +0x008 NoRightsUpgrade : 0y0 +0x008 Spare1 : 0y000000 (0) +0x00c Spare2 : 0 7: kd> ? (0xc503fa66`8d90fefb>>>10)&fffffffffffffff0 Evaluate expression: -64854100111984 = ffffc503`fa668d90 7: kd> dt _OBJECT_HEADER ffffc503`fa668d90 nt!_OBJECT_HEADER +0x000 PointerCount : 0n32638 +0x008 HandleCount : 0n1 +0x008 NextToFree : 0x00000000`00000001 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : 0x9d '' +0x019 TraceFlags : 0 '' +0x019 DbgRefTrace : 0y0 +0x019 DbgTracePermanent : 0y0 +0x01a InfoMask : 0x4c 'L' +0x01b Flags : 0x42 'B' +0x01b NewObject : 0y0 +0x01b KernelObject : 0y1 +0x01b KernelOnlyAccess : 0y0 +0x01b ExclusiveObject : 0y0 +0x01b PermanentObject : 0y0 +0x01b DefaultSecurityQuota : 0y0 +0x01b SingleHandleEntry : 0y1 +0x01b DeletedInline : 0y0 +0x01c Reserved : 0x2b4d85 +0x020 ObjectCreateInfo : 0x00000000`00000001 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : 0x00000000`00000001 Void +0x028 SecurityDescriptor : (null) +0x030 Body : _QUAD 7: kd> !object ffffc503`fa668d90+0x30 Object: ffffc503fa668dc0 Type: (ffffc503f80f4560) File ObjectHeader: ffffc503fa668d90 (new version) HandleCount: 1 PointerCount: 32638 Directory Object: 00000000 Name: \Windows\bootstat.dat {HarddiskVolume4} 7: kd> dt nt!_FILE_OBJECT ffffc503fa668dc0 +0x000 Type : 0n5 +0x002 Size : 0n216 +0x008 DeviceObject : 0xffffc503`f8c33b70 _DEVICE_OBJECT +0x010 Vpb : 0xffffc503`f8c9a220 _VPB +0x018 FsContext : 0xffff9902`8cc81b80 Void +0x020 FsContext2 : 0xffff9902`8ccd3640 Void +0x028 SectionObjectPointer : 0xffffc503`f8e86c08 _SECTION_OBJECT_POINTERS +0x030 PrivateCacheMap : 0xffffc503`f8e54c98 Void +0x038 FinalStatus : 0n0 +0x040 RelatedFileObject : (null) +0x048 LockOperation : 0 '' +0x049 DeletePending : 0 '' +0x04a ReadAccess : 0x1 '' +0x04b WriteAccess : 0x1 '' +0x04c DeleteAccess : 0 '' +0x04d SharedRead : 0x1 '' +0x04e SharedWrite : 0 '' +0x04f SharedDelete : 0 '' +0x050 Flags : 0x40042 +0x058 FileName : _UNICODE_STRING "\Windows\bootstat.dat" +0x068 CurrentByteOffset : _LARGE_INTEGER 0x33 +0x070 Waiters : 0 +0x074 Busy : 0 +0x078 LastLock : (null) +0x080 Lock : _KEVENT +0x098 Event : _KEVENT +0x0b0 CompletionContext : (null) +0x0b8 IrpListLock : 0 +0x0c0 IrpList : _LIST_ENTRY [ 0xffffc503`fa668e80 - 0xffffc503`fa668e80 ] +0x0d0 FileObjectExtension : (null) 7: kd> !fileobj ffffc503fa668dc0 \Windows\bootstat.dat Device Object: 0xffffc503f8c33b70 \Driver\volmgr Vpb: 0xffffc503f8c9a220 Event signalled Access: Read Write SharedRead Flags: 0x40042 Synchronous IO Cache Supported Handle Created FsContext: 0xffff99028cc81b80 FsContext2: 0xffff99028ccd3640 Private Cache Map: 0xffffc503f8e54c98 CurrentByteOffset: 33 Cache Data: Section Object Pointers: ffffc503f8e86c08 Shared Cache Map: ffffc503f8e54b20 File Offset: 33 in VACB number 0 Vacb: ffffc503f825d180 Your data is at: ffffb30269780033 |
Object Retention
Object Manager는 Reference Counting 이라는 개념을 이용하여, Object를 얼마나 많은 Client가 사용하고 있는지를 관리하여, 그 값이 0이 되었을 때 Object Manager가 Object를 정리할 수 있게 됩니다.
이 값은 Object Header에 PointerCount와 HandleCount field로 제공됩니다.
Object에 대한 접근 방법은 두 가지가 있는데, 하나는 Object의 Pointer(Memory Address)를 이용하는 방법과 Object의 Handle을 이용하는 방법이 있습니다.
첫 번째 방법을 PointerCount로 관리하고 두 번째를 HandleCount로 관리합니다.
또한, Object에 대한 모든 Reference는(방법에 상관없이) Object Manager가 Pointer Reference로 관리하기 때문에 PointerCount 값은 아래와 같이 계산될 수 있습니다.
Pointer Count = Handle Count + Actual number of Object References by Pointers
따라서 Handle Count가 0이 되었지만 Kernel Mode에서 해당 Object를 참조하고 있다면 Pointer Count는 0이 되지 않는 경우가 발생할 수 있습니다.
7: kd> dt nt!_OBJECT_HEADER +0x000 PointerCount : Int8B ### <-- +0x008 HandleCount : Int8B ### <-- +0x008 NextToFree : Ptr64 Void +0x010 Lock : _EX_PUSH_LOCK +0x018 TypeIndex : UChar +0x019 TraceFlags : UChar +0x019 DbgRefTrace : Pos 0, 1 Bit +0x019 DbgTracePermanent : Pos 1, 1 Bit +0x01a InfoMask : UChar +0x01b Flags : UChar +0x01b NewObject : Pos 0, 1 Bit +0x01b KernelObject : Pos 1, 1 Bit +0x01b KernelOnlyAccess : Pos 2, 1 Bit +0x01b ExclusiveObject : Pos 3, 1 Bit +0x01b PermanentObject : Pos 4, 1 Bit +0x01b DefaultSecurityQuota : Pos 5, 1 Bit +0x01b SingleHandleEntry : Pos 6, 1 Bit +0x01b DeletedInline : Pos 7, 1 Bit +0x01c Reserved : Uint4B +0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION +0x020 QuotaBlockCharged : Ptr64 Void +0x028 SecurityDescriptor : Ptr64 Void +0x030 Body : _QUAD kd> !object 8b407c30 Object: 8b407c30 Type: (87e8a0a8) Directory ObjectHeader: 8b407c18 (old version) HandleCount: 0 PointerCount: 31 ### <-- Directory Object: 8b407928 Name: ObjectTypes |
Handle Tracing
이러한 Handle을 Windbg를 통해 Open/Close 과정을 Tracing 할 수 있습니다.
Windbg > File > Attach to a Process 를 선택한 후, 내가 Tracing 하고자 하는 프로세스를 선택합니다. 아래 예제에서는 테스트로 notepad.exe를 선택하였습니다.
Windbg에서 제공하는 "!htrace" 를 통해서 Handle이 Open되고 Close 되는 과정을 살펴볼 수 있습니다.
!htrace
0:030> .sympath c:\sym;srv*c:\sym\websym*https://msdl.microsoft.com/download/symbols Symbol search path is: c:\sym;srv*c:\sym\websym*https://msdl.microsoft.com/download/symbols Expanded Symbol search path is: c:\sym;srv*c:\sym\websym*https://msdl.microsoft.com/download/symbols ************* Path validation summary ************** Response Time (ms) Location OK c:\sym Deferred srv*c:\sym\websym*https://msdl.microsoft.com/download/symbols 0:030> !htrace -h !htrace [handle [max_traces]] !htrace -enable [max_traces] !htrace -disable !htrace -snapshot !htrace -diff 0:030> !htrace -enable ### <-- Handle tracing enabled. Handle tracing information snapshot successfully taken. 0:030> g ### <-- (3fb0.996c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00007ffa`f8f27790 cc int 3 0:031> !htrace ### <-- -------------------------------------- Handle = 0x0000000000002180 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf64c1534: win32u!NtUserPostMessage+0x0000000000000014 0x00007ffaf7917164: USER32!PostMessageW+0x0000000000000054 0x00007ffaf8b4dfbf: combase!CComApartment::ClassicSTAPostMessage+0x00000000000000cb 0x00007ffaf8b4dd1f: combase!OXIDEntry::PostCall+0x0000000000000167 0x00007ffaf8b1b7c0: combase!ThreadInvokeWorker+0x0000000000001100 0x00007ffaf8b16681: combase!ThreadInvoke+0x0000000000000161 0x00007ffaf88169e2: RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000022 -------------------------------------- Handle = 0x0000000000002174 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf64c1534: win32u!NtUserPostMessage+0x0000000000000014 0x00007ffaf7917164: USER32!PostMessageW+0x0000000000000054 0x00007ffaf8b4dfbf: combase!CComApartment::ClassicSTAPostMessage+0x00000000000000cb 0x00007ffaf8b4dd1f: combase!OXIDEntry::PostCall+0x0000000000000167 -------------------------------------- Handle = 0x000000000000218c - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf8f24304: ntdll!NtDuplicateObject+0x0000000000000014 0x00007ffaf66ffa5c: KERNELBASE!DuplicateHandle+0x000000000000004c 0x00007ffaf87d1b13: RPCRT4!THREAD::THREAD+0x0000000000000087 0x00007ffaf87e75e4: RPCRT4!LrpcIoComplete+0x0000000000000164 0x00007ffaf8ea2160: ntdll!TppAlpcpExecuteCallback+0x0000000000000280 0x00007ffaf8e96e48: ntdll!TppWorkerThread+0x0000000000000448 0x00007ffaf77e55a0: KERNEL32!BaseThreadInitThunk+0x0000000000000010 0x00007ffaf8e8485b: ntdll!RtlUserThreadStart+0x000000000000002b -------------------------------------- Handle = 0x0000000000001638 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf8f24484: ntdll!NtCreateEvent+0x0000000000000014 0x00007ffaf66d3e52: KERNELBASE!CreateEventW+0x0000000000000092 0x00007ffaf87d1c9d: RPCRT4!EVENT::EVENT+0x000000000000002d 0x00007ffaf87d1ab6: RPCRT4!THREAD::THREAD+0x000000000000002a 0x00007ffaf87e75e4: RPCRT4!LrpcIoComplete+0x0000000000000164 0x00007ffaf8ea2160: ntdll!TppAlpcpExecuteCallback+0x0000000000000280 0x00007ffaf8e96e48: ntdll!TppWorkerThread+0x0000000000000448 0x00007ffaf77e55a0: KERNEL32!BaseThreadInitThunk+0x0000000000000010 0x00007ffaf8e8485b: ntdll!RtlUserThreadStart+0x000000000000002b -------------------------------------- Handle = 0x0000000000001638 - CLOSE ### <-- Thread ID = 0x00000000000029d0, Process ID = 0x0000000000003fb0 0x00007ffaf8f23d64: ntdll!NtClose+0x0000000000000014 0x00007ffaf87d872a: RPCRT4!LRPC_CASSOCIATION::~LRPC_CASSOCIATION+0x0000000000000072 0x00007ffaf87d8694: RPCRT4!LRPC_CASSOCIATION::`vector deleting destructor'+0x0000000000000014 0x00007ffaf87c6e69: RPCRT4!LRPC_CASSOCIATION::RemoveAssociationDictionaryReference+0x0000000000000051 0x00007ffaf87c6da0: RPCRT4!LRPC_CASSOCIATION::LrpcDeleteLingeringAssociations+0x00000000000000f0 0x00007ffaf87c6aee: RPCRT4!PerformGarbageCollection+0x000000000000009e 0x00007ffaf8ea03e3: ntdll!TppTimerpExecuteCallback+0x00000000000000b3 0x00007ffaf8e97086: ntdll!TppWorkerThread+0x0000000000000686 0x00007ffaf77e55a0: KERNEL32!BaseThreadInitThunk+0x0000000000000010 0x00007ffaf8e8485b: ntdll!RtlUserThreadStart+0x000000000000002b -------------------------------------- Parsed 0x5 stack traces. Dumped 0x5 stack traces. 0:031> !htrace -diff ### <-- Handle tracing information snapshot successfully taken. 0x5 new stack traces since the previous snapshot. Ignoring handles that were already closed... Outstanding handles opened since the previous snapshot: -------------------------------------- Handle = 0x0000000000002180 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf64c1534: win32u!NtUserPostMessage+0x0000000000000014 0x00007ffaf7917164: USER32!PostMessageW+0x0000000000000054 0x00007ffaf8b4dfbf: combase!CComApartment::ClassicSTAPostMessage+0x00000000000000cb 0x00007ffaf8b4dd1f: combase!OXIDEntry::PostCall+0x0000000000000167 0x00007ffaf8b1b7c0: combase!ThreadInvokeWorker+0x0000000000001100 0x00007ffaf8b16681: combase!ThreadInvoke+0x0000000000000161 0x00007ffaf88169e2: RPCRT4!DispatchToStubInCNoAvrf+0x0000000000000022 -------------------------------------- Handle = 0x0000000000002174 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf64c1534: win32u!NtUserPostMessage+0x0000000000000014 0x00007ffaf7917164: USER32!PostMessageW+0x0000000000000054 0x00007ffaf8b4dfbf: combase!CComApartment::ClassicSTAPostMessage+0x00000000000000cb 0x00007ffaf8b4dd1f: combase!OXIDEntry::PostCall+0x0000000000000167 -------------------------------------- Handle = 0x000000000000218c - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf8f24304: ntdll!NtDuplicateObject+0x0000000000000014 0x00007ffaf66ffa5c: KERNELBASE!DuplicateHandle+0x000000000000004c 0x00007ffaf87d1b13: RPCRT4!THREAD::THREAD+0x0000000000000087 0x00007ffaf87e75e4: RPCRT4!LrpcIoComplete+0x0000000000000164 0x00007ffaf8ea2160: ntdll!TppAlpcpExecuteCallback+0x0000000000000280 0x00007ffaf8e96e48: ntdll!TppWorkerThread+0x0000000000000448 0x00007ffaf77e55a0: KERNEL32!BaseThreadInitThunk+0x0000000000000010 0x00007ffaf8e8485b: ntdll!RtlUserThreadStart+0x000000000000002b -------------------------------------- Handle = 0x0000000000001638 - OPEN ### <-- Thread ID = 0x000000000000b430, Process ID = 0x0000000000003fb0 0x00007ffaf8f24484: ntdll!NtCreateEvent+0x0000000000000014 0x00007ffaf66d3e52: KERNELBASE!CreateEventW+0x0000000000000092 0x00007ffaf87d1c9d: RPCRT4!EVENT::EVENT+0x000000000000002d 0x00007ffaf87d1ab6: RPCRT4!THREAD::THREAD+0x000000000000002a 0x00007ffaf87e75e4: RPCRT4!LrpcIoComplete+0x0000000000000164 0x00007ffaf8ea2160: ntdll!TppAlpcpExecuteCallback+0x0000000000000280 0x00007ffaf8e96e48: ntdll!TppWorkerThread+0x0000000000000448 0x00007ffaf77e55a0: KERNEL32!BaseThreadInitThunk+0x0000000000000010 0x00007ffaf8e8485b: ntdll!RtlUserThreadStart+0x000000000000002b -------------------------------------- Displayed 0x4 stack traces for outstanding handles opened since the previous snapshot. |
Object Tracking
위에서 살펴본 Handle Tracing을 통해 Handle의 Open/Close 과정을 살펴볼 수 있지만, Obejct의 Pointer Reference는 Tracking 할 수 없습니다.
만약 gflags.exe 도구를 이용하여, Object Tracing을 enable 하면 Dump에서 "!obtrace" 명령어로 Object Tracing 정보를 추출할 수 있습니다.
문제가 되는 프로세스가 실행되는 시스템에서 C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags.exe를 실행하고 설정을 합니다.
아래 예제는 notepad.exe 프로세스에 대해서 Event Object를 Tracing 하기 위한 설정이며, 설정 후 재부팅을 진행합니다.
재부팅 한 후에 notepad.exe 를 실행하고 Debugger에서 Break로 멈춘 후 "!obtrace" 명령을 이용하면 Reference/Dereference 과정을 살펴볼 수 있습니다.
!obtrace
1: kd> !process 0 0 notepad.exe PROCESS ffffbd862e490080 SessionId: 2 Cid: 17d4 Peb: fc1b228000 ParentCid: 1298 DirBase: 13f7e9000 ObjectTable: ffff8002d81cbb40 HandleCount: 507. Image: notepad.exe 1: kd> !handle 0 f ffffbd862e490080 PROCESS ffffbd862e490080 SessionId: 2 Cid: 17d4 Peb: fc1b228000 ParentCid: 1298 DirBase: 13f7e9000 ObjectTable: ffff8002d81cbb40 HandleCount: 507. Image: notepad.exe Handle table at ffff8002d81cbb40 with 507 entries in use 0004: Object: ffffbd862e42afe0 GrantedAccess: 001f0003 (Protected) (Inherit) Entry: ffff8002d85ff010 Object: ffffbd862e42afe0 Type: (ffffbd86294ff820) Event ### <-- ObjectHeader: ffffbd862e42afb0 (new version) HandleCount: 1 PointerCount: 32768 <snip> 1: kd> !obtrace ffffbd862e42afe0 ### <-- Object: ffffbd862e42afe0 Image: notepad.exe Sequence (+/-) Tag Stack -------- ----- ---- --------------------------------------------------- 1 +1 Dflt nt!ObCreateObjectEx+15421a nt!NtCreateEvent+98 nt!KiSystemServiceCopyEnd+25 2 +1 Dflt nt!ObReferenceObjectExWithTag+1ac262 nt!ObpCreateHandle+88d nt!ObInsertObjectEx+109 nt!NtCreateEvent+d9 nt!KiSystemServiceCopyEnd+25 3 -1 Dflt nt!ObfDereferenceObject+1322ab nt!ObInsertObjectEx+149 nt!NtCreateEvent+d9 nt!KiSystemServiceCopyEnd+25 5c +1 Dflt nt!ObpReferenceObjectByHandleWithTag+14ecf7 nt!ObReferenceObjectByHandle+2e nt!NtSetEvent+77 nt!KiSystemServiceCopyEnd+25 5d -1 Dflt nt!ObfDereferenceObject+1322ab nt!NtSetEvent+9f nt!KiSystemServiceCopyEnd+25 -------- ----- --------------------------------------------------- References: 3, Dereferences 2 Tag: Dflt References: 3 Dereferences: 2 Over reference by: 1 |
Zombie Process와 Thread
Handle Count도 0으로 표시되고, Object Table의 주소도 없고, Process 하위에 Thread도 없는 상황에서 Process Object가 남아 있는 경우가 있습니다.
이러한 경우에 해당 Process를 Zombie Process라고 합니다.
아래는 Zombie Process의 예제입니다. 이러한 경우에는 남아있는 Process Object의 Handle을 누가 소유하고 있는지 확인해야 합니다.
Zombie Process
kd> !process 0 7 notepad.exe PROCESS 89e34030 SessionId: 2 Cid: 00b4 Peb: 7ffdb000 ParentCid: 1244 DirBase: 5e7da540 ObjectTable: 00000000 HandleCount: 0. ### <-- Image: notepad.exe VadRoot 00000000 Vads 0 Clone 0 Private 1. Modified 2. Locked 0. DeviceMap 9f72f6a8 Token 9fce4028 ElapsedTime 00:00:10.525 UserTime 00:00:00.000 KernelTime 00:00:00.030 QuotaPoolUsage[PagedPool] 0 QuotaPoolUsage[NonPagedPool] 0 Working Set Sizes (now,min,max) (6, 50, 345) (24KB, 200KB, 1380KB) PeakWorkingSetSize 872 VirtualSize 33 Mb PeakVirtualSize 46 Mb PageFaultCount 912 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 0 No active threads ### <-- kd> !object 89e34030 Object: 89e34030 Type: (8499d890) Process ObjectHeader: 89e34018 (new version) HandleCount: 1 PointerCount: 9 ### <-- 1: kd> !object ffffbd862e490080 Object: ffffbd862e490080 Type: (ffffbd86294ed900) Process ### <-- ObjectHeader: ffffbd862e490050 (new version) HandleCount: 7 PointerCount: 228192 1: kd> !findhandle ffffbd862e490080 [ffffbd8629484200 System] 25b4: Entry ffff8002d81526d0 Granted Access 102a (Protected) (Audit) 25c0: Entry ffff8002d8152700 Granted Access 1fffff (Protected) (Audit) 25c4: Entry ffff8002d8152710 Granted Access 102a (Protected) (Audit) [ffffbd862b866080 lsass.exe] 142c: Entry ffff8002d85120b0 Granted Access 1478 (Protected) (Audit) [ffffbd862ca04080 svchost.exe] fd4: Entry ffff8002d7c8cf50 Granted Access 100000 (Protected) (Audit) [ffffbd862cc1e240 svchost.exe] 2bc: Entry ffff8002d6733af0 Granted Access 1478 (Protected) (Audit) [ffffbd862ccdc080 csrss.exe] 2fc: Entry ffff8002d69f4bf0 Granted Access 1fffff (Protected) (Audit) ### <-- 1: kd> !handle 0 3 ffffbd862ccdc080 Process Searching for handles of type Process PROCESS ffffbd862ccdc080 SessionId: 2 Cid: 0cfc Peb: dfdee62000 ParentCid: 0d88 DirBase: 10f7fe000 ObjectTable: ffff8002d7359b40 HandleCount: 295. Image: csrss.exe Handle table at ffff8002d7359b40 with 295 entries in use 02fc: Object: ffffbd862e490080 GrantedAccess: 001fffff (Protected) (Audit) Entry: ffff8002d69f4bf0 ### <-- Object: ffffbd862e490080 Type: (ffffbd86294ed900) Process ObjectHeader: ffffbd862e490050 (new version) HandleCount: 7 PointerCount: 228192 1: kd> dt nt!_EPROCESS ffffbd862e490080 ImageFileName +0x450 ImageFileName : [15] "notepad.exe" ### <-- |