Checking the user-mode app's digital signature for secure communication with the user-mode?

To protect your code against reverse engineering you can use tools like VMProtect, Code Virtualizer or Enigma Protector. They all can run your critical code in custom VMs with custom RISC Processor instruction sets. You can even protect your critical driver code (VMProtect works best). It still can be cracked but the bar is now much higher.

If the idea is to lock-down the user to driver interface, may I suggest using a Service SID with an appropriate ACL on your Device Object?

Peter

@Tim_Roberts said:
You can never be 100% sure. Whatever you do in user-mode can be cracked. So, you do the best you can.

Well i still believe that this approach will 100% block any unauthorized process from communicating with my driver.
And this is assuming that i protect my own process and executable files from modification. if so, then how can anyone bypass this? its technically not possible. they cant just forge my certificate and sign with it.

@“Peter_Viscarola_(OSR)” said:
If the idea is to lock-down the user to driver interface, may I suggest using a Service SID with an appropriate ACL on your Device Object?

Peter

I dont want to lock down the user mode to driver interface, i mostly want to make sure ONLY my own process/executable can communicate with my driver and issue commands to it.

@pwilly said:
To protect your code against reverse engineering you can use tools like VMProtect, Code Virtualizer or Enigma Protector. They all can run your critical code in custom VMs with custom RISC Processor instruction sets. You can even protect your critical driver code (VMProtect works best). It still can be cracked but the bar is now much higher.

I don’t think using VMProtect on a driver would be 100% stable, specially for drivers. haven’t seen it being used on production drivers before. and still this will only make their job harder, but still not impossible for them to bypass.

@“Wilhelm_Nöker” said:
To establish trust in some particular user-mode executable for your driver, Authenticode signatures are not required. You can use public/private key authentication based on the CNG BCrypt* functions (which are available in user-mode and kernel-mode as well):

  • Identify the process that is sending you IOCTLs and the executable file from which it was loaded. (To be honest, I have no idea if this step is trivial or already a problem of its own.)
  • Calculate a hash of this executable file, using BCryptHashData() etc.
  • Locate the signature associated with your preferred executable. (This value will have been calculated during the final steps of building your product setup package, and your installer may have placed it anywhere, for example in the registry.)
  • See if this signature matches your calculated hash, using BCryptVerifySignature().

Regarding the required BCrypt operations, there is a complete sample on GitHub. It uses the DSA signature algorithm, the one algorithm apparently not supported in kernel-mode, but I suppose it will work with other algorithms like BCRYPT_RSA_ALGORITHM just as well.

But isn’t doing the combination of WinVerifyTrust + CertGetCertificateChain from user-mode easier?

**Now regarding getting the the path to the executable that send me the IOCTL : **

If i use PsGetCurrentProcess in my IRP_MJ_DEVICE_CONTROL dispatch function, will it always give me the EPROCESS for the process that send the IOCTL? because if so, then i can easily get the process path from there.

I dont want to lock down the user mode to driver interface, i mostly want to make sure ONLY my own process/executable can communicate with my driver and issue commands to it.

Sorry… how are those two things (“locking down the user-to-driver interface” and “mak[ing] sure ONLY my own process/executable can communicate” with a given driver) different? What am I missing? You’re trying to secure the channel against admin privileged users, so using a Service SID won’t work?

If i use PsGetCurrentProcess in my IRP_MJ_DEVICE_CONTROL dispatch function, will it always give me the EPROCESS for the process that send the IOCTL?

Well, yes or no, depending on how paranoid you want to be. And you seem to want to be very paranoid indeed, so “no” – You can’t be 100% guaranteed that your Dispatch Entry Point will be called in the context of the requesting thread/process if there’s a filter driver instantiated above your Device Object.

But you don’t need to do this… you can get the issuing THREAD from the IRP at Irp->Overlay.Thread – This will be set for IRPs sent from user mode… so be sure to guard against NULL in this field by first checking Irp->RequestorMode.

Peter

I’m reminded of the Sherlock Holmes story with the dancing man code - what one man can devise another may can decipher. That may not be an exact quote as it is entirely from memory

