运行任务管理器多个实例






4.84/5 (16投票s)
一个简单的应用程序,允许用户运行多个任务管理器实例。
引言
众所周知,任务管理器出于某种原因,不允许用户运行多个实例。本文介绍了一个简单的应用程序,允许用户启动任意数量的任务管理器实例。这里描述的技术仅适用于 Windows 7(以及可能 Vista);XP 的任务管理器使用不同的技术。
背景
为此,它采用简单的策略。当它开始执行时,它会尝试创建一个命名的内核对象(在本例中,一个互斥锁),如果已经存在一个名为“任务管理器”的对象,它会假定已经有另一个实例在运行,并关闭当前进程。
该互斥锁的名称是 TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0
。
以下是如何实现的示例
if( ::CreateMutex( NULL, FALSE,
TEXT( "TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0" ) ) == NULL )
{
if( ::GetLastError() == ERROR_ALREADY_EXISTS )
{
// task manager is already running - close current process
}
}
// active task manage wasn't detected - continue
代码
但首先,我们必须找出互斥锁的完整名称,其格式如下:\Sessions\<SESSION_ID>\BaseNamedObjects\TASKMGR.879e4d63-6c0e-4544-97f2-1244bd3f6de0,我们可以使用 ProcessIdToSessionId
API 调用来获取会话 ID。
DWORD sid;
if( !::ProcessIdToSessionId( ::GetCurrentProcessId(), &sid ) )
{
wprintf( L"Unable to get session ID. Error code: %d\n", ::GetLastError() );
return 2;
}
WCHAR mutexName[ MAX_PATH ];
mutexName[ 0 ] = 0;
// full name of the mutex (we want to mess only with session of the current user)
wcscat( mutexName, L"\\Sessions\\" );
_itow( sid, mutexName + wcslen( mutexName ), 10 );
wcscat( mutexName, L"\\BaseNamedObjects\\" );
wcscat( mutexName, MUTEX_NAME );
基本思路是在启动另一个任务管理器实例之前销毁互斥锁对象。要销毁它,我们需要找到对象的所有句柄并关闭它们。在此过程中,我们需要使用这些未公开的 API 调用:NtQuerySystemInformation
、NtQueryObject
和 DuplicateHandle
。
我们使用 NtQuerySystemInformation
获取系统中所有打开句柄的列表,然后遍历该列表,复制句柄以获得对该对象的访问权限,并调用 NtQueryObject
获取对象名称。当我们找到句柄时,我们使用 DuplicateHandle
API 调用创建一个副本,但这次,我们传递 DUPLICATE_CLOSE_SOURCE
标志,指示系统在复制后关闭原始句柄(有效地获取对象的控制权),然后立即关闭新句柄,最终结果是销毁该对象。
// Searches for handle to an object with specified name
// Returns -1 if it cannot obtain list of handles,
// 0 if there's no handles to the object or
// 1 if the object if found and handle is closed
INT SeekAndDestory(WCHAR* handleName)
{
INT found = 0;
// get list of opened handles
DWORD size = 0;
PSYSTEM_HANDLE_INFORMATION handles =
(PSYSTEM_HANDLE_INFORMATION)malloc( sizeof( SYSTEM_HANDLE_INFORMATION ) );
if( !NT_SUCCESS( ::pNtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handles,
sizeof( SYSTEM_HANDLE_INFORMATION ), &size ) ) )
{
free( handles );
if( size == 0 )
return -1;
DWORD newSize = size + sizeof(HANDLE) * 512;
handles = (PSYSTEM_HANDLE_INFORMATION)malloc( newSize );
if( !NT_SUCCESS( ::pNtQuerySystemInformation(
(SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handles,
newSize, &size ) ) )
{
free( handles );
return -1;
}
}
for( DWORD i = 0; i < handles->dwCount; i++ )
{
HANDLE process = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE,
handles->Handles[ i ].dwProcessId );
if( process )
{
HANDLE myHandle;
if( ::DuplicateHandle( process,
(HANDLE)handles->Handles[ i ].wValue, ::GetCurrentProcess(),
&myHandle, DUPLICATE_SAME_ACCESS, FALSE, 0 ) )
{
// get object name
PPUBLIC_OBJECT_TYPE_INFORMATION nameInfo =
(PPUBLIC_OBJECT_TYPE_INFORMATION)malloc(
sizeof( PUBLIC_OBJECT_TYPE_INFORMATION ) );
if( !NT_SUCCESS( pNtQueryObject( myHandle, ObjectNameInformation,
nameInfo, sizeof( PUBLIC_OBJECT_TYPE_INFORMATION ), &size ) ) )
{
free( nameInfo );
if( (int)size <= 0 )
{
::CloseHandle( myHandle );
continue;
}
DWORD newSize = size;
nameInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)malloc( newSize );
if( !NT_SUCCESS( pNtQueryObject( myHandle, ObjectNameInformation,
nameInfo, newSize, &size ) ) )
{
::CloseHandle( myHandle );
continue;
}
}
::CloseHandle( myHandle );
if( lstrcmp( handleName, nameInfo->TypeName.Buffer ) == 0 )
{
// take ownership of the handle
// (copy handle and close original and then close the copy)
if( ::DuplicateHandle( process,
(HANDLE)handles->Handles[ i ].wValue, ::GetCurrentProcess(),
&myHandle, 0, FALSE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ) )
{
::CloseHandle( myHandle );
found = 1;
}
}
free( nameInfo );
}
::CloseHandle( process );
}
}
free( handles );
return found;
}
注意:要访问 NtQuerySystemInformation
和 NtQueryObject
,我们需要使用 GetProcAddress
,因为它们在构建过程中对链接器不可用。NtLib.h 文件包含使用未公开 API 所需的定义。
pfnNtQuerySystemInformation pNtQuerySystemInformation = NULL;
pfnNtQueryObject pNtQueryObject = NULL;
BOOL LoadNtLib()
{
pNtQuerySystemInformation = (pfnNtQuerySystemInformation)::GetProcAddress(
GetModuleHandle( TEXT( "ntdll" ) ), "NtQuerySystemInformation" );
pNtQueryObject = (pfnNtQueryObject)::GetProcAddress(
GetModuleHandle( TEXT( "ntdll" ) ), "NtQueryObject" );
return pNtQuerySystemInformation && pNtQueryObject;
}
有关 NtQuerySystemInformation
的更多信息,请参阅 Naveen 的文章:列出已使用的文件。