The Windows kernel is a rich environment where countless drivers execute on a typical system, and where thousands of variables containing worldwide state are present. For advanced troubleshooting, IT specialists will typically use tools like the Windows Debugger (WinDbg), SysInternals Tools, or compose their own. Unfortunately, use of those tools is getting increasingly challenging, and they are themselves limited by their particular access to Windows APIs and exposed attributes.
Some of today’s challenges include:
- Windows 8 and after support Secure Boot, which prevents kernel debugging (including local debugging) and loading of test-signed driver code. This restricts troubleshooting tools to those who possess a signed kernel-mode driver.
- On systems without Secure Boot empowered, allowing local debugging or altering boot options which ease debugging capabilities will often activate BitLocker’s retrieval manner.
- Windows 10 Anniversary Update and later include much stricter driver signature demands, which currently enforce Microsoft EV Attestation Signing. This limits the freedom of software developers as generic”read-write-everything” drivers have been frowned upon.
- Windows 10 Spring Update now includes customer-facing options for enabling HyperVisor Code Integrity (HVCI) which further limits allowable drivers and blacklists multiple 3rd party drivers that had”read-write-everything” capacities because of poorly written interfaces and security risks.
- Technologies such as Supervisor Mode Execution Prevention (SMEP), Kernel Control Flow Guard (KCFG) and HVCI with Secondly Level Address Translation (SLAT) are creating traditional Ring 0 execution tricks’ obsoleted, therefore a new strategy is necessary.
In such an environment, it was obvious that a very simple tool which may be utilized as a crisis band-aid/hotfix and to quickly troubleshoot kernel/system-level problems which may be apparent by analyzing kernel condition might be valuable for the community.
How it Works
R0ak works by redirecting the implementation flow of the window manager’s trustworthy font validation tests when trying to load a new font, by substituting the font table’s comparator pattern with another purpose which schedules an executive function thing (
WORK_QUEUE_ITEM) saved from the input node. Then, the font table’s right kid (that serves as the origin node) is overwritten with a named pipe’s write buffer (
NP_DATA_ENTRY) where a custom function item is saved. This thing’s underlying worker function and its parameter are exactly what will be executed by a committed in
PASSIVE_LEVELonce a ribbon load is attempted and the comparator routine executes, getting the title pipe-backed parent node as its input. A real-time Event Tracing for Windows (ETW) trace event is used to receive an asynchronous notification that the work item has finished executing, making it secure to tear down the structures, free the kernel-mode buffers, and restore normal operation.
When using the option
--implement , this function and parameter are supplied by the user.
--compose a custom gadget is used to alter arbitrary 32-bit values everywhere in kernel memory.
--read the compose gadget is used to alter the system’s HSTI buffer pointer and size (N.B.: This is damaging behavior regarding any other software that will ask the HSTI data. As this is optional Windows behavior, and this instrument is intended for emergency debugging/experimentation, this reduction of information was considered acceptable). Then, the HSTI Query API is used to copy back into the program’s user-mode address space, and a hex dump is shown.
Because merely built-in, Microsoft-signed, Windows functionality is used, and all called functions are a part of their KCFG bitmap, there is no breach of any safety checks, and no debugging flags are required, or usage of 3rd party poorly-written drivers.
Because of the usage of the Windows Symbol Engine, you have to have either the Windows Software Development Kit (SDK) or Windows Driver Kit (WDK) installed with the Debugging Tools for Windows. The tool will search your setup route automatically, and leverage them
SymSrv.dll are present in that directory. Because these documents aren’t re-distributable, they cannot be contained with the release of the tool.
Alternatively, if you get these libraries by yourself, you can modify the source-code to utilize them.
Usage of symbols requires an Internet connection unless you’ve pre-cached them locally. Moreover, you ought to set up the variable
_NT_SYMBOL_PATH pointing to an appropriate symbol server and cached location.
It’s supposed that an IT Expert or alternative troubleshooter which apparently has a need to read/write/execute kernel memory (and has knowledge of the right kernel variables to access) is already more than familiar with the above setup requirements. Please don’t file issues inquiring exactly what the SDK is or how to set an environmental variable.
- Some driver leaked kernel pool? Why don’t you telephone and
ntoskrnl.exe!ExFreePoolmove into the kernel address that is leaking? What about an object reference? Go call and
ntoskrnl.exe!ObfDereferenceObjectalso have that cleaned up.
- Wish to dump the kernel DbgPrint log? Why not ditch the inner circular buffer in
- Wondering how large the kernel stacks are in your own machine? Try taking a look at
- Want to dump the system call table to search for hooks? Go print out
These are just a few examples — all Ring 0 addresses are approved, either by syntax
module!symbol or directly passing the kernel pointer if understood. The Windows Symbol Engine is used to look up these.
The application requires certain kernel variables and functions which are known to exist in modern versions of Windows 10 and was just meant to operate on 64-bit systems. These limitations are due to the fact that on older systems (or even x86 systems), these more rigorous safety requirements don’t exist, and therefore, more conventional approaches may be used alternatively. This is a private tool which I am making accessible, and that I had no requirement for these older systems, where I could use a simple driver instead. That having been said, this repository takes pull asks, if anyone is interested in porting it.
Secondly, due to the use cases and my needs, the following restrictions apply:
- Reads — Limited to 4 GB of data at a time
- Writes — Limited to 32-bits of Information at a time
- Executes — Limited to functions which just require 1 scalar parameter
Obviously, these constraints could be fixed by programmatically choosing a different strategy, but they match the needs of a command line tool and my use cases. Again, pull requests are approved if others want to donate their own developments.
Be aware that all execution (including implementation of this and
--write controls ) happens in the context of a System Worker Thread in.
PASSIVE_LEVEL Therefore, user-mode addresses shouldn’t be passed in as parameters/arguments.
r0ak v1.0.0 -- Ring 0 Army Knife http://www.github.com/ionescu007/r0ak Copyright (c) 2018 Alex Ionescu [@aionescu] USAGE: r0ak.exe [--implementmodule.ext!function> ] [–compose module.ext!function> ] [–read module.ext!function> ]