Rebooting from Kernel Mode

I see this question posted on OSR Online a lot: “How do I force a reboot of the computer from kernel mode?”. The clean solution always being recommended is to have a user-mode service that talks to the driver and does the appropriate ExitWindowsEx API call. But what if you really want to do it from kernel-mode? Well, you could use HalReturnToFirmware or NtShutdownSystem, but those functions are undocumented, and you probably won’t get WHQLed if you try using them. So I’ll show you a sneaky way that does the same, but uses a fully documented kernel API. Don’t use it unless you really know what you’re doing; I personally recommend using a service as well.

Rebooting a machine from kernel mode:


Now, I know what you’re thinking, but you’re wrong. This will *not* bugcheck the machine. It will actually call HalReturnToFirmware(HalRebootMachine), right after processing bugcheck callbacks. No BSOD, no crash dump, just a clean, simple, immediate reboot.

Enjoy 😉


I promised I’d blog about this little bugger, so here it is. It’s an amazing little API that’s pretty useful for various purposes. Let’s look at the definion first:

IN HANDLE Process,
IN PVOID CallSite,
IN ULONG ArgumentCount,
IN PULONG Arguments,
IN BOOLEAN PassContext,
IN BOOLEAN AlreadySuspended

You can already guess what this function does! Basically, it hijacks any thread of your choice into any process that you have access to, and sends the thread to a new “CallSite” by updating its EIP there. It also allocates a new ESP, and pushes up to 4 parameters at most. That’s somewhat similar to CreateRemoteThread, but notice that in this case we’re hijacking an existing thread, not creating a new one. Which means that once the CallSite has been hit, the thread will simply die.

So this is where the PassContext argument comes into play. If set to TRUE, then the function will also push the thread’s context before being supended and modified, on the new ESP. Therefore, if you control the routine on the other side, you can have it issue a NtSetContextThread(&Context), and the hijacked thread will return where it was executing. Be careful with waits though, since this will restart a wait.

Finally, the AlreadySuspended parameter is useful if your thread is already suspended, and you want to resume it yourself at a later time. Otherwise, the remote call is instant (as soon as the OS switches to the other thread).

So what’s all this good for? Turns out one great use is to build a sweet IPC (Inter-Process Communication) framework without resorting to LPC/RPC. I built a sample project that I’ll release soon, but the basic premise is that two threads, client and server, in different processes, are running. The server thread is always suspended, and loops around a NtSuspendThread call (for the case when it gets waken up). The server process has a special routine for incoming requests. The client process has a special routine for incoming replies. The client issues, at various times, InterAPI calls. These calls have 4 parameters, which is the maximum. The first is the actual Thread ID of the caller, the second is an API Number, and the last 2 parameters are specific to whichever API call is being done. The handler then calls the respective handler (based on a table, the API Numbers are indexes). To reply, the handler then issues a second RtlRemoteCall back to the client (to its reply routine). But how do we know the caller? That’s where the Thread ID comes in, since we can get a handle to it and its process by using NtQueryInformationThread. And how do we know the pointer to the callback routine? Let’s leave that as a surprise for the code.

This callback routine only takes one parameter, which is the return code. The callback then saves this return code in the TEB (guess where?), and issues an NtResumeThread, which will cause the caller thread to return. The caller thread can then read the return code from the TEB and return it to the caller of the InterAPI.

The code will be shown soon 🙂