The import for this particular problem is that any security scheme that you devise, I can always break.
If necessary, we can go into specifics on the approaches that you mention but that’s axiomatic. But the important question is how difficult will it be for me to do so and whether I have the skill. Ask the NSA how much motivated and skilled people can do.

The conclusion is that you have to trust something at some point. And you should trust the OS and the security system built into it. And that means that you should assign an appropriate ACL and call it a day. Because every effort after that provides only illusory increases in security. If I have admin access, I can replace your driver with a decompiled version that omits your check if I want

@brand_H: I don’t think using VMProtect on a driver would be 100% stable, specially for drivers. haven’t seen it being used on production drivers before. and still this will only make their job harder, but still not impossible for them to bypass.
That you haven’t seen it doesn’t mean it doesn’t exist. You wouldn’t see if the driver is protected with VMProtect unless you carefully analyze the driver binary. From our experience it works very well and stable, not a single issue so far.
@MBond2: If I have admin access, I can replace your driver with a decompiled version that omits your check if I want.
If your driver is protected with VMProtect, decompiling is so much harder. You would need to decrypt the driver boot loader and than the VM with it’s custom instruction-set, Then track down all the garbage instructions injected with code mutation and then make sense of it. It can be done, but you need very skilled experts and a lot of time (and money) to do this.
However nothing is 100% secure and anything can be hacked, it’s more a matter of how difficult you make it.

@brad_H said:
I can easily block any malicious user process from even opening a handle to me with ObRegisterCallbacks, let alone injecting into it, blocking this issue is pretty easy. i can also register my process as a protected process.

This keeps honest processes honest. It’s not a guarantee that code that doesn’t play by the rules can’t compromise your process.

@brad_H said:
Well i still believe that this approach will 100% block any unauthorized process from communicating with my driver.
And this is assuming that i protect my own process and executable files from modification. if so, then how can anyone bypass this? its technically not possible. they cant just forge my certificate and sign with it.

This is true. It is also mostly useless. It’s not the at-rest representation you need to worry about, it’s the in-memory image, with all of the address fix-ups and data values, (and possibly injections), that matters. And you won’t be able to assert a lot of that, because of the image in memory will look pretty different than it will on-disk.

@MBond2 said:
I’m reminded of the Sherlock Holmes story with the dancing man code - what one man can devise another may can decipher. That may not be an exact quote as it is entirely from memory

The import for this particular problem is that any security scheme that you devise, I can always break.
If necessary, we can go into specifics on the approaches that you mention but that’s axiomatic. But the important question is how difficult will it be for me to do so and whether I have the skill. Ask the NSA how much motivated and skilled people can do.

The conclusion is that you have to trust something at some point. And you should trust the OS and the security system built into it. And that means that you should assign an appropriate ACL and call it a day. Because every effort after that provides only illusory increases in security. If I have admin access, I can replace your driver with a decompiled version that omits your check if I want

Well, as i said, in this scenario lets assume that i can protect my files and processes from modification (since I’m already in kernel and we assume the attacker doesn’t have a driver, if he did then its obviously game over)

In this scenario, if i am checking the digital signature of the process that is sending me the IOCTL, you CANNOT bypass is, literally. Okay maybe if i used SHA-1 then there is a small chance, but if i am using a SHA-2 digital signature, you CANNOT, and i repeat, CANNOT bypass this without having some sort of super computer to forge my digital signature… I am more than happy to see if you can provide me any type of attack that can bypass my protection.

And again, we assume that the attacker doesn’t have a driver to begin with, and wants to use the functionality of my driver for exploit or something else, and we assume that i am properly protecting my processes and files using callbacks and minifilters, in this scenario i am 100% sure you cannot bypass this and communicate with my driver unless you break SHA-2…

@pwilly said:

@brand_H: I don’t think using VMProtect on a driver would be 100% stable, specially for drivers. haven’t seen it being used on production drivers before. and still this will only make their job harder, but still not impossible for them to bypass.
That you haven’t seen it doesn’t mean it doesn’t exist. You wouldn’t see if the driver is protected with VMProtect unless you carefully analyze the driver binary. From our experience it works very well and stable, not a single issue so far.

