We are currently developing a security software for Windows. This application consists of a service running in user mode and a driver in kernel mode. These two need to communicate, so that the service can get data from the driver and send actions to perform. The communication is implemented using IOCTL.

The problem is, how we should secure this communication, so that no 3rd party software can abuse this.

From the documentation I've learned to set permissions to the device-file, but these are very limited. We can only grant permissions to the admin-group or the SYSTEM account.

The service itself does not need elevated privileges and we therefore don't want to run the service with too much rights (principle of least privilege...)

Our approach now is to create a local user with restricted privileges that runs the service, like it is often done in Linux.

We can also get the user from the IOCTL calls and by comparing them to the expected user, we are able to 'grant' and 'deny' access.

The question now is, is this approach secure? Or does it have flaws we do not see? Because we could not find anyone following this approach.


Considerations we have taken (assuming the user's password is secret): as a normal user you cannot pretend to be the app-defined user and therefore you can't communicate with the driver. An Admin/SYSTEM has this possibility (at least the password can be changed). But an Admin/SYSTEM could also communicate with the driver if the permissions on the device are set.

There are ELAM (early launch anti malware) drivers that can launch protected processes. This would probably solve the problem, but right now we would not get the required certificates from Microsoft.

1 Answer 1


If the service doesn't need to run as any specific user, it should run as its own user or, more accurately, as a service account, potentially a virtual account. Unlike user accounts, service accounts don't need the permission to log into the machine except as a service, but otherwise are broadly similar; you can define access control entries for them in any ACL (including on driver objects), they can have their own private locations in the file system and private registry hive, etc.

There are three built-in service accounts on Windows, though you can also create your own (either through a domain controller or locally). The built-in ones - which are used widely both by services that come with Windows and by third-party services - are Local Service, Network Service, and LocalSystem (pretty sure they aren't case-sensitive; I've seen it written as LOCALSYSTEM and such too). The first two have privileges similar to (but not quite the same as) a normal user account. The last has every privilege a process can have, including some that even the built-in Administrator account doesn't get by default. Of course, these are shared accounts; if a service running in one of these accounts is malicious or gets compromised, it can see and do anything that any other service in that account could see or do.

Virtual accounts are intended to be more convenient than custom-made service accounts, but provide similar levels of security. You don't create or manage passwords for them, don't need to manually create them or set them up for service login, and in general they are supposed to "just work". They are only available on Win7 / Server 2008 R2 or later, though. Starting with Vista / Server 2008, every single service automatically has a unique security identity (SID) that is distinct from other SIDs (such as for users, computers, integrity levels, AppContainer capabilities, etc.). This service SID is based on the name of the service (the actual service name, not the display name; it is in fact possible to get the service SID for a service that doesn't even exist, if you know what it'd be called). In Win7 and later, it is possible for a service to use this SID as a "virtual account" (the service "logs in" to an account named NT SERVICE\<servicename>, as opposed to Local Service or similar).

In the scenario you describe, I would recommend setting the ACL (using SDDL, via whatever framework you're using to create the driver) on the driver's device object so that only NT SERVICE\<servicename> (and possibly the localsystem account, which can override or ignore ACLs anyhow) can access the device. This will work whether or not the service is "logging in" using that virtual account; it will have that SID regardless (a process' security token can - and almost always does - have multiple SIDs). Adding an additional check of getting the calling process' user and comparing it to the expected service account (virtual or otherwise) probably won't do any harm, but shouldn't be necessary (though be sure to write tests, including "negative" tests that are supposed to fail with Access Denied errors!)

  • I didn't know about this virtual accounts or the service specific SIDs, cool. So, for my clarification. A setup would essentially consist of the following steps: 1) Install the user mode service. 2) get the service SID (S-1-5-80-...) for this service. 3. Set this SID in the inf-file of the driver and specify the SDDL. 4. Install the driver using this inf file. The modification of the inf file does not break the signature, does it? Jun 27, 2019 at 14:34
  • You can pre-compute the service SID. It's based on the service name, and is the same for a given name across all Windows versions that support service SIDs at all. The service doesn't need to be installed (or exist at all) yet to get the SID; I'm pretty sure it's just S-1-5-80-{some-hash-of-the-name}. Therefore, your installer can have the service's SID already built in, and there's no need to run steps 2 or 3 at install time at all.
    – CBHacking
    Jun 27, 2019 at 19:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .