Thursday, March 1, 2012

The "RtlSetProcessIsCritical" function is one of the ntdll.dll undocumented functions, which can be very useful for software protections and malware.

The function has the following prototype:int __cdecl RtlSetProcessIsCritical(bool IsCritical, bool* pOld,void* u);

It is easy to see from the function prototype that if the function is called with the first parameter set to true, the process becomes critical and vice versa. For those who don't know, if a process is critical and it crashes or gracefully exits, the whole system is taken down after a blue screen of death is displayed.

The interesting thing about the code in the image above is that if it is run in OllyDbg, the system crashes upon any attempt to terminate the process or OllyDbg, while this does not happen if the code runs without a debugger. The reason behind this behavior is that the "RtlSetProcessIsCritical" function requires the debug privilege, SeDebugPrivilege, to come into effect and OllyDbg passes this privilege down to its debuggees. This can be very useful for anti-debugging, since any failed debugging attempt e.g. failure to handle an exception due to the author-defined unhandled exception filter not being called, would result into taking down the whole system.

I have seen some anti-anti-debug plugins, which patch OllyDbg process memory to prevent it from acquiring the debug privilege and subsequently depriving debuggees from inheriting that privilege and becoming critical. To circumvent those plugins, we can explicitly acquire that privilege by calling the "AdjustTokenPrivileges" function with the appropriate parameters. The only drawback here is that any crash to our process or any graceful termination attempt would result in a blue screen of death. We can take care of this by patching the "ZwTerminateProcess" function or any similar technique.

Side note:
The "RtlSetProcessIsCritical" function is just a wrapper of the "ZwSetInformationProcess" function with the "ProcessInformationClass" parameter set to 0x1D.

In response to some malware, i have created an OllyDbg plugin to handle such situations. The plugin simply calls the "ZwSetInformationProcess" to detox (remove criticality of) the process being debugged and thus safely debugging it without caring about the more likely debugging crashes.

Bypassing that is easy. RtlSetProcessIsCritical is nothing but a wrap up of the "ZwSetInformationProcess" function with the "ProcessInformationClass" parameter set to ProcessBreakOnTermination 0x1D. We can then call ZwSetInformationProcess after acquiring a handle to the naughty process. Otherwise, we can just create a remote thread into the process that tries to deprive it from the SeDebugPrivilege.

#1 Yea, that too would by-pass it. Just saying that if you are looking at some malware or whatever, its probably easier to just terminate smss. No code required.

#2 Ah right, its SeShutdownPrivilege and not SeDebugName, my bad. Also, you wouldnt know when to call NtRaiseHardError(), since your process would be terminated at that point =) So im not really sure what I was thinking.

Guess you could elevate SeShutdownPrivilege if you have SeDebugName set, spawn yourself twice and have both processes wait for each other, and raise the error if either one dies. Like 10x more code but would achieve the same result, a be bit a little bit trickier to disable.

Read all your articles now, very high quality and they make for some interesting reading :)