But Have you seen VMprotect or similar VM based obfuscator being used in any known production driver, other than those crazy Anti-Cheat companies? I assume some of them could be using this, but as far as i heard they do so many crazy undocumented stuff that shows they really don’t care about producing a stable driver, so I’m excluding them from this question.

For example have you seen any Anti virus company use VMprotect? I’m pretty sure non of them do, because they want to have a stable driver.

@“Peter_Viscarola_(OSR)” said:

I dont want to lock down the user mode to driver interface, i mostly want to make sure ONLY my own process/executable can communicate with my driver and issue commands to it.

Sorry… how are those two things (“locking down the user-to-driver interface” and “mak[ing] sure ONLY my own process/executable can communicate” with a given driver) different? What am I missing? You’re trying to secure the channel against admin privileged users, so using a Service SID won’t work?

But why should i use Service SID, when i can use the digital signature of the executable and be 100% sure that no other executable can communicate with me? I’m not saying using Service SID is bad, But obviously digital signatures, specially SHA-2, are mathematically proven to be extremely hard (if not Impossible) to forge/bypass. so why shouldn’t everyone use this approach to be 100% sure?

This topic is important, because i think as you know, the amount of drivers out there that are not properly checking the ICOTLs, and therefore making their drivers exploitable, is vast, and driver developers really need to come up with a solid plan that can block any type of unauthorized user mode app from communicating with them, that can be proven to be impossible to bypass (or at least block 99.99999% of attacks)

@brad_H: But Have you seen VMprotect or similar VM based obfuscator being used in any known production driver…?
Well, we use it in production since a couple of years, never had any issues. We protect only a few critical functions to protect our IP from reverse engineering.

@brad_H said:

@“Wilhelm_Nöker” said:
To establish trust in some particular user-mode executable for your driver, Authenticode signatures are not required. You can use public/private key authentication based on the CNG BCrypt* functions (which are available in user-mode and kernel-mode as well):

But isn’t doing the combination of WinVerifyTrust + CertGetCertificateChain from user-mode easier?

Like you said, it’s user-mode, and the result is needed in your driver. But if you’re comfortable with the techniques required to have a driver delegate some task to a user-mode component, then sure, it’s easier that way. I was suggesting a technique that could run completely in kernel-mode.

**Now regarding getting the the path to the executable that send me the IOCTL : **

If i use PsGetCurrentProcess in my IRP_MJ_DEVICE_CONTROL dispatch function, will it always give me the EPROCESS for the process that send the IOCTL? because if so, then i can easily get the process path from there.

I’ve used PsGetCurrentProcess myself in a COM port driver to let an associated diagnostic tool know which process is keeping the COM port open, and it’s certainly good enough for that purpose. But I did most of the remaining work in user-mode (OpenProcess, EnumProcessModules, GetModuleBaseName), so I just don’t know how this would be done in kernel-mode, and whether it’s easy or not. That’s all.

Well, let’s assume that you can actually protect your files and processes - so what more do you need to do? What extra value does this scheme provide?

If a system administrator is determined enough and skillful enough, he will break anything that you attempt to do. The folks at the NSA have proved this point by pre-calculating all of the possible prime factors for common RSA encryption strengths - and that’s what we know that they could do about 10 years ago.

and what does verifying an on disk image versus a signature have with respect to a loaded module that must necessarily have DLL imports and thunks resolved? Even if the on disk signature is valid, any in process or out of process actor can arbitrarily change the behavior of the binary by replacing the code bytes. And those changes can’t be detected by checking the signature of the disk image, and checking the ‘signature’ of the in memory image is impossible, so what’s the plan?

This may thwart the most infantile attacks - but so does a simple ACL. And it will fail utterly under sophisticated attacks - as will a simple ACL. Possibly achieving some nebulous mid level attack protection at the cost of a huge amount of extra complexity?

