使用 RtlSetProcessIsCritical“保护”您的进程
使用 Win32 内核函数将进程提升到系统关键状态

引言
RtlSetProcessIsCritical
是隐藏在Windows内核中的另一个未公开函数。 它是少数几个没有kernel32等效函数的函数之一。 然而,微软有充分的理由不公开这个函数 - 任何应用程序都不应该出于任何目的使用它。 我根本无法想象这种功能会真正有用的情况。 因此
免责声明:对于在您的计算机上调用此函数产生的任何副作用,我不承担任何责任。它可能导致极端的系统不稳定。 示例仅作为“概念验证”呈现。
背景
RtlSetProcessIsCritical
的作用是将您的进程设置为系统关键状态。这意味着该进程现在对Windows的运行至关重要,这也意味着当您的进程终止时,Windows本身也会终止。当系统关键进程结束/终止时,停止代码为CRITICAL_PROCESS_DIED
(0xEF)(进程退出),如果进程被异常终止,则为CRITICAL_OBJECT_TERMINATION
(0xF4)。 虽然从技术上讲,这可以用来“保护”一个进程不被人们终止,但我建议您寻找其他方法,因为如果用户意外终止了一个关键进程,或者一个进程在处于关键状态时崩溃,系统也会立即崩溃。 这对用户来说会非常恼人。
这种行为也可以在诸如 winlogon.exe, csrss.exe, services.exe, smss.exe, 和 lsass.exe等进程中看到。 所有这些进程都知道要调用 RtlSetProcessIsCritical
。
可以使用类为ProcessBreakOnTermination
(0x1D) 的ZwQueryProcessInformation
调用来获取进程是否为关键进程。 并且,此功能仅在NTDLL版本5.1及更高版本中可用。
Using the Code
RtlSetProcessIsCritical
的函数定义如下
NTSTATUS
RtlSetProcessIsCritical (
BOOLEAN bNew, // new setting for process
BOOLEAN *pbOld, // pointer which receives old setting (can be null)
BOOLEAN bNeedScb); // need system critical breaks
这意味着调用RtlSetProcessIsCritical(TRUE, NULL, FALSE)
将使进程变为关键进程,而另一次调用RtlSetProcessIsCritical(FALSE, NULL, FALSE)
将使进程恢复正常。 当设置关键状态时,以任何方式终止或结束该进程通常会导致 BSOD(如果启用了 BSOD),或者导致系统自行重启。
从内核中获取此函数很简单。 首先,我们定义该函数的原型
typedef long ( WINAPI *RtlSetProcessIsCritical ) (
IN BOOLEAN bNew,
OUT BOOLEAN *pbOld,
IN BOOLEAN bNeedScb );
然后,我们获取NTDLL.DLL的打开句柄,以便使用GetProcAddress
获取该函数
HANDLE ntdll = LoadLibrary("ntdll.dll");
RtlSetProcessIsCritical SetCriticalProcess;
SetCriticalProcess = (RtlSetProcessIsCritical)
GetProcAddress((HINSTANCE)ntdll, "RtlSetProcessIsCritical");
之后,我们可以简单地使用适当的参数调用SetCriticalProcess
。
更详细和注释过的示例在 Example.zip 下载中。
注意:使用此函数需要调用进程中的SE_DEBUG_NAME
特权。 这可以使用AdjustTokenPrivileges轻松获得,并且可以在示例源代码中看到一个示例。
关注点
我不确定其他编译器,但在我相当老的MSVC++ 6.0编译器上,我收到一个错误,指出“ESP的值在函数调用中未正确保存...”,并且该程序在默认的Release模式下也会在退出前崩溃。 如果您将优化更改为禁用(Debug),这些问题就会消失。 我猜VC++ 6.0的一些优化不能正常工作。
历史
我可能不会更新这个,除非代码中存在关键缺陷。
- v1.0 - 2009年10月30日