Microsoft KB Archive/131065

= How to obtain a handle to any process with SeDebugPrivilege =

Article ID: 131065

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Win32 Application Programming Interface, when used with:  Microsoft Windows Server 2003, Standard Edition (32-bit x86)

 Microsoft Windows Server 2003, Enterprise Edition (32-bit x86)

 Microsoft Windows 2000 Advanced Server

 Microsoft Windows 2000 Server</li></ul>

 Microsoft Windows 2000 Professional Edition</li></ul>

 Microsoft Windows NT Advanced Server 3.1</li></ul>

 Microsoft Windows NT Server 3.5</li></ul>

 Microsoft Windows NT Server 3.51</li></ul>

 Microsoft Windows NT Server 4.0 Standard Edition</li></ul>

 Microsoft Windows NT Workstation 3.1</li></ul>

 Microsoft Windows NT Workstation 3.5</li></ul>

 Microsoft Windows NT Workstation 3.51</li></ul>

<ul> <li>Microsoft Windows NT Workstation 4.0 Developer Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q131065

<div class="notice_section">

<div class="summary_section">

SUMMARY
In Microsoft Windows NT, Microsoft Windows 2000, and Microsoft Windows Server 2003, you can retrieve a handle to any process in the system by enabling the SeDebugPrivilege in the calling process. The calling process can then call the OpenProcess Win32 API to obtain a handle with PROCESS_ALL_ACCESS.

<div class="moreinformation_section">

MORE INFORMATION
This functionality is provided for system-level debugging purposes. For debugging non-system processes, it is not necessary to grant or enable this privilege.

This privilege allows the caller all access to the process, including the ability to call TerminateProcess, CreateRemoteThread, and other potentially dangerous Win32 APIs on the target process.

Take great care when granting SeDebugPrivilege to users or groups.

Sample Code
The following source code illustrates how to obtain SeDebugPrivilege in order to get a handle to a process with PROCESS_ALL_ACCESS. The sample code then calls TerminateProcess on the resultant process handle. --*/


 * 1) define RTN_OK 0
 * 2) define RTN_USAGE 1
 * 3) define RTN_ERROR 13


 * 1) include <windows.h>
 * 2) include <stdio.h>

BOOL SetPrivilege(   HANDLE hToken,          // token handle    LPCTSTR Privilege,      // Privilege to enable/disable    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable    );

void DisplayError(LPTSTR szAPI);

int main(int argc, char *argv[]) {   HANDLE hProcess; HANDLE hToken; int dwRetVal=RTN_OK; // assume success from main

// show correct usage for kill if (argc != 2) {       fprintf(stderr,"Usage: %s [ProcessId]\n", argv[0]); return RTN_USAGE; }

if(!OpenThreadToken(GetCurrentThread, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) {       if (GetLastError == ERROR_NO_TOKEN) {           if (!ImpersonateSelf(SecurityImpersonation)) return RTN_ERROR;

if(!OpenThreadToken(GetCurrentThread, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){ DisplayError("OpenThreadToken"); return RTN_ERROR; }        }        else return RTN_ERROR; }

// enable SeDebugPrivilege if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)) {       DisplayError("SetPrivilege");

// close token handle CloseHandle(hToken);

// indicate failure return RTN_ERROR; }

// open the process if((hProcess = OpenProcess(           PROCESS_ALL_ACCESS,            FALSE,            atoi(argv[1]) // PID from commandline            )) == NULL) {       DisplayError("OpenProcess"); return RTN_ERROR; }

// disable SeDebugPrivilege SetPrivilege(hToken, SE_DEBUG_NAME, FALSE);

if(!TerminateProcess(hProcess, 0xffffffff)) {       DisplayError("TerminateProcess"); dwRetVal=RTN_ERROR; }

// close handles CloseHandle(hToken); CloseHandle(hProcess);

return dwRetVal; } BOOL SetPrivilege(   HANDLE hToken,          // token handle    LPCTSTR Privilege,      // Privilege to enable/disable    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable    ) {   TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);

if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;

//    // first pass. get current privilege setting //    tp.PrivilegeCount           = 1; tp.Privileges[0].Luid      = luid; tp.Privileges[0].Attributes = 0;

AdjustTokenPrivileges(           hToken,            FALSE,            &tp,            sizeof(TOKEN_PRIVILEGES),            &tpPrevious,            &cbPrevious            );

if (GetLastError != ERROR_SUCCESS) return FALSE;

//    // second pass. set privilege based on previous setting //    tpPrevious.PrivilegeCount       = 1; tpPrevious.Privileges[0].Luid  = luid;

if(bEnablePrivilege) { tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); }   else { tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &           tpPrevious.Privileges[0].Attributes); }

AdjustTokenPrivileges(           hToken,            FALSE,            &tpPrevious,            cbPrevious,            NULL,            NULL            );

if (GetLastError != ERROR_SUCCESS) return FALSE;

return TRUE; } BOOL SetPrivilege(    HANDLE hToken,  // token handle     LPCTSTR Privilege,  // Privilege to enable/disable     BOOL bEnablePrivilege  // TRUE to enable. FALSE to disable ) {    TOKEN_PRIVILEGES tp = { 0 }; // Initialize everything to zero LUID luid; DWORD cb=sizeof(TOKEN_PRIVILEGES); if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if(bEnablePrivilege) { tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; } else { tp.Privileges[0].Attributes = 0; }    AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL ); if (GetLastError != ERROR_SUCCESS) return FALSE;

return TRUE; } void DisplayError(   LPTSTR szAPI    // pointer to failed API name    ) {   LPTSTR MessageBuffer; DWORD dwBufferLength;

fprintf(stderr,"%s error!\n", szAPI);

if(dwBufferLength=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError, GetSystemDefaultLangID, (LPTSTR) &MessageBuffer, 0,               NULL ))   {        DWORD dwBytesWritten;

//        // Output message string on stderr //        WriteFile(                GetStdHandle(STD_ERROR_HANDLE),                MessageBuffer,                dwBufferLength,                &dwBytesWritten,                NULL                );

//        // free the buffer allocated by the system //        LocalFree(MessageBuffer); } }

Additional query words: 3.10 3.50 OpenProcess TerminateProcess

Keywords: kbbug kbdebug kbhowto kbkernbase kbsecurity KB131065

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.