This lists the unkillable process names in the Windows XP source code. These are process names that are not allowed to be killed by the Task Manager.
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 | BOOL CProcPage::IsSystemProcess(DWORD pid, CProcInfo * pProcInfo) { // We don't allow the following set of critical system processes to be terminated, // since the system would bugcheck immediately, no matter who you are. static const LPCTSTR apszCantKill[] = { TEXT("csrss.exe"), TEXT("winlogon.exe"), TEXT("smss.exe"), TEXT("services.exe"), TEXT("lsass.exe") }; // if they pass in a pProcInfo we'll use it, otherwise find it ourselves if (!pProcInfo) pProcInfo = FindProcInArrayByPID(m_pProcArray, pid); if (!pProcInfo) return FALSE; for (int i = 0; i < ARRAYSIZE(apszCantKill); ++i) { if (0 == lstrcmpi(pProcInfo->m_pszImageName, apszCantKill[i])) { TCHAR szTitle[MAX_PATH]; TCHAR szBody[MAX_PATH]; if (0 != LoadString(g_hInstance, IDS_CANTKILL, szTitle, ARRAYSIZE(szTitle)) && 0 != LoadString(g_hInstance, IDS_KILLSYS, szBody, ARRAYSIZE(szBody))) { MessageBox(m_hPage, szBody, szTitle, MB_ICONEXCLAMATION | MB_OK); } return TRUE; } } return FALSE; } |
This is the code to kill a process in Task Manager.
3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 | /*++ KillProcess Routine Description: Kills a process Arguments: pid - process Id of process to kill Return Value: Revision History: Nov-22-95 Davepl Created --*/ BOOL CProcPage::KillProcess(DWORD pid, BOOL bBatchKill) { DWORD dwError = ERROR_SUCCESS; // // Special-case killing WOW tasks // CProcInfo * pProcInfo; pProcInfo = FindProcInArrayByPID(m_pProcArray, pid); if (NULL == pProcInfo) return FALSE; if (IsSystemProcess(pid, pProcInfo)) return FALSE; // Grab info from pProcInfo (because once we call QuickConfirm(), the // pProcInfo pointer may be invalid) INT_PTR fWowTask = pProcInfo->IsWowTask(); #if defined (_WIN64) #else DWORD dwRealPID = pProcInfo->GetRealPID(); WORD hTaskWow = pProcInfo->m_htaskWow; #endif // OK so far, now confirm that the user really wants to do this. if (!bBatchKill && (IDYES != QuickConfirm(IDS_WARNING, IDS_KILL))) { return FALSE; } // We can't use this pointer after QuickConfirm() is called. // NULL it out to prevent subtle bugs. pProcInfo = NULL; if (fWowTask) { #if defined (_WIN64) return FALSE; #else return VDMTerminateTaskWOW(dwRealPID, hTaskWow); #endif } // // If possible, enable the Debug privilege. This allows us to kill // processes not owned by the current user, including processes // running in other TS sessions. // // Alternatively, we could first open the process for WRITE_DAC, // grant ourselves PROCESS_TERMINATE access, and then reopen the // process to kill it. // CPrivilegeEnable privilege(SE_DEBUG_NAME); HANDLE hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, pid ); if (hProcess) { if (FALSE == TerminateProcess( hProcess, 1 )) { dwError = GetLastError(); dprintf(TEXT("Can't terminate process: %08x\n"), dwError); } else { TimerEvent(); } CloseHandle( hProcess ); } else { dwError = GetLastError(); } if (ERROR_SUCCESS != dwError) { DisplayFailureMsg(m_hPage, IDS_CANTKILL, dwError); return FALSE; } else { return TRUE; } } |
Is it possible you could name a process winlogon.exe or smss.exe to allow unkillable malware to run?
The code below gets the process ID of the currently selected process.
3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 | /*++ CProcPage::GetSelectedProcess Routine Description: Returns the CProcInfo * of the currently selected process Arguments: Return Value: CProcInfo * on success, NULL on error or nothing selected Revision History: Nov-22-95 Davepl Created --*/ CProcInfo * CProcPage::GetSelectedProcess() { HWND hTaskList = GetDlgItem(m_hPage, IDC_PROCLIST); INT iItem = ListView_GetNextItem(hTaskList, -1, LVNI_SELECTED); CProcInfo * pProc; if (-1 != iItem) { LV_ITEM lvitem = { LVIF_PARAM }; lvitem.iItem = iItem; if (ListView_GetItem(hTaskList, &lvitem)) { pProc = (CProcInfo *) (lvitem.lParam); } else { pProc = NULL; } } else { pProc = NULL; } return pProc; } |
This is an interesting discovery. I do wonder if this still exists in Windows 11. It could, and this could be exploited. This is why better coding standards are required.