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.
778 lines
18 KiB
778 lines
18 KiB
/*++
|
|
|
|
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 <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#define _ADVAPI32_
|
|
#define _KERNEL32_
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
|
|
#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);
|
|
}
|