65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 RtlSetProcessIsCritical“保护”您的进程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (14投票s)

2009年10月31日

CPOL

3分钟阅读

viewsIcon

85190

downloadIcon

3697

使用 Win32 内核函数将进程提升到系统关键状态

Example

引言

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日
© . All rights reserved.