You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
824 lines
24 KiB
824 lines
24 KiB
/*++
|
|
|
|
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;
|
|
}
|