Kernel drivers and Valorant

5 Apr 2020

Just when you think the Internet can’t get any more stupid, you get something like this.

There’s a group of people claiming that Valorant contains a rootkit and can do all kings of nasty things to your system.

Before I get into the more interesting stuff, a TLDR for those that don’t want to read everything:

Now for the more interesting stuff.

What’s a rootkit

A rootkit is a bit of software that hides itself on your system and prevents attempts to remove it. This usually involves a kernel driver, which is used to hide the rootkit from the user and the rest of the operating system.

Common ‘root-kitty’ things to do are to adjust the process list (so you don’t know it’s running) and to hide files/directories where they keep data. Hiding files in this sense doesn’t mean setting the hidden flag, it means intercepting the filesystem calls and re-writing them to remove them.

If done correctly it’s also impossible to detect a rootkit when the system is running, your only option is to take the disk/SSD out and look at it using another machine.

Vanguard makes no attempt to hide itself and you can uninstall it easily, which makes anyone calling it a rootkit an idiot.

Drivers in general

Once upon a time all drivers were kernel drivers, and on some operating systems (OSs) they still are (I believe Mac OS still lacks a usermode driver framework, and most Linux drivers are either compiled into the kernel or loaded as modules into it).

Drivers are a piece of software that your OS uses to talk to (usually) hardware. They contain all of the low-level specific stuff and expose a standard interface to the OS, so under Windows your graphics driver exposes a WDDM API that Windows uses to do graphics stuff.

By being separate, drivers can be added and updated without having to change or recompile the kernel (other early Linux users will know the fun this could be), and it also means you don’t have stuff in memory that you don’t need, which is good from both a space and security point of view.

Now while drivers tend to be used to talk to hardware they don’t have to be, you can have drivers that just pretend to be hardware, like the virtual microphone and speakers used in Steam-link.

You’ll find plenty of drivers on a modern Windows machine, some are part of Windows and some are extra stuff you’ve installed along the way. Under Windows drivers are actaully just a Service that has a DLL rather than an executable as their image. They don’t show up in the services list or with Get-Service in powershell, but if you look under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services you’ll find them.

Execution states

Before we get into kernel drivers we need to talk about CPU execution states.

x86 CPUs have different levels, called rings, they can run at from 0 to 3, and some instructions and parts of the CPU can only be adjusted if it’s at or below a value.

At ring 0 you can do anything you want, and the ‘higher’ ones remove features, however most OSs only use 0 (for the kernel) and 3 (for everything else). When the machine boots it starts at ring 0, then when the OS wants to switch to a user process it drops ‘down’ to 3 and lets the other code take over.

So you might be wondering how we get back to ring 0 when we need to do kernel stuff. Well that’s via a special instruction that does two things: jump to a fixed location in memory, and switch back to ring 0. Since the code it jumps to can only be changed when running in ring 0, the user process can’t change what happens afterwards, it just leaves a message in a fixed place and gives up control.

The other important limit we have in ring 3, at least for this article, is the virtual memory system.

A simple version of what’s going on is to imagine that every process running in the OS gets it’s own view of RAM. It can only see the parts that the OS lets it, enforced by the CPU, and it thinks it’s the only thing running.

This means one process can’t peek at what another one is doing, without getting help from the OS, so your browser can’t see what’s in your email clients memory.

Kernel and user-mode drivers

To show that it’s not just rootkits lets have a look at what’s on my system, compared to a clean install of windows in a virtual machine. Removing some that are part of Windows I’m left with about 55 drivers, including…

\??\C:\Program Files (x86)\MSI Afterburner\RTCore64.sys
\??\C:\Program Files\AMD\RyzenMaster\bin\AMDRyzenMasterDriver.sys
\??\C:\Program Files\NVIDIA Corporation\NvStreamSrv\NvStreamKms.sys
\??\C:\Program Files\Riot Vanguard\vgk.sys
\??\C:\Windows\system32\Drivers\SIVX64.sys
\SystemRoot\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_63268710a2dc3648\nvlddmkm.sys
\SystemRoot\System32\drivers\arturiausbmidi.sys
\SystemRoot\System32\drivers\arturiausbmidiks.sys
\SystemRoot\System32\drivers\nvvhci.sys
\SystemRoot\system32\DRIVERS\npcap.sys
\SystemRoot\system32\DRIVERS\nvnusbaudio.sys
\SystemRoot\system32\drivers\ftdibus.sys
\SystemRoot\system32\drivers\nvhda64v.sys
\SystemRoot\system32\drivers\nvvad64v.sys

