Taskbar Modfication to Kill Windows NT/2000 Processes | CodeGuru

Taskbar Modfication to Kill Windows NT/2000 Processes

The application lets you terminate any kind of running processes by 1) modifying Task Manager, 2) through a popup menu that comes up by right clicking on a tray icon. Click here for larger image By selecting a process from the menu, the process will be terminated. By selecting “Task Manager…” from the menu, a […]

Written By
CodeGuru Staff
CodeGuru Staff
Feb 8, 2001
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

The application lets you terminate any kind of running processes by
1) modifying Task Manager,

2) through a popup menu that comes up by right clicking on a tray icon.




Click here for larger image

By selecting a process from the menu, the process will be terminated.
By selecting “Task Manager…” from the menu, a new Task
Manager will be spawned, if one is not running yet.
Then, Task Manager will be modified so that it allows the user to
use “End Process” (right click on the process name in the list box)
to terminate services.

There are 2 binaries involved in the operation:

killer.exe: main application

privi.dll: process privilege manipulator dll

Here is how it works:

1. First the application creates a tray icon for itself. For this, I
used
Chris Maunder‘s CSystemTray class. Thanks Chris!

(Unfortunately, couldn’t find the link to his submission.)

2. On Right click on the icon, the running processes are collected and
their are added to an stl vector. It is done using PSAPI.DLL:

int CKillerDlg::UpdateProcessList()
{
 typedef DWORD (WINAPI *PEnumProcesses)( DWORD*, \
                                         UINT, \
                                         DWORD* );
 typedef DWORD (WINAPI *PEnumProcessModules)( HANDLE, \
                                              HMODULE*, \
                                              UINT, \
                                              DWORD* );
 typedef DWORD (WINAPI *PGetModuleBaseName)( HANDLE, \
                                             HMODULE, \
                                             LPTSTR, \
                                             UINT );
 _TCHAR   szProcessName[MAX_PATH] = _T(“unknown”);
 DWORD    processID[1024], cbNeeded, cProcesses;
 UINT i;
 int result = -1;
 HINSTANCE hPsApi = LoadLibrary( _T(“PSAPI.DLL”) );
 if ( hPsApi == NULL )
  return result;
 PEnumProcessModules EnumProcessModules =
 (PEnumProcessModules)GetProcAddress( hPsApi,
                                      “EnumProcessModules” );
#ifdef UNICODE
 PGetModuleBaseName GetModuleBaseName =
 (PGetModuleBaseName)GetProcAddress( hPsApi,
                                     “GetModuleBaseNameW” );
#else
 PGetModuleBaseName GetModuleBaseName =
 (PGetModuleBaseName)GetProcAddress( hPsApi,
                                     “GetModuleBaseNameA” );
#endif
 PEnumProcesses EnumProcesses =
 (PEnumProcesses)GetProcAddress( hPsApi,
                                 “EnumProcesses” );
 if ( EnumProcessModules == NULL
 || GetModuleBaseName == NULL
 || EnumProcesses == NULL )
  return result;
 // Get the list of process identifiers.
 if ( !EnumProcesses( processID,
                      sizeof(processID),
                      &cbNeeded ) )
  return result;
 // Calculate how many process identifiers were returned.
 cProcesses = cbNeeded / sizeof(DWORD);
 // Print the name and process identifier for each process.
 ClearProcessList();
 for ( i = 0; i < cProcesses; i++ )
 {
  // Get a handle to the process.
  HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION
                                 | PROCESS_VM_READ,
                                 FALSE,
                                 processID[i] );
  if ( hProcess )
  {
   HMODULE hMod;
   if ( EnumProcessModules( hProcess, &hMod,
                            sizeof(hMod), &cbNeeded) )
   {
    GetModuleBaseName( hProcess, hMod, szProcessName,
                       sizeof(szProcessName) );
    ProcItemStruct *procItem = new ProcItemStruct;
    procItem->name = szProcessName;
    procItem->id = processID[i];
    this->m_processList.push_back(procItem);
   }
  }
  CloseHandle( hProcess );
 }
 return result;
}

3. Afterwards, the the vector is sorted and used to create the popup menu.

