windows-nt/Source/XPSP1/NT/inetsrv/iis/setup/osrc/kill.cpp
2020-09-26 16:20:57 +08:00

782 lines
21 KiB
C++

#include "stdafx.h"
#include <windows.h>
#include <winuserp.h>
#include <winperf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kill.h"
PUCHAR g_CommonLargeBuffer = NULL;
ULONG g_CommonLargeBufferSize = 64*1024;
DWORD
GetTaskListEx(
PTASK_LIST pTask,
DWORD dwNumTasks,
BOOL fThreadInfo,
DWORD dwNumServices,
const _ENUM_SERVICE_STATUS_PROCESSA* pServiceInfo
)
/*++
Routine Description:
Provides an API for getting a list of tasks running at the time of the
API call. This function uses internal NT apis and data structures. This
api is MUCH faster that the non-internal version that uses the registry.
Arguments:
pTask - Array of TASK_LIST structures to fill.
dwNumTasks - Maximum number of tasks that the pTask array can hold.
fThreadInfo - TRUE if thread information is desired.
dwNumServices - Maximum number of entries in pServiceInfo.
pServiceInfo - Array of service status structures to reference
for supporting services in processes.
Return Value:
Number of tasks placed into the pTask array.
--*/
{
#ifndef _CHICAGO_
PSYSTEM_PROCESS_INFORMATION ProcessInfo = NULL;
NTSTATUS status;
ANSI_STRING pname;
PCHAR p = NULL;
ULONG TotalOffset;
ULONG totalTasks = 0;
retry:
if (g_CommonLargeBuffer == NULL)
{
g_CommonLargeBuffer = (PUCHAR) VirtualAlloc(NULL,g_CommonLargeBufferSize,MEM_COMMIT,PAGE_READWRITE);
if (g_CommonLargeBuffer == NULL)
{
return 0;
}
}
status = NtQuerySystemInformation(SystemProcessInformation,g_CommonLargeBuffer,g_CommonLargeBufferSize,NULL);
if (status == STATUS_INFO_LENGTH_MISMATCH)
{
g_CommonLargeBufferSize += 8192;
VirtualFree (g_CommonLargeBuffer, 0, MEM_RELEASE);
g_CommonLargeBuffer = NULL;
goto retry;
}
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) g_CommonLargeBuffer;
TotalOffset = 0;
while (TRUE)
{
pname.Buffer = NULL;
if ( ProcessInfo->ImageName.Buffer )
{
RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
if (pname.Buffer)
{
p = strrchr(pname.Buffer,'\\');
if ( p )
{
p++;
}
else
{
p = pname.Buffer;
}
}
else
{
p = "";
}
}
else
{
p = "System Process";
}
strcpy( pTask->ProcessName, p );
pTask->flags = 0;
pTask->dwProcessId = (DWORD)(DWORD_PTR)ProcessInfo->UniqueProcessId;
pTask->dwInheritedFromProcessId = (DWORD)(DWORD_PTR)ProcessInfo->InheritedFromUniqueProcessId;
pTask->CreateTime.QuadPart = (ULONGLONG)ProcessInfo->CreateTime.QuadPart;
pTask->PeakVirtualSize = ProcessInfo->PeakVirtualSize;
pTask->VirtualSize = ProcessInfo->VirtualSize;
pTask->PageFaultCount = ProcessInfo->PageFaultCount;
pTask->PeakWorkingSetSize = ProcessInfo->PeakWorkingSetSize;
pTask->WorkingSetSize = ProcessInfo->WorkingSetSize;
pTask->NumberOfThreads = ProcessInfo->NumberOfThreads;
if (fThreadInfo)
{
if (pTask->pThreadInfo = (PTHREAD_INFO) malloc(pTask->NumberOfThreads * sizeof(THREAD_INFO))) {
UINT nThread = pTask->NumberOfThreads;
PTHREAD_INFO pThreadInfo = pTask->pThreadInfo;
PSYSTEM_THREAD_INFORMATION pSysThreadInfo =
(PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
while (nThread--) {
pThreadInfo->ThreadState = pSysThreadInfo->ThreadState;
pThreadInfo->UniqueThread = pSysThreadInfo->ClientId.UniqueThread;
pThreadInfo++;
pSysThreadInfo++;
}
}
}
else
{
pTask->pThreadInfo = NULL;
}
// Initialize the ServiceNames if this task hosts any.
//
*pTask->ServiceNames = 0;
if (dwNumServices)
{
// For each service with this process id, append it's service
// name to the buffer. Separate each with a comma.
//
BOOL fFirstTime = TRUE;
DWORD iSvc;
size_t cchRemain = SERVICENAMES_SIZE - 1;
size_t cch;
for (iSvc = 0; iSvc < dwNumServices; iSvc++) {
if (pTask->dwProcessId == pServiceInfo[iSvc].ServiceStatusProcess.dwProcessId) {
cch = strlen(pServiceInfo[iSvc].lpServiceName);
if (fFirstTime) {
fFirstTime = FALSE;
strncpy(
pTask->ServiceNames,
pServiceInfo[iSvc].lpServiceName,
cchRemain);
// strncpy may not terminate the string if
// cchRemain <= cch so we do it regardless.
//
pTask->ServiceNames[cchRemain] = 0;
} else if (cchRemain > 1) { // ensure room for the comma
strncat(
pTask->ServiceNames,
",",
cchRemain--);
strncat(
pTask->ServiceNames,
pServiceInfo[iSvc].lpServiceName,
cchRemain);
}
// Counts are unsigned so we have to check before
// subtracting.
//
if (cchRemain < cch) {
// No more room for any more.
break;
} else {
cchRemain -= cch;
}
}
}
}
pTask++;
totalTasks++;
if (totalTasks >= dwNumTasks)
{
break;
}
if (ProcessInfo->NextEntryOffset == 0)
{
break;
}
TotalOffset += ProcessInfo->NextEntryOffset;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&g_CommonLargeBuffer[TotalOffset];
}
return totalTasks;
#else
return 0;
#endif
}
DWORD
GetTaskList(
PTASK_LIST pTask,
DWORD dwNumTasks
)
{
return GetTaskListEx(pTask, dwNumTasks, FALSE, 0, NULL);
}
void FreeTaskListMem(void)
{
if (g_CommonLargeBuffer)
{
VirtualFree (g_CommonLargeBuffer, 0, MEM_RELEASE);
g_CommonLargeBuffer = NULL;
}
return;
}
BOOL DetectOrphans(PTASK_LIST pTask,DWORD dwNumTasks)
{
DWORD i, j;
BOOL Result = FALSE;
for (i=0; i<dwNumTasks; i++) {
if (pTask[i].dwInheritedFromProcessId != 0) {
for (j=0; j<dwNumTasks; j++) {
if (i != j && pTask[i].dwInheritedFromProcessId == pTask[j].dwProcessId) {
if (pTask[i].CreateTime.QuadPart <= pTask[j].CreateTime.QuadPart) {
pTask[i].dwInheritedFromProcessId = 0;
Result = TRUE;
}
break;
}
}
}
}
return Result;
}
/*++
Routine Description:
Changes the tlist process's privilige so that kill works properly.
Return Value:
TRUE - success
FALSE - failure
--*/
BOOL EnableDebugPriv(VOID)
{
HANDLE hToken;
LUID DebugValue;
TOKEN_PRIVILEGES tkp;
//
// Retrieve a handle of the access token
//
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken)) {
//printf("OpenProcessToken failed with %d\n", GetLastError());
return FALSE;
}
//
// Enable the SE_DEBUG_NAME privilege or disable
// all privileges, depending on the fEnable flag.
//
//if (!LookupPrivilegeValue((LPSTR) NULL,SE_DEBUG_NAME,&DebugValue))
if (!LookupPrivilegeValueA((LPSTR) NULL,"SeDebugPrivilege",&DebugValue))
{
//printf("LookupPrivilegeValue failed with %d\n", GetLastError());
return FALSE;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = DebugValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tkp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL)) {
//
// The return value of AdjustTokenPrivileges be texted
//
//printf("AdjustTokenPrivileges failed with %d\n", GetLastError());
return FALSE;
}
return TRUE;
}
BOOL KillProcess(PTASK_LIST tlist,BOOL fForce)
{
HANDLE hProcess1 = NULL;
HANDLE hProcess2 = NULL;
HDESK hdeskSave = NULL;
HDESK hdesk = NULL;
HWINSTA hwinsta = NULL;
HWINSTA hwinstaSave = NULL;
if (fForce || !tlist->hwnd) {
hProcess1 = OpenProcess( PROCESS_ALL_ACCESS, FALSE, (DWORD) (DWORD_PTR) tlist->dwProcessId );
if (hProcess1)
{
hProcess2 = OpenProcess( PROCESS_ALL_ACCESS, FALSE, (DWORD) (DWORD_PTR) tlist->dwProcessId );
if (hProcess2 == NULL)
{
// clean up memory already allocated
CloseHandle( hProcess1 );
return FALSE;
}
if (!TerminateProcess( hProcess2, 1 ))
{
CloseHandle( hProcess1 );
CloseHandle( hProcess2 );
return FALSE;
}
CloseHandle( hProcess1 );
CloseHandle( hProcess2 );
return TRUE;
}
}
//
// save the current windowstation
//
hwinstaSave = GetProcessWindowStation();
//
// save the current desktop
//
hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
//
// open the windowstation
//
hwinsta = OpenWindowStationA( tlist->lpWinsta, FALSE, MAXIMUM_ALLOWED );
if (!hwinsta) {
return FALSE;
}
//
// change the context to the new windowstation
//
SetProcessWindowStation( hwinsta );
//
// open the desktop
//
hdesk = OpenDesktopA( tlist->lpDesk, 0, FALSE, MAXIMUM_ALLOWED );
if (!hdesk) {
return FALSE;
}
//
// change the context to the new desktop
//
SetThreadDesktop( hdesk );
//
// kill the process
//
PostMessage( (HWND) tlist->hwnd, WM_CLOSE, 0, 0 );
//
// restore the previous desktop
//
if (hdesk != hdeskSave) {
SetThreadDesktop( hdeskSave );
CloseDesktop( hdesk );
}
//
// restore the context to the previous windowstation
//
if (hwinsta != hwinstaSave) {
SetProcessWindowStation( hwinstaSave );
CloseWindowStation( hwinsta );
}
return TRUE;
}
VOID GetWindowTitles(PTASK_LIST_ENUM te)
{
//
// enumerate all windows and try to get the window
// titles for each task
//
EnumWindowStations( (WINSTAENUMPROC) EnumWindowStationsFunc, (LPARAM)te );
}
/*++
Routine Description:
Callback function for windowstation enumeration.
Arguments:
lpstr - windowstation name
lParam - ** not used **
Return Value:
TRUE - continues the enumeration
--*/
BOOL CALLBACK EnumWindowStationsFunc(LPSTR lpstr,LPARAM lParam)
{
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
HWINSTA hwinsta;
HWINSTA hwinstaSave;
//
// open the windowstation
//
hwinsta = OpenWindowStationA( lpstr, FALSE, MAXIMUM_ALLOWED );
if (!hwinsta) {
return FALSE;
}
//
// save the current windowstation
//
hwinstaSave = GetProcessWindowStation();
//
// change the context to the new windowstation
//
SetProcessWindowStation( hwinsta );
te->lpWinsta = _strdup( lpstr );
//
// enumerate all the desktops for this windowstation
//
EnumDesktops( hwinsta, (DESKTOPENUMPROC) EnumDesktopsFunc, lParam );
//
// restore the context to the previous windowstation
//
if (hwinsta != hwinstaSave) {
SetProcessWindowStation( hwinstaSave );
CloseWindowStation( hwinsta );
}
//
// continue the enumeration
//
return TRUE;
}
/*++
Routine Description:
Callback function for desktop enumeration.
Arguments:
lpstr - desktop name
lParam - ** not used **
Return Value:
TRUE - continues the enumeration
--*/
BOOL CALLBACK EnumDesktopsFunc(LPSTR lpstr,LPARAM lParam)
{
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
HDESK hdeskSave;
HDESK hdesk;
//
// open the desktop
//
hdesk = OpenDesktopA( lpstr, 0, FALSE, MAXIMUM_ALLOWED );
if (!hdesk) {
return FALSE;
}
//
// save the current desktop
//
hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
//
// change the context to the new desktop
//
SetThreadDesktop( hdesk );
te->lpDesk = _strdup( lpstr );
//
// enumerate all windows in the new desktop
//
((PTASK_LIST_ENUM)lParam)->bFirstLoop = TRUE;
EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
((PTASK_LIST_ENUM)lParam)->bFirstLoop = FALSE;
EnumWindows( (WNDENUMPROC)EnumWindowsProc, lParam );
//
// restore the previous desktop
//
if (hdesk != hdeskSave) {
SetThreadDesktop( hdeskSave );
CloseDesktop( hdesk );
}
return TRUE;
}
/*++
Routine Description:
Callback function for window enumeration.
Arguments:
hwnd - window handle
lParam - pte
Return Value:
TRUE - continues the enumeration
--*/
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
DWORD pid = 0;
DWORD i;
CHAR buf[TITLE_SIZE];
PTASK_LIST_ENUM te = (PTASK_LIST_ENUM)lParam;
PTASK_LIST tlist = te->tlist;
DWORD numTasks = te->numtasks;
//
// Use try/except block when enumerating windows,
// as a window may be destroyed by another thread
// when being enumerated.
//
//try {
//
// get the processid for this window
//
if (!GetWindowThreadProcessId( hwnd, &pid )) {
return TRUE;
}
if ((GetWindow( hwnd, GW_OWNER )) ||
(!(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)) && te->bFirstLoop) {
//
// not a top level window
//
return TRUE;
}
//
// look for the task in the task list for this window
// If this is the second time let invisible windows through if we don't
// have a window already
//
for (i=0; i<numTasks; i++) {
if (((DWORD) (DWORD_PTR)tlist[i].dwProcessId == pid) && (te->bFirstLoop || (tlist[i].hwnd == 0))) {
tlist[i].hwnd = hwnd;
tlist[i].lpWinsta = te->lpWinsta;
tlist[i].lpDesk = te->lpDesk;
//
// we found the task no lets try to get the
// window text
//
if (GetWindowTextA( (HWND) tlist[i].hwnd, buf, sizeof(buf) )) {
//
// go it, so lets save it
//
lstrcpyA( tlist[i].WindowTitle, buf );
}
break;
}
}
//} except(EXCEPTION_EXECUTE_HANDLER) {
//}
//
// continue the enumeration
//
return TRUE;
}
BOOL MatchPattern(PUCHAR String,PUCHAR Pattern)
{
UCHAR c, p, l;
for (; ;) {
switch (p = *Pattern++) {
case 0: // end of pattern
return *String ? FALSE : TRUE; // if end of string TRUE
case '*':
while (*String) { // match zero or more char
if (MatchPattern (String++, Pattern))
return TRUE;
}
return MatchPattern (String, Pattern);
case '?':
if (*String++ == 0) // match any one char
return FALSE; // not end of string
break;
case '[':
if ( (c = *String++) == 0) // match char set
return FALSE; // syntax
c = (UCHAR)toupper(c);
l = 0;
while (p = *Pattern++) {
if (p == ']') // if end of char set, then
return FALSE; // no match found
if (p == '-') { // check a range of chars?
p = *Pattern; // get high limit of range
if (p == 0 || p == ']')
return FALSE; // syntax
if (c >= l && c <= p)
break; // if in range, move on
}
l = p;
if (c == p) // if char matches this element
break; // move on
}
while (p && p != ']') // got a match in char set
p = *Pattern++; // skip to end of set
break;
default:
c = *String++;
if (toupper(c) != p) // check for exact char
return FALSE; // not a match
break;
}
}
}
struct _ProcessIDStruct
{
DWORD pid;
CHAR pname[MAX_PATH];
} g_Arguments[ 64 ];
DWORD g_dwNumberOfArguments;
int _cdecl KillProcessNameReturn0(CHAR *ProcessNameToKill)
{
DWORD i, j;
DWORD numTasks;
TASK_LIST_ENUM te;
int rval = 0;
CHAR tname[PROCESS_SIZE];
LPSTR p;
DWORD ThisPid;
BOOL iForceKill = TRUE;
TASK_LIST The_TList[MAX_TASKS];
g_dwNumberOfArguments = 0;
//
// Get the process name into the array
//
g_Arguments[g_dwNumberOfArguments].pid = 0;
// make sure there is no path specified.
char pfilename_only[_MAX_FNAME];
char pextention_only[_MAX_EXT];
_splitpath( ProcessNameToKill, NULL, NULL, pfilename_only, pextention_only);
if (pextention_only) {strcat(pfilename_only,pextention_only);}
// make it uppercase
char *copy1 = _strupr(_strdup(pfilename_only));
lstrcpyA(g_Arguments[g_dwNumberOfArguments].pname, copy1);
free( copy1 );
g_dwNumberOfArguments += 1;
//
// lets be god
//
EnableDebugPriv();
//
// get the task list for the system
//
numTasks = GetTaskList( The_TList, MAX_TASKS );
//
// enumerate all windows and try to get the window
// titles for each task
//
te.tlist = The_TList;
te.numtasks = numTasks;
GetWindowTitles( &te );
ThisPid = GetCurrentProcessId();
for (i=0; i<numTasks; i++) {
//
// this prevents the user from killing KILL.EXE and
// it's parent cmd window too
//
if (ThisPid == (DWORD) (DWORD_PTR) The_TList[i].dwProcessId) {
continue;
}
if (MatchPattern( (PUCHAR) The_TList[i].WindowTitle, (PUCHAR) "*KILL*" )) {
continue;
}
tname[0] = 0;
lstrcpyA( tname, The_TList[i].ProcessName );
p = strchr( tname, '.' );
if (p) {
p[0] = '\0';
}
for (j=0; j<g_dwNumberOfArguments; j++) {
if (g_Arguments[j].pname) {
if (MatchPattern( (PUCHAR) tname, (PUCHAR) g_Arguments[j].pname )) {
The_TList[i].flags = TRUE;
} else if (MatchPattern( (PUCHAR) The_TList[i].ProcessName, (PUCHAR) g_Arguments[j].pname )) {
The_TList[i].flags = TRUE;
} else if (MatchPattern( (PUCHAR) The_TList[i].WindowTitle, (PUCHAR) g_Arguments[j].pname )) {
The_TList[i].flags = TRUE;
}
} else if (g_Arguments[j].pid) {
if ((DWORD) (DWORD_PTR) The_TList[i].dwProcessId == g_Arguments[j].pid) {
The_TList[i].flags = TRUE;
}
}
}
}
for (i=0; i<numTasks; i++)
{
if (The_TList[i].flags)
{
if (KillProcess( &The_TList[i], iForceKill ))
{
//printf( "process %s (%d) - '%s' killed\n", The_TList[i].ProcessName,The_TList[i].dwProcessId,The_TList[i].hwnd ? The_TList[i].WindowTitle : "");
}
else
{
//printf( "process %s (%d) - '%s' could not be killed\n",The_TList[i].ProcessName,The_TList[i].dwProcessId,The_TList[i].hwnd ? The_TList[i].WindowTitle : "");
rval = 1;
}
}
}
FreeTaskListMem();
return rval;
}