mirror of https://github.com/tongzx/nt5src
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.
496 lines
13 KiB
496 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
handle.cpp
|
|
|
|
Abstract:
|
|
|
|
!handle using the debug engine handle query interface.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
char * AccessMask[] = { "Delete", "ReadControl", "WriteDac", "WriteOwner",
|
|
"Synch", "", "", "",
|
|
"Sacl", "MaxAllowed", "", "",
|
|
"GenericAll", "GenericExec", "GenericWrite", "GenericRead"};
|
|
|
|
char * TokenRights[] = {"AssignPrimary", "Duplicate", "Impersonate", "Query",
|
|
"QuerySource", "AdjustPriv", "AdjustGroup", "AdjustDef"};
|
|
|
|
char * KeyRights[] = { "QueryValue", "SetValue", "CreateSubKey", "EnumSubKey",
|
|
"Notify", "CreateLink", "", "" };
|
|
|
|
char * EventRights[] = {"QueryState", "ModifyState" };
|
|
|
|
char * MutantRights[]={ "QueryState" };
|
|
|
|
char * SemaphoreRights[] = { "QueryState", "ModifyState" };
|
|
|
|
char * TimerRights[] = {"QueryState", "ModifyState" };
|
|
|
|
char * ProfileRights[]={"Control"};
|
|
|
|
char * ProcessRights[]={"Terminate", "CreateThread", "", "VMOp",
|
|
"VMRead", "VMWrite", "DupHandle", "CreateProcess",
|
|
"SetQuota", "SetInfo", "QueryInfo", "SetPort" };
|
|
|
|
char * ThreadRights[] ={"Terminate", "Suspend", "Alert", "GetContext",
|
|
"SetContext", "SetInfo", "QueryInfo", "SetToken",
|
|
"Impersonate", "DirectImpersonate" };
|
|
|
|
char * SectionRights[]={"Query", "MapWrite", "MapRead", "MapExecute",
|
|
"Extend"};
|
|
|
|
char * FileRights[] = { "Read/List", "Write/Add", "Append/SubDir/CreatePipe", "ReadEA",
|
|
"WriteEA", "Execute/Traverse", "DelChild", "ReadAttr",
|
|
"WriteAttr"};
|
|
|
|
char * PortRights[] = { "Connect" };
|
|
|
|
char * DirRights[] = { "Query", "Traverse", "Create", "CreateSubdir" };
|
|
|
|
char * SymLinkRights[]={"Query" };
|
|
|
|
char * WinstaRights[]={ "EnumDesktops", "ReadAttr", "Clipboard", "CreateDesktop",
|
|
"WriteAttr", "GlobalAtom", "ExitWindows", "",
|
|
"Enumerate", "ReadScreen" };
|
|
|
|
char * DesktopRights[]={"ReadObjects", "CreateWindow", "CreateMenu", "HookControl",
|
|
"JournalRecord", "JournalPlayback", "Enumerate", "WriteObjects",
|
|
"SwitchDesktop" };
|
|
|
|
char * CompletionRights[] = { "Query", "Modify" };
|
|
|
|
char * ChannelRights[] = { "ReadMessage", "WriteMessage", "Query", "SetInfo" };
|
|
|
|
char * JobRights[] = { "AssignProcess", "SetAttr", "Query", "Terminate", "SetSecAttr" };
|
|
|
|
#define GHI_TYPE 0x00000001
|
|
#define GHI_BASIC 0x00000002
|
|
#define GHI_NAME 0x00000004
|
|
#define GHI_SPECIFIC 0x00000008
|
|
#define GHI_VERBOSE 0x00000010
|
|
#define GHI_NOLOOKUP 0x00000020
|
|
#define GHI_SILENT 0x00000100
|
|
|
|
#define TYPE_NONE 0
|
|
#define TYPE_EVENT 1
|
|
#define TYPE_SECTION 2
|
|
#define TYPE_FILE 3
|
|
#define TYPE_PORT 4
|
|
#define TYPE_DIRECTORY 5
|
|
#define TYPE_LINK 6
|
|
#define TYPE_MUTANT 7
|
|
#define TYPE_WINSTA 8
|
|
#define TYPE_SEM 9
|
|
#define TYPE_KEY 10
|
|
#define TYPE_TOKEN 11
|
|
#define TYPE_PROCESS 12
|
|
#define TYPE_THREAD 13
|
|
#define TYPE_DESKTOP 14
|
|
#define TYPE_COMPLETE 15
|
|
#define TYPE_CHANNEL 16
|
|
#define TYPE_TIMER 17
|
|
#define TYPE_JOB 18
|
|
#define TYPE_WPORT 19
|
|
#define TYPE_MAX 20
|
|
|
|
typedef struct _TYPEINFO
|
|
{
|
|
PSTR Name;
|
|
char * * AccessRights;
|
|
DWORD NumberRights;
|
|
} TYPEINFO, * PTYPEINFO;
|
|
|
|
TYPEINFO g_TypeNames[TYPE_MAX] =
|
|
{
|
|
{ "None", NULL, 0 },
|
|
{ "Event", EventRights, 2 },
|
|
{ "Section", SectionRights, 5 },
|
|
{ "File", FileRights, 9 },
|
|
{ "Port", PortRights, 1 },
|
|
{ "Directory", DirRights, 4 },
|
|
{ "SymbolicLink", SymLinkRights, 1 },
|
|
{ "Mutant", MutantRights, 2 },
|
|
{ "WindowStation", WinstaRights, 10 },
|
|
{ "Semaphore", SemaphoreRights, 2 },
|
|
{ "Key", KeyRights, 6 },
|
|
{ "Token", TokenRights, 8 },
|
|
{ "Process", ProcessRights, 12 },
|
|
{ "Thread", ThreadRights, 10 },
|
|
{ "Desktop", DesktopRights, 10 },
|
|
{ "IoCompletion", CompletionRights, 2 },
|
|
{ "Channel", ChannelRights, 4},
|
|
{ "Timer", TimerRights, 2 },
|
|
{ "Job", JobRights, 5 },
|
|
{ "WaitablePort", PortRights, 1 }
|
|
};
|
|
|
|
void DisplayFlags( DWORD Flags,
|
|
DWORD FlagLimit,
|
|
char *flagset[],
|
|
PSTR Buffer)
|
|
{
|
|
char * offset;
|
|
DWORD mask, test, i;
|
|
DWORD scratch;
|
|
|
|
if (!Flags)
|
|
{
|
|
strcpy(Buffer, "None");
|
|
return;
|
|
}
|
|
|
|
mask = 0;
|
|
offset = Buffer;
|
|
test = 1;
|
|
for (i = 0 ; i < FlagLimit ; i++ )
|
|
{
|
|
if (Flags & test)
|
|
{
|
|
scratch = sprintf(offset, "%s", flagset[i]);
|
|
offset += scratch;
|
|
mask |= test;
|
|
if (Flags & (~mask))
|
|
{
|
|
*offset++ = ',';
|
|
}
|
|
}
|
|
test <<= 1;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
GetObjectTypeIndex(
|
|
LPCSTR TypeName
|
|
)
|
|
{
|
|
DWORD i;
|
|
|
|
for ( i = 1 ; i < TYPE_MAX ; i++ )
|
|
{
|
|
if (_stricmp( g_TypeNames[i].Name, TypeName ) == 0 )
|
|
{
|
|
return( i );
|
|
}
|
|
}
|
|
|
|
return( (DWORD) -1 );
|
|
}
|
|
|
|
DWORD
|
|
GetHandleInfo(
|
|
ULONG64 hThere,
|
|
DWORD Flags,
|
|
DWORD * Type)
|
|
{
|
|
HRESULT Status;
|
|
DWORD SuccessCount = 0;
|
|
DWORD i;
|
|
UCHAR Buffer[1024];
|
|
CHAR szBuf[256];
|
|
|
|
if ( (Flags & GHI_SILENT) == 0)
|
|
{
|
|
dprintf("Handle %p\n", hThere );
|
|
}
|
|
|
|
if (Flags & GHI_TYPE)
|
|
{
|
|
if (g_ExtData->
|
|
ReadHandleData(hThere,
|
|
DEBUG_HANDLE_DATA_TYPE_TYPE_NAME,
|
|
Buffer, sizeof(Buffer), NULL) == S_OK)
|
|
{
|
|
if ((Flags & GHI_SILENT) == 0)
|
|
{
|
|
dprintf(" Type \t%s\n", Buffer);
|
|
}
|
|
for (i = 1; i < TYPE_MAX ; i++)
|
|
{
|
|
if (strcmp((LPSTR)Buffer, g_TypeNames[i].Name) == 0)
|
|
{
|
|
*Type = i;
|
|
break;
|
|
}
|
|
}
|
|
if (i == TYPE_MAX)
|
|
{
|
|
*Type = 0;
|
|
}
|
|
SuccessCount++;
|
|
}
|
|
}
|
|
|
|
if (Flags & GHI_BASIC)
|
|
{
|
|
DEBUG_HANDLE_DATA_BASIC Basic;
|
|
|
|
if (g_ExtData->
|
|
ReadHandleData(hThere,
|
|
DEBUG_HANDLE_DATA_TYPE_BASIC,
|
|
&Basic, sizeof(Basic), NULL) == S_OK)
|
|
{
|
|
dprintf(" Attributes \t%#x\n", Basic.Attributes );
|
|
dprintf(" GrantedAccess\t%#x:\n", Basic.GrantedAccess );
|
|
DisplayFlags( Basic.GrantedAccess >> 16,
|
|
16,
|
|
AccessMask,
|
|
szBuf);
|
|
dprintf(" %s\n", szBuf);
|
|
DisplayFlags( Basic.GrantedAccess & 0xFFFF,
|
|
g_TypeNames[ *Type ].NumberRights,
|
|
g_TypeNames[ *Type ].AccessRights,
|
|
szBuf);
|
|
dprintf(" %s\n", szBuf);
|
|
dprintf(" HandleCount \t%d\n", Basic.HandleCount );
|
|
dprintf(" PointerCount \t%d\n", Basic.PointerCount );
|
|
SuccessCount++;
|
|
}
|
|
else
|
|
{
|
|
dprintf("unable to query object information\n");
|
|
}
|
|
}
|
|
|
|
if ( (Flags & GHI_NAME) &&
|
|
(*Type != TYPE_FILE ) )
|
|
{
|
|
if (g_ExtData->
|
|
ReadHandleData(hThere,
|
|
DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME,
|
|
Buffer, sizeof(Buffer), NULL) == S_OK)
|
|
{
|
|
dprintf(" Name \t%s\n",
|
|
Buffer[0] ? (PSTR)Buffer : "<none>" );
|
|
SuccessCount++;
|
|
}
|
|
else
|
|
{
|
|
dprintf("unable to query object information\n");
|
|
}
|
|
}
|
|
|
|
if ( Flags & GHI_SPECIFIC )
|
|
{
|
|
dprintf(" No object specific information available\n");
|
|
}
|
|
|
|
return( SuccessCount );
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called as an NTSD extension to mimic the !handle
|
|
kd command. This will walk through the debuggee's handle table
|
|
and duplicate the handle into the ntsd process, then call NtQueryobjectInfo
|
|
to find out what it is.
|
|
|
|
Called as:
|
|
|
|
!handle [handle [flags [Type]]]
|
|
|
|
If the handle is 0 or -1, all handles are scanned. If the handle is not
|
|
zero, that particular handle is examined. The flags are as follows
|
|
(corresponding to secexts.c):
|
|
1 - Get type information (default)
|
|
2 - Get basic information
|
|
4 - Get name information
|
|
8 - Get object specific info (where available)
|
|
|
|
If Type is specified, only object of that type are scanned. Type is a
|
|
standard NT type name, e.g. Event, Semaphore, etc. Case sensitive, of
|
|
course.
|
|
|
|
Examples:
|
|
|
|
!handle -- dumps the types of all the handles, and a summary table
|
|
!handle 0 0 -- dumps a summary table of all the open handles
|
|
!handle 0 f -- dumps everything we can find about a handle.
|
|
!handle 0 f Event
|
|
-- dumps everything we can find about open events
|
|
|
|
--*/
|
|
DECLARE_API( handle )
|
|
{
|
|
ULONG64 hThere;
|
|
DWORD Type;
|
|
DWORD Mask;
|
|
DWORD HandleCount;
|
|
DWORD Total;
|
|
DWORD TypeCounts[TYPE_MAX];
|
|
DWORD Handle;
|
|
DWORD Hits;
|
|
DWORD Matches;
|
|
DWORD ObjectType;
|
|
ULONG SessionType;
|
|
ULONG SessionQual;
|
|
|
|
INIT_API();
|
|
|
|
//
|
|
// This particular implementation is only used for
|
|
// dump debug sessions as more information can be
|
|
// retrieved on live sessions via the NtQuery APIs.
|
|
// If this isn't a dump session let the !handle
|
|
// search continue on.
|
|
//
|
|
|
|
if (g_ExtControl == NULL ||
|
|
g_ExtControl->
|
|
GetDebuggeeType(&SessionType, &SessionQual) != S_OK)
|
|
{
|
|
SessionType = DEBUG_CLASS_USER_WINDOWS;
|
|
SessionQual = DEBUG_USER_WINDOWS_PROCESS;
|
|
}
|
|
if (SessionType == DEBUG_CLASS_USER_WINDOWS &&
|
|
SessionQual == DEBUG_USER_WINDOWS_PROCESS)
|
|
{
|
|
ExtRelease();
|
|
return DEBUG_EXTENSION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
Mask = GHI_TYPE;
|
|
hThere = (ULONG64)(LONG_PTR)INVALID_HANDLE_VALUE;
|
|
Type = 0;
|
|
|
|
while (*args == ' ')
|
|
{
|
|
args++;
|
|
}
|
|
|
|
hThere = GetExpression( args );
|
|
|
|
while (*args && (*args != ' ') )
|
|
{
|
|
args++;
|
|
}
|
|
while (*args == ' ')
|
|
{
|
|
args++;
|
|
}
|
|
|
|
if (*args)
|
|
{
|
|
Mask = (DWORD)GetExpression( args );
|
|
}
|
|
|
|
while (*args && (*args != ' ') )
|
|
{
|
|
args++;
|
|
}
|
|
while (*args == ' ')
|
|
{
|
|
args++;
|
|
}
|
|
|
|
if (*args)
|
|
{
|
|
Type = GetObjectTypeIndex( (LPSTR)args );
|
|
if (Type == (DWORD) -1)
|
|
{
|
|
dprintf("Unknown type '%s'\n", args );
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if they specified 0, they just want the summary. Make sure nothing
|
|
// sneaks out.
|
|
//
|
|
|
|
if ( Mask == 0 )
|
|
{
|
|
Mask = GHI_SILENT;
|
|
}
|
|
|
|
if (g_ExtData->
|
|
ReadHandleData(0, DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT,
|
|
&HandleCount, sizeof(HandleCount),
|
|
NULL) != S_OK) {
|
|
dprintf("Unable to read handle information\n");
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// hThere of 0 indicates all handles.
|
|
//
|
|
if ((hThere == 0) || (hThere == (ULONG64)(LONG_PTR)INVALID_HANDLE_VALUE))
|
|
{
|
|
Hits = 0;
|
|
Handle = 0;
|
|
Matches = 0;
|
|
ZeroMemory( TypeCounts, sizeof(TypeCounts) );
|
|
|
|
while ( Hits < HandleCount )
|
|
{
|
|
if ( Type )
|
|
{
|
|
if (GetHandleInfo( Handle,
|
|
GHI_TYPE | GHI_SILENT,
|
|
&ObjectType ) )
|
|
{
|
|
Hits++;
|
|
if ( ObjectType == Type )
|
|
{
|
|
GetHandleInfo( Handle,
|
|
Mask,
|
|
&ObjectType );
|
|
Matches ++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetHandleInfo( Handle,
|
|
GHI_TYPE | GHI_SILENT,
|
|
&ObjectType) )
|
|
{
|
|
Hits++;
|
|
TypeCounts[ ObjectType ] ++;
|
|
|
|
GetHandleInfo( Handle,
|
|
Mask,
|
|
&ObjectType );
|
|
}
|
|
}
|
|
|
|
Handle += 4;
|
|
}
|
|
|
|
if ( Type == 0 )
|
|
{
|
|
dprintf( "%d Handles\n", Hits );
|
|
dprintf( "Type \tCount\n");
|
|
for (Type = 0; Type < TYPE_MAX ; Type++ )
|
|
{
|
|
if (TypeCounts[Type])
|
|
{
|
|
dprintf("%-15s\t%d\n",
|
|
g_TypeNames[Type].Name, TypeCounts[Type]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf("%d handles of type %s\n",
|
|
Matches, g_TypeNames[Type].Name );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetHandleInfo( hThere, Mask, &Type );
|
|
}
|
|
|
|
Exit:
|
|
EXIT_API();
|
|
return S_OK;
|
|
}
|