void CKillerDlg::ShowTrayPopupMenu( CWnd* pWnd, CPoint pt )
{
 CMenu menu;
 CMenu* pSubMenu = NULL;
 menu.LoadMenu( IDR_TRAYPOPUPMENU );
 pSubMenu = menu.GetSubMenu(0);
 if ( pSubMenu != NULL )
 {
  UpdateMenu( pSubMenu );
  ::SetMenuDefaultItem( pSubMenu->m_hMenu, 0, TRUE );
  UpdateProcessList();
  // Function object for sorting
  ProcItemLess pl;
  std::sort(m_processList.begin(), m_processList.end(), pl);
  for (UINT i = 0; i < m_processList.size(); i++)
  {
   // arrange items into columns
   if (i%20 == 0)
    pSubMenu->AppendMenu( MF_MENUBARBREAK | MF_STRING,
                          KILLER_WINDOWID_FIRST + i ,
                          m_processList[i]->name );
   else
    pSubMenu->AppendMenu( MF_STRING,
                          KILLER_WINDOWID_FIRST + i ,
                          m_processList[i]->name );
  }
  if ( pWnd != NULL )
   pWnd->SetForegroundWindow();
  pSubMenu->TrackPopupMenu( TPM_LEFTALIGN,
                            pt.x, pt.y,
                            pWnd );
  if ( pWnd != NULL )
   pWnd->SetForegroundWindow();
 }
}

4. On clicking on process names, the KillProcess function is activated:

void CKillerDlg::OnKillProcess( UINT nID )
{
 ProcItemStruct *procItem;
 procItem = m_processList[nID – KILLER_WINDOWID_FIRST];
 // Below, 3 lines are commented out, so that no 
 // annoying “Are you sure?” messagebox is shown.
 //CString str(procItem->name);
 //str.Format(_T(“Name: %s \nPID: %d”), 
 //           str, 
 //           procItem->id);   
 //if (IDOK == ::MessageBox(NULL, 
 //                         str, 
 //                         _T(“Kill?”), 
 //                         MB_OKCANCEL))
 theApp.KillProcess(procItem->id, 9);
}

5. If the user select “Task Manager…”, first there is a test for running
instance. If running TaskMgr is found, the process ID is obtained, if not,
a new instance is spawnd using CreateProcess(), then the process ID is stored.
After this, LoadDllForRemoteThread() is called:

if (pId != 0)
 LoadDllForRemoteThread( pId,
                         TRUE,
                         TRUE,
                         L”privi.dll”,
                         L”Func” );

This

function
was published by
Zoltan Csizmadia. Thanks Zoltan!

Minor modification was made to his code. If debug code is compiled, function
pointer point to a relative jump instruction (E9), and the real function code
starts from where the jump is made to. Between the two addresses, variable
amount of “other stuff” is present. If MAXINJECTSIZE (the size of memory that
is allocated in the remote process to hold the code copied from our process) is
not big enough, problems arise. By testing for the relative jump in debug mode,
MAXINJECTSIZE can be reduced to the size of the function code. The following
simple function is the implementation:

PVOID GetFuncAddress(PVOID addr)
{
#ifdef _DEBUG
 //check if instruction is relative jump (E9)
 if (0xE9 != *((UCHAR*)addr))
  return addr;
 // calculate base of relative jump
 ULONG base = (ULONG)((UCHAR*)addr + 5);
 // calculate offset 
 ULONG *offset = (ULONG*)((UCHAR*)addr + 1);
 return (PVOID)(base + *offset);
#else
 // in release, don’t have to mess with jumps
 return addr;
#endif
}

Then it is used as follows:

WriteProcessMemory( hProcess,
                    p,
                    GetFuncAddress(RemoteThread),
                    MAXINJECTSIZE,
                    0 );

What the Func() does in privi.dll is merely enables the
DEBUG process privilege:

// Set SE_DEBUG privilige for TaskMgr process
// This will make it able to kill services as well
ULONG Func()
{
 HANDLE hToken;
 if ( ! OpenProcessToken( GetCurrentProcess(),
                          TOKEN_ADJUST_PRIVILEGES
                          | TOKEN_QUERY,
                          &hToken ))
  return 1;
 if ( ! SetPrivilege( hToken, SE_DEBUG_NAME, TRUE ))
 {
  CloseHandle(hToken);
  return 2;
 }
 CloseHandle(hToken);
 return 0;
}

Here is how SetPrivilege works:

// Set/Unset specified privilige for given handle
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;
}

The same adjustment of privileges takes place in the killer process to
allow the termination of services.

Downloads

Download executables – 12 Kb

Download source – 26 Kb

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.