@brad_H

In this scenario, if i am checking the digital signature of the process that is sending me the IOCTL, you CANNOT bypass is, literally.

This is incorrect. First of all, an admin can install any driver and circumvent any protection you will come up with, and this is pretty easy when there are many third party signed drivers that simply provide an IOCTL interface to read/write memory in kernel mode - you don’t even have to sign your own driver. This allows the attacker to install any driver and “remove” your ObRegisterCallbacks protection for example or do whatever he wants.

Moreover, You will soon realize that the suggested “ObRegisterCallbacks protection” is never a 100% protection since there are legitimate windows services that need to open a handle to your process for all sorts of purposes, so you will have to allow them to open a handle if you don’t want to cause serious system instability - meaning that if someone injects to these processes (such as a critical svchost) he will be able to inject into your “signed” IOCTL caller from there.

What you are doing here is security by obscurity, which probably isn’t worth it (Depending on who you ask and on your specific requirements, different people have different opinions about this subject). You need to understand that if someone tried to write code to invoke an IOCTL in your driver, he will probably also be able to inject code to your “signed” process and run it from there if he wants - it’s not hard.

For example, just to show you these things are pretty easy and well known, look at this project here: https://github.com/notscimmy/libelevate

Just to summarize: If I were you, I would use an ACL to protect the device, and that’s it.

Also, Injection can be done without opening a handle to your process - I guess you have dependencies on DLLs in your “signed app” right? Remember an admin attacker can simply replace any DLL on disk with his own DLL…

@0xrepnz said:
@brad_H

In this scenario, if i am checking the digital signature of the process that is sending me the IOCTL, you CANNOT bypass is, literally.

This is incorrect. First of all, an admin can install any driver and circumvent any protection you will come up with, and this is pretty easy when there are many third party signed drivers that simply provide an IOCTL interface to read/write memory in kernel mode - you don’t even have to sign your own driver. This allows the attacker to install any driver and “remove” your ObRegisterCallbacks protection for example or do whatever he wants.

Although i agree that if a user is already an admin, at the end of the day he can always bypass protections, but you have to realize my goal here is not to secure a system from malicious users, but only to do my job as a driver developer of securing my communications. Just don’t want my driver to end up as one of those poorly written drivers that gets used by rootkits as a way to bypass driver signature enforcement. if i make it extremely difficult for them use my driver for malicious activities, then they will basically switch to another driver.

my goal here is not to secure a system from malicious users, but only to do my job as a driver developer

Then your efforts are being badly misdirected.

Put an ACL on you device object, as has been suggested here multiple times, and you’re done. That’s considered the standard for best practice. Anything beyond that is just window dressing, unless you want to go with a full-on threat analysis and a set of countermeasures focus on your identified threats.

Peter

Remember too that an admin can arbitrarily affect the way that signatures get checked and which ones are acceptable. Exceptions exist, but administrators routinely take advantage of this to trust their internal private certificates in addition to those that the public CAs provide.

An ACL check is no more or less secure than a signature check, but they check different things. A signature check is like a more sophisticated CRC - excellent for detecting corruption or unauthorized modification, but almost irrelevant for security. ACLs don’t even attempt to detect corruption, but they do enforce security across security boundaries. The assumption has to be made that the code enforcing the security boundary has not been compromised. Think about it and you’ll understand why

Just don’t want my driver to end up as one of those poorly written drivers that gets used by rootkits as a way to bypass driver signature enforcement

The main issue about “security” is that it’s almost always a trade-off with something else such as performance, reliability, stability, usability, etc. There is no supported way to perform “WinVerifyTrust” from kernel mode so basically implementing this will require a complex piece of code to develop, maintain and support. I think that in this case, the quality of your driver is much more important than stopping some rootkit developer from abusing your driver. As you said, they will simply move to the next driver they have so what’s the point? I think it’s not worth the potential issues you will encounter in this complex piece of code. Moreover, as we already agreed, this is not really any kind of security boundary you’re trying to protect here, it’s just a trick you want to do in order to “warn off” rootkit developers…