/*++ Copyright (c) 1996 Microsoft Corporation Module Name: leaks.c Abstract: A filter DLL for trying to detect memory, event, registry, and token handle leaks. Author: Charlie Wickham/Rod Gamache Revision History: --*/ #include #include #include #define _ADVAPI32_ #define _KERNEL32_ #include #include #include "clusrtl.h" #include "leaks.h" HINSTANCE Kernel32Handle; HINSTANCE Advapi32Handle; FARPROC SystemLocalAlloc; FARPROC SystemLocalFree; FARPROC SystemCreateEventA; FARPROC SystemCreateEventW; FARPROC SystemRegOpenKeyA; FARPROC SystemRegOpenKeyW; FARPROC SystemRegOpenKeyExA; FARPROC SystemRegOpenKeyExW; FARPROC SystemRegCreateKeyA; FARPROC SystemRegCreateKeyW; FARPROC SystemRegCreateKeyExA; FARPROC SystemRegCreateKeyExW; FARPROC SystemRegCloseKey; FARPROC SystemOpenProcessToken; FARPROC SystemOpenThreadToken; FARPROC SystemDuplicateToken; FARPROC SystemDuplicateTokenEx; FARPROC SystemCloseHandle; #define SetSystemPointer( _h, _n ) \ System##_n = GetProcAddress( _h, #_n ); BOOL LeaksVerbose = FALSE; HANDLE_TABLE HandleTable[ MAX_HANDLE / HANDLE_DELTA ]; BOOLEAN WINAPI LeaksDllEntry( IN HINSTANCE DllHandle, IN DWORD Reason, IN LPVOID Reserved ) /*++ Routine Description: Main DLL entrypoint Arguments: DllHandle - Supplies the DLL handle. Reason - Supplies the call reason Return Value: TRUE if successful FALSE if unsuccessful --*/ { if (Reason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(DllHandle); ClRtlInitialize( FALSE ); // // get pointers to the real functions // Kernel32Handle = LoadLibrary( "kernel32.dll" ); Advapi32Handle = LoadLibrary( "advapi32.dll" ); SetSystemPointer( Kernel32Handle, LocalAlloc ); SetSystemPointer( Kernel32Handle, LocalFree ); SetSystemPointer( Kernel32Handle, CreateEventA ); SetSystemPointer( Kernel32Handle, CreateEventW ); SetSystemPointer( Advapi32Handle, RegOpenKeyA ); SetSystemPointer( Advapi32Handle, RegOpenKeyW ); SetSystemPointer( Advapi32Handle, RegOpenKeyExA ); SetSystemPointer( Advapi32Handle, RegOpenKeyExW ); SetSystemPointer( Advapi32Handle, RegCreateKeyA ); SetSystemPointer( Advapi32Handle, RegCreateKeyW ); SetSystemPointer( Advapi32Handle, RegCreateKeyExA ); SetSystemPointer( Advapi32Handle, RegCreateKeyExW ); SetSystemPointer( Advapi32Handle, RegCloseKey ); SetSystemPointer( Advapi32Handle, OpenProcessToken ); SetSystemPointer( Advapi32Handle, OpenThreadToken ); SetSystemPointer( Advapi32Handle, DuplicateToken ); SetSystemPointer( Advapi32Handle, DuplicateTokenEx ); SetSystemPointer( Kernel32Handle, CloseHandle ); } return(TRUE); } // // leaks memory header. This structure is at the front of the allocated area // and the area behind it is returned to the caller. PlaceHolder holds the // heap free list pointer. Signature holds ALOC or FREE. // #define HEAP_SIGNATURE_ALLOC 'COLA' #define HEAP_SIGNATURE_FREE 'EERF' typedef struct _MEM_HDR { PVOID PlaceHolder; DWORD Signature; PVOID CallersAddress; PVOID CallersCaller; } MEM_HDR, *PMEM_HDR; HLOCAL WINAPI LocalAlloc( UINT uFlags, SIZE_T uBytes ) { HLOCAL memory; PMEM_HDR memHdr; PVOID callersAddress; PVOID callersCaller; RtlGetCallersAddress( &callersAddress, &callersCaller ); memHdr = (PVOID)(*SystemLocalAlloc)( uFlags, uBytes + sizeof(MEM_HDR) ); if ( !memHdr ) { return NULL; } memHdr->Signature = HEAP_SIGNATURE_ALLOC; memHdr->CallersAddress = callersAddress; memHdr->CallersCaller = callersCaller; return(memHdr+1); } HLOCAL WINAPI LocalFree( HLOCAL hMem ) { PMEM_HDR memHdr = hMem; PVOID callersAddress; PVOID callersCaller; if ( memHdr ) { --memHdr; if ( memHdr->Signature == HEAP_SIGNATURE_FREE ) { CHAR buf[64]; sprintf( buf, "Freeing %X a 2nd time!\n", memHdr ); OutputDebugString( buf ); DebugBreak(); } else if ( memHdr->Signature == HEAP_SIGNATURE_ALLOC ) { RtlGetCallersAddress(&callersAddress, &callersCaller ); memHdr->Signature = HEAP_SIGNATURE_FREE; memHdr->CallersAddress = callersAddress; memHdr->CallersCaller = callersCaller; } else { memHdr++; } } return( (HLOCAL)(*SystemLocalFree)(memHdr) ); } HANDLE WINAPI CreateEventA( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName ) { HANDLE handle; PVOID callersAddress; PVOID callersCaller; handle = (HANDLE)(*SystemCreateEventA)( lpEventAttributes, bManualReset, bInitialState, lpName ); if ( handle != NULL ) { SetHandleTable( handle, TRUE, LeaksEvent ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] CreateEventA returns handle %1!X!, called from %2!X! and %3!X!\n", handle, callersAddress, callersCaller ); } return(handle); } // CreateEventA HANDLE WINAPI CreateEventW( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName ) { HANDLE handle; PVOID callersAddress; PVOID callersCaller; handle = (HANDLE)(*SystemCreateEventW)( lpEventAttributes, bManualReset, bInitialState, lpName ); if ( handle != NULL ) { SetHandleTable( handle, TRUE, LeaksEvent ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] CreateEventW returns handle %1!X!, called from %2!X! and %3!X!\n", handle, callersAddress, callersCaller ); } return(handle); } // CreateEventW LONG APIENTRY RegOpenKeyA( HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegOpenKeyA)( hKey, lpSubKey, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegOpenKeyA returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegOpenKeyA LONG APIENTRY RegOpenKeyW( HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegOpenKeyW)( hKey, lpSubKey, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegOpenKeyW returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegOpenKeyW LONG APIENTRY RegOpenKeyExA( HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegOpenKeyExA)( hKey, lpSubKey, ulOptions, samDesired, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegOpenKeyExA returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegOpenKeyExA LONG APIENTRY RegOpenKeyExW( HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegOpenKeyExW)( hKey, lpSubKey, ulOptions, samDesired, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegOpenKeyExW returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegOpenKeyExW LONG APIENTRY RegCreateKeyA( HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegCreateKeyA)( hKey, lpSubKey, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegCreateKeyA returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegCreateKeyA LONG APIENTRY RegCreateKeyW( HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegCreateKeyW)( hKey, lpSubKey, phkResult ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegCreateKeyW returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegCreateKeyW LONG APIENTRY RegCreateKeyExA( HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegCreateKeyExA)(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegCreateKeyExA returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegCreateKeyExA LONG APIENTRY RegCreateKeyExW( HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegCreateKeyExW)( hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition ); if ( status == ERROR_SUCCESS ) { SetHandleTable( *phkResult, TRUE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegCreateKeyExW returns key %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phkResult, status, callersAddress, callersCaller ); } return(status); } // RegCreateKeyExW LONG APIENTRY RegCloseKey( HKEY hKey ) { LONG status; PVOID callersAddress; PVOID callersCaller; status = (*SystemRegCloseKey)( hKey ); if ( status == ERROR_SUCCESS ) { SetHandleTable( hKey, FALSE, LeaksRegistry ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] RegCloseKey for key %1!X! returns status %2!u!, called from %3!X! and %4!X!\n", hKey, status, callersAddress, callersCaller ); } return(status); } // RegCloseKey BOOL WINAPI CloseHandle( IN OUT HANDLE hObject ) { PVOID callersAddress; PVOID callersCaller; if ( HandleTable[ HINDEX( hObject )].InUse ) { RtlGetCallersAddress(&callersAddress, &callersCaller ); HandleTable[ HINDEX( hObject )].InUse = FALSE; HandleTable[ HINDEX( hObject )].Caller = callersAddress; HandleTable[ HINDEX( hObject )].CallersCaller = callersCaller; if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] CloseHandle for handle %1!X!, called from %2!X! and %3!X!\n", hObject, callersAddress, callersCaller ); } } return (*SystemCloseHandle)( hObject ); } BOOL WINAPI OpenProcessToken ( IN HANDLE ProcessHandle, IN DWORD DesiredAccess, OUT PHANDLE TokenHandle ) { BOOL status; PVOID callersAddress; PVOID callersCaller; status = (*SystemOpenProcessToken)(ProcessHandle, DesiredAccess, TokenHandle); if ( status ) { SetHandleTable( *TokenHandle, TRUE, LeaksToken ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] OpenProcessToken returns handle %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *TokenHandle, status, callersAddress, callersCaller ); } return(status); } BOOL WINAPI OpenThreadToken ( IN HANDLE ThreadHandle, IN DWORD DesiredAccess, IN BOOL OpenAsSelf, OUT PHANDLE TokenHandle ) { BOOL status; PVOID callersAddress; PVOID callersCaller; status = (*SystemOpenThreadToken)(ThreadHandle, DesiredAccess, OpenAsSelf, TokenHandle); if ( status ) { SetHandleTable( *TokenHandle, TRUE, LeaksToken ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] OpenThreadToken returns handle %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *TokenHandle, status, callersAddress, callersCaller ); } return(status); } BOOL WINAPI DuplicateToken( IN HANDLE ExistingTokenHandle, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, OUT PHANDLE DuplicateTokenHandle ) { BOOL status; PVOID callersAddress; PVOID callersCaller; status = (*SystemDuplicateToken)(ExistingTokenHandle, ImpersonationLevel, DuplicateTokenHandle); if ( status ) { SetHandleTable( *DuplicateTokenHandle, TRUE, LeaksToken ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] DuplicateToken returns handle %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *DuplicateTokenHandle, status, callersAddress, callersCaller ); } return(status); } BOOL WINAPI DuplicateTokenEx( IN HANDLE hExistingToken, IN DWORD dwDesiredAccess, IN LPSECURITY_ATTRIBUTES lpTokenAttributes, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, IN TOKEN_TYPE TokenType, OUT PHANDLE phNewToken) { BOOL status; PVOID callersAddress; PVOID callersCaller; status = (*SystemDuplicateTokenEx)(hExistingToken, dwDesiredAccess, lpTokenAttributes, ImpersonationLevel, TokenType, phNewToken); if ( status ) { SetHandleTable( *phNewToken, TRUE, LeaksToken ); } if ( LeaksVerbose ) { ClRtlLogPrint("[LEAKS] DuplicateTokenEx returns handle %1!X!, status %2!u!, called from %3!X! and %4!X!\n", *phNewToken, status, callersAddress, callersCaller ); } return(status); }