|
|
/*++
Copyright (c) 1992-2000 Microsoft Corporation
Module Name:
handle.c
Abstract:
WinDbg Extension Api
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
BOOL DumpHandles ( IN ULONG64 RealProcessBase, IN ULONG64 HandleToDump, IN ULONG64 pObjectType, IN ULONG Flags );
BOOLEAN DumpHandle( IN ULONG64 pHandleTableEntry, IN ULONG64 Handle, IN ULONG64 pObjectType, IN ULONG Flags );
DECLARE_API( handle )
/*++
Routine Description:
Dump the active handles
Arguments:
args - [handle-to-dump [flags [process-to-dump [TypeName]]]]
if handle-to-dump is 0 dump all, otherwise it's the handle to dump.
if process-to-dump is 0 dump all. if nonzero, it can be either an EPROCESS pointer or a PID.
flags bit meanings:
0x2 Dump the object 0x4 Dump free entries 0x10 Dump kernel handle table 0x20 Dump psp cid handle table
Examples:
!handle 0 3 ffffffff Section
means dump all Section handles (using verbosity flags=3) for the current process.
-----
!handle 0 3 ffffffff
means dump all handles (using verbosity flags=3) for the current process.
-----
!handle 0 3 0
means dump all handles (using verbosity flags=3) for all processes.
-----
!handle 0 10 ffffffff Section
means dump Section entries in the kernel handle table (using verbosity flags=3).
Return Value:
None
--*/
{
ULONG64 ProcessToDump; ULONG64 HandleToDump; ULONG Flags; ULONG Result; ULONG nArgs; ULONG64 Next = 0; ULONG64 ProcessHead = 1; ULONG64 Process; char TypeName[ MAX_PATH ]; ULONG64 pObjectType; ULONG64 UserProbeAddress; ULONG ActiveProcessLinksOffset=0; ULONG64 UniqueProcessId=0, ActiveProcessLinks_Flink=0; FIELD_INFO procLink[] = { {"ActiveProcessLinks", "", 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL}, {"UniqueProcessId", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &UniqueProcessId}, {"ActiveProcessLinks.Flink","", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ActiveProcessLinks_Flink}, }; SYM_DUMP_PARAM EProc = { sizeof (SYM_DUMP_PARAM), "nt!_EPROCESS", DBG_DUMP_NO_PRINT, 0, NULL, NULL, NULL, 3, &procLink[0], }; ULONG dwProcessor=0; CHAR Addr1[100], Addr2[100];
GetCurrentProcessor(Client, &dwProcessor, NULL); HandleToDump = 0; Flags = 0x3; //by default dump bodies and objects for in use entries
ProcessToDump = -1; UserProbeAddress = GetNtDebuggerDataValue(MmUserProbeAddress);
dprintf("processor number %d\n", dwProcessor);
Addr1[0] = 0; Addr2[0] = 0; nArgs = 0; if (GetExpressionEx(args, &HandleToDump, &args)) { ULONG64 tmp; ++nArgs; if (GetExpressionEx(args, &tmp, &args) && args) { ULONG i; Flags = (ULONG) tmp; ++nArgs; while (*args == ' ') { ++args; }
// Do not use GetExpressionEx since it will search for TypeName
// in symbols
i=0; while (*args && (*args != ' ')) { Addr1[i++] = *args++; } Addr1[i] = 0; if (Addr1[0]) { ProcessToDump = GetExpression(Addr1); ++nArgs; while (*args == ' ') { ++args; } if (StringCchCopy(TypeName, sizeof(TypeName), args) != S_OK) { TypeName[0] = 0; }
if (TypeName[0]) ++nArgs; } } }
pObjectType = 0; if (nArgs > 3 && FetchObjectManagerVariables(FALSE)) { pObjectType = FindObjectType( TypeName ); }
if (ProcessToDump == 0) { dprintf("**** NT ACTIVE PROCESS HANDLE DUMP ****\n"); if (Flags == 0xFFFFFFFF) { Flags = 1; } } else if (ProcessToDump == -1) { GetCurrentProcessAddr( dwProcessor, 0, &ProcessToDump ); if (ProcessToDump == 0) { dprintf("Unable to get current process pointer.\n"); return E_INVALIDARG; } }
if (ProcessToDump < UserProbeAddress) {
//
// If a process id is specified, then search the active process list
// for the specified process id.
//
ULONG64 List_Flink=0, List_Blink=0; FIELD_INFO listFields[] = { {"Flink", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &List_Flink}, {"Blink", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &List_Blink}, }; SYM_DUMP_PARAM Lst = { sizeof (SYM_DUMP_PARAM), "nt!_LIST_ENTRY", DBG_DUMP_NO_PRINT, 0, NULL, NULL, NULL, 2, &listFields[0] };
ProcessHead = GetNtDebuggerData( PsActiveProcessHead ); if ( !ProcessHead ) { dprintf("Unable to get value of PsActiveProcessHead\n"); return E_INVALIDARG; }
Lst.addr = ProcessHead; if (Ioctl(IG_DUMP_SYMBOL_INFO, &Lst, Lst.size)) { dprintf("Unable to find _LIST_ENTRY type, ProcessHead: %08I64x\n", ProcessHead); return E_INVALIDARG; }
if (ProcessToDump != 0) { dprintf("Searching for Process with Cid == %I64lx\n", ProcessToDump); }
Next = List_Flink;
if (Next == 0) { dprintf("PsActiveProcessHead is NULL!\n"); return E_INVALIDARG; }
}
if (GetFieldOffset("nt!_EPROCESS", "ActiveProcessLinks", &ActiveProcessLinksOffset)) { dprintf("Unable to find _EPROCESS type\n"); return E_INVALIDARG; }
if (pObjectType != 0) { dprintf("Searching for handles of type %s\n", TypeName); }
while (Next != ProcessHead) {
if ( CheckControlC() ) { return E_INVALIDARG; }
if (Next != 0) { Process = Next - ActiveProcessLinksOffset;
} else { Process = ProcessToDump; }
EProc.addr = Process; if (Ioctl(IG_DUMP_SYMBOL_INFO, &EProc, EProc.size)) { dprintf("_EPROCESS Ioctl failed at %p\n",Process); return E_INVALIDARG; }
if (ProcessToDump == 0 || ProcessToDump < UserProbeAddress && ProcessToDump == UniqueProcessId || ProcessToDump >= UserProbeAddress && ProcessToDump == Process ) { if (DumpProcess ("", Process, 0, NULL)) { if (!DumpHandles ( Process, HandleToDump, pObjectType, Flags)) { break; }
} else { break; } }
if (Next == 0) { break; } Next = ActiveProcessLinks_Flink; } return S_OK; }
#define KERNEL_HANDLE_MASK 0x80000000
//+---------------------------------------------------------------------------
//
// Function: DumpHandles
//
// Synopsis: Dump the handle table for the given process
//
// Arguments: [RealProcessBase] -- base address of the process
// [HandleToDump] -- handle to look for - if 0 dump all
// [pObjectType] -- object type to look for
// [Flags] -- flags passed thru to DumpHandle
// if 0x10 is set dump the kernel handle table
//
// Returns: TRUE if successful
//
// History: 1-12-1998 benl Created
//
// Notes: Each segment of table has 0xFF or 8 bits worth of entries
// the handle number's lowest 2 bit are application defined
// so the indexes are gotten from the 3 8 bits ranges after
// the first 2 bits
//
//----------------------------------------------------------------------------
BOOL DumpHandles ( IN ULONG64 RealProcessBase, IN ULONG64 HandleToDump, IN ULONG64 pObjectType, IN ULONG Flags )
{ ULONG64 ObjectTable=0; ULONG ulRead; ULONG64 ulTopLevel; ULONG64 ulMidLevel; ULONG ulHandleNum = ((ULONG)(HandleToDump) >> 2); ULONG iIndex1; ULONG iIndex2; ULONG iIndex3; ULONG ptrSize, hTableEntrySize, hTableEntryPointerSize; ULONG64 tablePtr; ULONG64 HandleCount = 0; ULONG64 Table = 0; ULONG64 UniqueProcessId = 0; BOOL KernelHandle = FALSE, CidHandle = FALSE;
ULONG LowLevelCounts = 256; ULONG MidLevelCounts = 256; ULONG HighLevelCounts = 256; ULONG TableLevel = 2; BOOLEAN NewStyle = FALSE;
//
// Typeinfo parsing structures
//
FIELD_INFO procFields[] = { {"ObjectTable", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ObjectTable}, };
FIELD_INFO handleTblFields[] = { {"HandleCount", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &HandleCount}, {"UniqueProcessId", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &UniqueProcessId}, };
SYM_DUMP_PARAM handleSym = { sizeof (SYM_DUMP_PARAM), "nt!_EPROCESS", DBG_DUMP_NO_PRINT, RealProcessBase, NULL, NULL, NULL, 1, &procFields[0] };
//
// Check for kernel handle table
//
if ((Flags & 0x10) || ((ulHandleNum != 0) && (((ULONG_PTR)HandleToDump & KERNEL_HANDLE_MASK) == KERNEL_HANDLE_MASK))) {
ULONG64 KernelTableAddr;
KernelHandle = TRUE;
KernelTableAddr = GetExpression( "nt!ObpKernelHandleTable" ); if (!KernelTableAddr) { dprintf( "Unable to find ObpKernelHandleTable\n" ); return FALSE; }
if (!ReadPointer(KernelTableAddr, &ObjectTable)) { dprintf( "Unable to find ObpKernelHandleTable at %p\n", KernelTableAddr ); return FALSE; }
} else if (Flags & 0x20) {
CidHandle = TRUE; ObjectTable = GetNtDebuggerDataValue(PspCidTable); if (!ObjectTable) { dprintf( "Unable to find PspCidTable\n" ); return FALSE; }
} else {
if (Ioctl(IG_DUMP_SYMBOL_INFO, &handleSym, handleSym.size)) { dprintf("Unable to get ObjectTable address from process %I64x\n", RealProcessBase); return FALSE; } }
ptrSize = DBG_PTR_SIZE; if (!ptrSize) { dprintf("Cannot get pointer size\n"); return FALSE; }
handleSym.sName = "nt!_HANDLE_TABLE"; handleSym.addr = ObjectTable; handleSym.nFields = sizeof (handleTblFields) / sizeof (FIELD_INFO); handleSym.Fields = &handleTblFields[0];
if (!ObjectTable || Ioctl(IG_DUMP_SYMBOL_INFO, &handleSym, handleSym.size)) { dprintf("%08p: Unable to read handle table\n", ObjectTable); return FALSE; }
if (GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "TableCode", Table)) { // Could be older build
} else if (!IsPtr64()) { //
// GetFieldValue doesn't sign extend it since TableCode is defined as dword (not pointer)
//
Table = (ULONG64) (LONG64) (LONG) Table; }
hTableEntrySize = GetTypeSize("nt!_HANDLE_TABLE_ENTRY"); hTableEntryPointerSize = IsPtr64() ? 8 : 4;
if (hTableEntrySize == 0) { dprintf("Cannot get size of nt!_HANDLE_TABLE_ENTRY \n"); return FALSE; }
if (Table != 0) {
NewStyle = TRUE; LowLevelCounts = PageSize / hTableEntrySize; MidLevelCounts = PageSize / hTableEntryPointerSize; HighLevelCounts = (1<<24) / (LowLevelCounts * MidLevelCounts);
TableLevel = (ULONG)(Table & 3); Table &= ~((ULONG64)3);
} else if (GetFieldValue(ObjectTable, "nt!_HANDLE_TABLE", "Table", Table) ) {
dprintf("%08p: Unable to read Table field from _HANDLE_TABLE\n", ObjectTable); return FALSE; }
if (KernelHandle) { dprintf( "Kernel " ); } else if (CidHandle) { dprintf( "Cid " ); }
dprintf("%s version of handle table at %p with %I64d %s in use\n", (NewStyle ? "New" : "Old"), Table, HandleCount, ((HandleCount == 1) ? "Entry" : "Entries"));
if (ulHandleNum != 0) {
if (NewStyle) {
ULONG64 CrtTable = Table; ULONG64 CrtHandleNum = ulHandleNum;
if (TableLevel == 2) {
ULONG64 HighLevelIndex = ulHandleNum / (LowLevelCounts * MidLevelCounts);
CrtTable = CrtTable + HighLevelIndex * ptrSize;
if (!ReadPointer(CrtTable, &CrtTable)) { dprintf("%08p: Unable to read handle table level 3\n", CrtTable ); return FALSE; }
CrtHandleNum = ulHandleNum - HighLevelIndex * (LowLevelCounts * MidLevelCounts); }
if (TableLevel == 1) {
CrtTable = CrtTable + (CrtHandleNum / LowLevelCounts) * ptrSize;
if (!ReadPointer(CrtTable, &CrtTable)) { dprintf("%08p: Unable to read handle table level 2\n", CrtTable ); return FALSE; }
CrtHandleNum = CrtHandleNum % LowLevelCounts; }
tablePtr = CrtTable + CrtHandleNum * hTableEntrySize;
} else {
//
// Read the 3 level table stage by stage to find the specific entry
//
tablePtr = Table + ((ulHandleNum & 0x00FF0000) >> 16) * ptrSize; ulTopLevel = 0; if (!ReadPointer(tablePtr, &ulTopLevel)) { dprintf("%08p: Unable to read handle table level 3\n", tablePtr ); return FALSE; }
if (!ulTopLevel) { dprintf("Invalid handle: 0x%x\n", ulHandleNum); return FALSE; }
tablePtr = ulTopLevel + ((ulHandleNum & 0x0000FF00) >> 8) * ptrSize; ulMidLevel = 0; if (!ReadPointer(tablePtr, &ulMidLevel)) { dprintf("%08p: Unable to read handle table level 2\n", tablePtr); return FALSE; }
if (!ulMidLevel) { dprintf("Invalid handle: 0x%x\n", ulHandleNum); return FALSE; }
//
// Read the specific entry req. and dump it
//
tablePtr = (ulMidLevel + (0x000000ff & ulHandleNum) * hTableEntrySize); }
DumpHandle(tablePtr, HandleToDump, pObjectType, Flags);
} else {
//
// loop over all the possible parts of the table
//
for (iIndex1=0; iIndex1 < HighLevelCounts; iIndex1++) {
//
// check for ctrl-c to abort
//
if (CheckControlC()) { return FALSE; }
if (TableLevel < 2) {
tablePtr = Table; ulTopLevel = tablePtr;
//
// We break the loop second time if we don't have the table level 2
//
if (iIndex1 > 0) { break; }
} else {
//
// Read the 3 level table stage by stage to find the specific entry
//
tablePtr = Table + iIndex1 * ptrSize; ulTopLevel = 0; if (!ReadPointer(tablePtr, &ulTopLevel)) { dprintf("%08p: Unable to read handle table top level\n", tablePtr); return FALSE; }
if (!ulTopLevel) { continue; } }
for (iIndex2=0; iIndex2 < MidLevelCounts; iIndex2++) {
//
// check for ctrl-c to abort
//
if (CheckControlC()) { return FALSE; }
if (TableLevel < 1) {
tablePtr = Table; ulMidLevel = tablePtr;
//
// We break the loop second time if we don't have the table level 1
//
if (iIndex2 > 0) { break; }
} else {
tablePtr = ulTopLevel + iIndex2 * ptrSize; ulMidLevel = 0; if (!ReadPointer(tablePtr, &ulMidLevel)) { dprintf("%08p: Unable to read handle table middle level\n", tablePtr); return FALSE; }
if (!ulMidLevel) { continue; } }
//
// now read all the entries in this segment of the table and dump them
// Note: Handle Number = 6 unused bits + 8 bits high + 8 bits mid +
// 8 bits low + 2 bits user defined
//
for (iIndex3 = 0; iIndex3 < LowLevelCounts; iIndex3++) {
//
// check for ctrl-c to abort
//
if (CheckControlC()) { return FALSE; }
DumpHandle(ulMidLevel + iIndex3*hTableEntrySize, (iIndex3 + (iIndex2 + iIndex1 * MidLevelCounts) * LowLevelCounts) * 4, pObjectType, Flags);
} } } // end outermost for
} // endif on a specific handle
return TRUE; } // DumpHandles
//+---------------------------------------------------------------------------
//
// Function: DumpHandle
//
// Synopsis: Dump a particular Handle
//
// Arguments: [pHandleTableEntry] -- entry to dump
// [Handle] -- handle number of entry
// [pObjectType] -- only dump if object type matches this
// if NULL dump everything
// [Flags] -- flags if 0x2 also dump the object
// if 0x4 dump free entries
//
// Returns:
//
// History: 1-12-1998 benl Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOLEAN DumpHandle( IN ULONG64 pHandleTableEntry, IN ULONG64 Handle, IN ULONG64 pObjectType, IN ULONG Flags ) { ULONG64 ulObjectHeaderAddr; ULONG Result;
ULONG HandleAttributes; // OBJECT_HEADER ObjectHeader;
ULONG64 ObjectBody; ULONG GrantedAccess=0; ULONG64 Object=0, ObjType=0;
FIELD_INFO hTableEntryFields[] = { {"Object", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &Object}, {"GrantedAccess", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &GrantedAccess}, }; FIELD_INFO ObjHeaderFields[] = { {"Type", "", 0, DBG_DUMP_FIELD_COPY_FIELD_DATA, 0, (PVOID) &ObjType}, {"Body", "", 0, DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL}, };
SYM_DUMP_PARAM ObjSym = { sizeof (SYM_DUMP_PARAM), "nt!_HANDLE_TABLE_ENTRY", DBG_DUMP_NO_PRINT, pHandleTableEntry, NULL, NULL, NULL, sizeof (hTableEntryFields) /sizeof (FIELD_INFO), &hTableEntryFields[0], };
if (Ioctl (IG_DUMP_SYMBOL_INFO, &ObjSym, ObjSym.size)) { dprintf("Unable to get _HANDLE_TABLE_ENTRY : %p\n", pHandleTableEntry); return FALSE; }
if (!(Object)) { //only print if flag is set to 4
if (Flags & 4) { dprintf("%04lx: free handle, Entry address %p, Next Entry %p\n", (ULONG)Handle, pHandleTableEntry, GrantedAccess); } return TRUE; }
if (BuildNo > 2230) { // if (GetExpression( "nt!ObpAccessProtectCloseBit" )) {
//
// we have a new handle table style
//
//actual hdr has the lowest 3 bits cancelled out
//lower 3 bits mark auditing, inheritance and lock
ulObjectHeaderAddr = (Object) & ~(0x7);
//
// Apply the sign extension, if the highest bit is set
//
if ( !IsPtr64() && (Object & 0x80000000)) {
ulObjectHeaderAddr |= 0xFFFFFFFF00000000L; }
} else {
//actual hdr is sign extend value with the lowest 3 bits cancelled out
//top bit marks whether entry is locked
//lower 3 bits mark auditing, inheritance and protection
if (!IsPtr64()) { ulObjectHeaderAddr = ((Object) & ~(0x7)) | 0xFFFFFFFF80000000L; } else { ulObjectHeaderAddr = ((Object) & ~(0x7)) | 0x8000000000000000L; } }
ObjSym.sName = "nt!_OBJECT_HEADER"; ObjSym.addr = ulObjectHeaderAddr; ObjSym.nFields = sizeof (ObjHeaderFields) / sizeof (FIELD_INFO); ObjSym.Fields = &ObjHeaderFields[0]; if (Ioctl ( IG_DUMP_SYMBOL_INFO, &ObjSym, ObjSym.size)) { dprintf("%08p: Unable to read nonpaged object header\n", ulObjectHeaderAddr); return FALSE; }
if (pObjectType != 0 && ObjType != pObjectType) { return TRUE; }
if (Flags & 0x20) { //
// PspCidTable contains pointer to object, not object header
// Compute header address based on object.
//
ObjectBody = ulObjectHeaderAddr; ulObjectHeaderAddr -= ObjHeaderFields[1].address-ulObjectHeaderAddr; } else { ObjectBody = ObjHeaderFields[1].address; }
dprintf("%04I64lx: Object: %08p GrantedAccess: %08lx", Handle, ObjectBody, (GrantedAccess & ~MAXIMUM_ALLOWED));
if (BuildNo > 2230) { // if (GetExpression( "nt!ObpAccessProtectCloseBit" )) {
//
// New handle table style
//
if (((ULONG) Object & 1) == 0) { dprintf(" (Locked)"); }
if (GrantedAccess & MAXIMUM_ALLOWED) { dprintf(" (Protected)"); }
} else {
if (IsPtr64()) { if (Object & 0x8000000000000000L) { dprintf(" (Locked)"); } } else if ((ULONG) Object & 0x80000000) { dprintf(" (Locked)"); }
if (Object & 1) { dprintf(" (Protected)"); } }
if (Object & 2) { dprintf(" (Inherit)"); }
if (Object & 4) { dprintf(" (Audit)"); }
dprintf("\n"); if (Flags & 2) { DumpObject( " ", ObjectBody, Flags ); }
EXPRLastDump = ObjectBody; dprintf("\n"); return TRUE; }
|