|
|
#include "ntsdextp.h"
#define REASONABLE_NUMBER 8
typedef BOOL (_ID_MATCH_FN)( PVOID A, PVOID B); typedef _ID_MATCH_FN * PID_MATCH_FN;
typedef VOID (_ID_BANNER_FN)( PVOID Id ); typedef _ID_BANNER_FN * PID_BANNER_FN;
typedef VOID (_HANDLE_CALLBACK_FN)( PVOID Context, HANDLE Here, HANDLE There ); typedef _HANDLE_CALLBACK_FN * PHANDLE_CALLBACK_FN;
#define MATCH_LARGE_INT ((PID_MATCH_FN)1)
typedef struct _HANDLE_TRACK { LIST_ENTRY List ; ULONG Flags ; ULONG Count ; ULONG Size ; PHANDLE Handles ; HANDLE HandleList[ REASONABLE_NUMBER ]; UCHAR IdData[ 1 ]; } HANDLE_TRACK, * PHANDLE_TRACK ;
typedef struct _HANDLE_TRACK_ARRAY { ULONG Count ; ULONG Size ; ULONG IdDataSize ; PID_MATCH_FN MatchFunc ; LIST_ENTRY List ; } HANDLE_TRACK_ARRAY, * PHANDLE_TRACK_ARRAY ;
typedef struct _THREAD_TRACK_INFO { CLIENT_ID Id ; PVOID Win32StartAddress ; DWORD Status ; } THREAD_TRACK_INFO ;
typedef struct _HANDLE_LEAK_HELPER { PWSTR Type ; PID_BANNER_FN Banner ; PHANDLE_CALLBACK_FN Filter ; ULONG ArraySize ; PID_MATCH_FN Match ; } HANDLE_LEAK_HELPER, * PHANDLE_LEAK_HELPER ;
_ID_BANNER_FN ThreadBanner ; _ID_BANNER_FN TokenBanner ; _HANDLE_CALLBACK_FN ThreadCallback ; _HANDLE_CALLBACK_FN TokenCallback ;
HANDLE_LEAK_HELPER HandleLeakHelpers[] = { { L"Thread", ThreadBanner, ThreadCallback, sizeof( THREAD_TRACK_INFO ), MATCH_LARGE_INT }, { L"Token", TokenBanner, TokenCallback, sizeof( TOKEN_CONTROL ), MATCH_LARGE_INT } };
PHANDLE_TRACK_ARRAY CreateArray( ULONG IdDataSize, PID_MATCH_FN MatchFn ) { PHANDLE_TRACK_ARRAY Array ;
Array = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( HANDLE_TRACK_ARRAY ) );
if ( Array ) { Array->Count = 0 ; Array->Size = 0; Array->IdDataSize = IdDataSize ; Array->MatchFunc = MatchFn ;
InitializeListHead( &Array->List );
return Array ; }
return NULL ; }
VOID DeleteArray( PHANDLE_TRACK_ARRAY Array ) { ULONG i ; PHANDLE_TRACK Track ;
while ( !IsListEmpty( &Array->List ) ) { Track = (PHANDLE_TRACK) RemoveHeadList( &Array->List );
if ( Track->Handles != Track->HandleList ) { RtlFreeHeap( RtlProcessHeap(), 0, Track->Handles ); }
RtlFreeHeap( RtlProcessHeap(), 0, Track ); }
RtlFreeHeap( RtlProcessHeap(), 0, Array ); }
VOID ExtendTrack( PHANDLE_TRACK Track ) { PHANDLE NewHandle ;
NewHandle = RtlAllocateHeap( RtlProcessHeap(), 0, (Track->Size + REASONABLE_NUMBER ) * sizeof( HANDLE ) );
if ( NewHandle ) { CopyMemory( NewHandle, Track->Handles, Track->Count * sizeof( HANDLE ) );
if ( Track->Handles != Track->HandleList ) { RtlFreeHeap( RtlProcessHeap(), 0, Track->Handles ); }
Track->Handles = NewHandle ; Track->Size += REASONABLE_NUMBER ; } }
VOID AddHandleToArray( PHANDLE_TRACK_ARRAY Array, PVOID IdData, HANDLE Handle ) { ULONG i; ULONG j; BOOL Match ; PHANDLE_TRACK Track ; PLIST_ENTRY Scan ;
Scan = Array->List.Flink ;
while ( Scan != &Array->List ) { Track = (PHANDLE_TRACK) Scan ;
if ( Array->MatchFunc == MATCH_LARGE_INT ) { Match = ((PLARGE_INTEGER) Track->IdData)->QuadPart == ((PLARGE_INTEGER) IdData)->QuadPart ; } else { Match = Array->MatchFunc( Track->IdData, IdData ); }
if ( Match ) { //
// We have a match:
//
if ( Track->Count == Track->Size ) { ExtendTrack( Track ); }
if ( Track->Count < Track->Size ) { Track->Handles[ Track->Count ] = Handle ;
Track->Count++; }
return ; }
Scan = Scan->Flink ; }
//
// No match, gotta add a new tid
//
Track = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( HANDLE_TRACK ) + Array->IdDataSize );
if ( Track ) { Track->Size = REASONABLE_NUMBER ; Track->Count = 1 ; Track->Handles = Track->HandleList ; Track->HandleList[0] = Handle ;
CopyMemory( Track->IdData, IdData, Array->IdDataSize );
InsertTailList( &Array->List, &Track->List ); }
}
VOID DumpArray( PHANDLE_TRACK_ARRAY Array, PID_BANNER_FN Banner ) { ULONG j; PHANDLE_TRACK Track ; PLIST_ENTRY Scan ;
Scan = Array->List.Flink ;
while ( Scan != &Array->List ) { Track = (PHANDLE_TRACK) Scan ;
Banner( Track->IdData );
dprintf(" Handles \t%d: ", Track->Count ); for ( j = 0 ; j < Track->Count ; j++ ) { dprintf("%x, ", Track->Handles[j] ); }
dprintf("\n");
Scan = Scan->Flink ; }
}
VOID HandleScanner( HANDLE hCurrentProcess, PWSTR Type, PVOID Context, PHANDLE_CALLBACK_FN Callback ) { DWORD HandleCount; NTSTATUS Status; DWORD Total; DWORD Handle; DWORD Hits; DWORD Matches; HANDLE hHere ; PHANDLE_TRACK_ARRAY Array ; POBJECT_TYPE_INFORMATION pTypeInfo; UCHAR Buffer[1024];
Status = NtQueryInformationProcess( hCurrentProcess, ProcessHandleCount, &HandleCount, sizeof( HandleCount ), NULL );
if ( !NT_SUCCESS( Status ) ) { return; }
Hits = 0; Handle = 0; Matches = 0;
while ( Hits < HandleCount ) { Status = NtDuplicateObject( hCurrentProcess, (HANDLE)(DWORD_PTR)Handle, NtCurrentProcess(), &hHere, 0, 0, DUPLICATE_SAME_ACCESS );
if ( NT_SUCCESS( Status ) ) {
pTypeInfo = (POBJECT_TYPE_INFORMATION) Buffer;
ZeroMemory( Buffer, 1024 );
Status = NtQueryObject( hHere, ObjectTypeInformation, pTypeInfo, 1024, NULL );
if (NT_SUCCESS(Status)) { if ( wcscmp( pTypeInfo->TypeName.Buffer, Type ) == 0 ) { //
// Score!
//
Callback( Context, hHere, (HANDLE)(DWORD_PTR)Handle );
Matches++ ;
} }
Hits++ ;
NtClose( hHere );
}
Handle += 4; }
dprintf("%d handles to objects of type %ws\n", Matches, Type ); }
VOID ThreadBanner( PVOID Id ) { UCHAR Symbol[ MAX_PATH ]; DWORD_PTR Disp ; THREAD_TRACK_INFO * Info ; UCHAR ExitStatus[ 32 ];
Info = (THREAD_TRACK_INFO *) Id ;
Symbol[0] = '\0';
GetSymbol( Info->Win32StartAddress, Symbol, &Disp );
if ( Info->Status != STILL_ACTIVE ) { sprintf(ExitStatus, " Stopped, %#x", Info->Status ); } else { strcpy( ExitStatus, "<Running>"); }
if ( Symbol[0] ) { dprintf("Thread %x.%x (%s) %s\n", Info->Id.UniqueProcess, Info->Id.UniqueThread, Symbol, ExitStatus ); } else { dprintf("Thread %x.%x %s\n", Info->Id.UniqueProcess, Info->Id.UniqueThread, ExitStatus );
} }
VOID ThreadCallback( PVOID Context, HANDLE Here, HANDLE There ) { NTSTATUS Status ; THREAD_BASIC_INFORMATION Info;
THREAD_TRACK_INFO ThdInfo ;
ZeroMemory( &ThdInfo, sizeof( ThdInfo ) );
Status = NtQueryInformationThread( Here, ThreadBasicInformation, &Info, sizeof( Info ), NULL );
if ( NT_SUCCESS( Status ) ) { ThdInfo.Id = Info.ClientId ; ThdInfo.Status = Info.ExitStatus ;
Status = NtQueryInformationThread( Here, ThreadQuerySetWin32StartAddress, &ThdInfo.Win32StartAddress, sizeof( PVOID ), NULL );
AddHandleToArray( Context, &ThdInfo , There ); } }
VOID TokenCallback( PVOID Context, HANDLE Here, HANDLE There ) { NTSTATUS Status ; TOKEN_CONTROL Control ; TOKEN_STATISTICS Stats ; ULONG Size ;
Status = NtQueryInformationToken( Here, TokenStatistics, &Stats, sizeof( Stats ), &Size );
if ( NT_SUCCESS( Status ) ) { Control.TokenId = Stats.TokenId ; Control.AuthenticationId = Stats.AuthenticationId ; Control.ModifiedId = Stats.ModifiedId ; NtQueryInformationToken( Here, TokenSource, &Control.TokenSource, sizeof( TOKEN_SOURCE ), &Size );
AddHandleToArray( Context, &Control, There ); } else { dprintf("Unable to query token information, %x\n", Status ); } }
VOID TokenBanner( PVOID Id ) { PTOKEN_CONTROL Control ;
Control = (PTOKEN_CONTROL) Id ;
dprintf("Token Id %x:%x, LogonId = %x:%x, Source = %s\n", Control->TokenId.HighPart, Control->TokenId.LowPart, Control->AuthenticationId.HighPart, Control->AuthenticationId.LowPart, Control->TokenSource.SourceName ); }
DECLARE_API( hleak ) { UNICODE_STRING String ; PHANDLE_LEAK_HELPER Helper = NULL ; PHANDLE_TRACK_ARRAY Array ; int i ;
INIT_API();
if ( !args || (*args == '\0' ) ) { dprintf( "!hleak <typename>\n" ); goto Exit; }
while ( *args == ' ' ) { args++ ; }
if ( !RtlCreateUnicodeStringFromAsciiz( &String, args ) ) { goto Exit; }
for ( i = 0 ; i < sizeof( HandleLeakHelpers ) / sizeof( HANDLE_LEAK_HELPER ) ; i++ ) { if ( _wcsicmp( String.Buffer, HandleLeakHelpers[ i ].Type ) == 0 ) { Helper = &HandleLeakHelpers[ i ]; break; } }
if ( Helper == NULL ) { dprintf( "The type '%ws' was not recognized. Valid types are:\n", String.Buffer ); for ( i = 0 ; i < sizeof( HandleLeakHelpers ) / sizeof( HANDLE_LEAK_HELPER ) ; i++ ) { dprintf( "\t%ws\n", HandleLeakHelpers[ i ].Type ); } RtlFreeUnicodeString( &String ); goto Exit; }
RtlFreeUnicodeString( &String );
Array = CreateArray( Helper->ArraySize, Helper->Match );
if ( !Array ) { dprintf( "not enough memory\n" ); }
HandleScanner( g_hCurrentProcess, Helper->Type, Array, Helper->Filter );
DumpArray( Array, Helper->Banner );
DeleteArray( Array );
Exit: EXIT_API(); }
|