These all look like kernel drivers (checked by opening them in Ghidra and seeing if they have the UDMF entry points or not), and you might be able to guess who wrote some of them. In terms of size, the largest is the driver for my graphics card, which is about 20MB.

Threat model and risks

Now we’ve gone through all of that I’m now going to tell you why it mostly doesn’t matter that Vanguard has a kernel driver.

Lets break things down into three groups and what the risks are with each. One thing you need to remember is that as we go up the levels, each one gets to do everything in the ones below.

You run software on your machine without installing it

At this point the software can’t change your OS, assuming there isn’t a bug that lets it elevate, so it can’t do anything too nasty.

However it’s running as you, so everything you can access it can. This means all your files on the machine, browser history, and potentially any unsecured machines on your network. It can also make outgoing network connections which you can’t stop because it’s an online game that needs to talk to other machines to be played.

If you are worried about someone stealing your data, you can’t run anything from them with the same user account, they don’t need a background service or kernel driver to do that.

The only way of stopping this is too have multiple accounts on your machine, one for using untrusted software, and another for everything else, and then make sure your machine (and all the other software on it) is kept up to date.

Software running un-elevated can’t access memory from other processes, but it can stop any you started and start other code to hang around longer.

You run an installer that elevates

Once you let an installer through a UAC prompt, those things that darken the screen and ask you to say if things to happen or not, things get more interesting (even though UAC isn’t a boundary in the Windows security model, that’s why you should always have a non-admin account for normal use).

Once it has these elevated right it can start making changes to the OS.

All of these changes are visible, they’re not hidden (that’s why a rootkit has a kernel driver after all).

One of the most common is to add a service to Windows. These are just bits of software that run in the background, usually as special users, so they don’t tend to run as you. There’s lots of places to start these from in Windows, and the best tool for looking at them is AutoRuns.

Depending on how a service is created it can run with less rights then a normal user (e.g. no network access), or full administrative rights (they run as the SYSTEM user).

A service running as SYSTEM, or a user with equivalent permissions, can read any file on the system and make any changes it wants to the OS. Again, none of these changes are hidden, if you know what you’re looking for, but they are done without asking you for permission again.

At this point using another user account on the system isn’t going to help you, unless your files are encrypted and the service can’t compromise the tool you user to access them. In other words, don’t bet on encryption working against an attacker that’s expecting it.

At this point it’s also possible to inject a driver into Windows so you can start reading other processes memory via the debug interfaces, which is what most game cheats will try to do.

The software installs a kernel driver

So we can already do everything above, which I think covers 99% of the scare stories I’ve seen online, so what does the kernel driver give us?

From a capabilities point of view it’s mostly the ability to intercept OS calls, poke hardware directly, and be harder for non-kernel code to touch. You see, if another bit of code tries to load a driver to get debug access you can stop that as a kernel driver. You can also stop it from trying to replace processes you trust with versions that you don’t.

Of course, if the attacker decides to write their own kernel driver to attack your then things get interesting, but that makes things more expensive for the attacker.

Real risks

If you’re worried about Riot stealing all your data, then the kernel driver doesn’t really give them anything they don’t already have if you run code from them.

The real risk, and why security researcher don’t like them, is that a bug could give an attacker the ability to get code running in the kernel without first getting administrative rights.

If they really screwed up and say, exposed a direct memory fiddling interface that any process running on the system could use, then you would have a real problem. That might seem like a stupid example, but at least two motherboard manufacturers did exactly that on the drivers they used to control the lights on their products.

So far Riot’s reponse to the risks looks sensible. They’ve had external audits of the code done, to try and make sure there are no mistakes, and are offering bug bounties for expliots found.

Some people seem to be confused about bug bounties, claiming that it’s a risk offering them and makes it more likely they’ll get attacked, but this is just silly.

Pretending your code is perfect doesn’t help, what you want to do it find bugs and fix them, but if it’s profitable to keep them secret (and use them for malware or cheats) then you’ll never know.

The bad guys are always going to look for bugs, this way the good guys have an extra incentive to do it, as well as making some of the more grey-hatted members of the community think twice before selling an explit to cheat makes, who probably won’t pay $100,000 for one as they’ld find it hard to make it back.