Can we find the digital signature of the user-mode app inside our kernel mode WDM dispatch function, and check it to make sure the executable file of the user-mode process has our own certificate/signature or not? If so, how can i do this in kernel mode inside my dispatch function? for example inside the handler for irp_mj_device_control, how can i check the digital signature of the user mode app that is sending me the ICOTL?
Therefore make sure that only a executable with our own digital signature can communicate with us.
@antsteel said:
Even if you could do this, someone could still load a DLL or inject code into your process, so you would need to prevent that as well.
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.
my main concern right now is to how to properly check the digital signature of a user mode process that send the IOCTL to my driver, in my kernel code?
The short answer is that you donât. The long answer is much longer, but if you are trying to implement some kind of âtrustedâ process scheme, your viable options are to call out to a hypervisor or external hardware. beyond the ACL, donât try to implement this kind of security. you will make a lot of very complex code that does not improve your security except with respect to obscurity.
@Mark_Roddy said:
âcheck the digital signatureâ is going to have to be done in user mode, so you will need to pass that request up to a service.
What is the best way to find who the certificate is issued to and if the certificate is valid, in user-mode? i assume combining WinVerifyTrust + CertGetCertificateChain will work?
@MBond2 said:
The short answer is that you donât. The long answer is much longer, but if you are trying to implement some kind of âtrustedâ process scheme, your viable options are to call out to a hypervisor or external hardware. beyond the ACL, donât try to implement this kind of security. you will make a lot of very complex code that does not improve your security except with respect to obscurity.
May i ask why? assuming i am also protecting my user-mode process, how can someone bypass this and communicate with my driver then?
using hypervisor and external hardware is not an option for me.
i need to be 100% sure that no other application can communicate with my driver (for example by reversing my code and finding out the encryption method for communication, etc), and I think this is the best way, since only i have the certificate.
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.
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.
@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.
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âŠ
@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.
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)