I’m new to kernel-level development, so apologies in advance if anything below reeks of ignorance.
I’ve just begun writing a driver that will (eventually) be signed, distributed, and capable of making various changes to system state. Myself and others at my company don’t want malware (or really any userspace software that isn’t authored by us) to be able to use this driver to do bad things to our users. As such, I’ve been trying to come up with a way to authenticate processes that interact with the driver. The best way I can think to do this is to look up the executable that spawned the calling process whenever a new pid connects and then verify its Authenticode signature / metadata.
Sounds straightforward except that, to my dismay, it turns out all the Windows APIs for doing this exist only in userspace libraries. Apparently there’s not even basic cryptographic functionality in the XP kernel, which we are still required to support. Therefore, I’ve been looking for a way to invoke the Win32 functions I need from kernelspace. So far, I’ve found some undocumented functions that might let me queue a User APC to do the dirty work (ZwQueueApcThread / KeInsertQueueApc), but haven’t found any code samples that use these and I feel a little out of my depth trying to figure it out from scratch. I’d appreciate any guidance you all might have, either on how to implement the solution I’ve described or on alternate solutions to the problem.
Specific questions:
- Can I target individual Win32 functions with an APC somehow or am I going to need to inject a DLL into the calling process containing my verification routine? Are there good examples anywhere for doing this from kernelspace? I haven’t looked into this part much yet.
- Once an APC from the driver is queued, do I just need to let the calling thread return and SleepEx to let the APC run?
- Assuming I get past (1) and (2), is there a way to get the output/result of the APC from kernelspace in a way that can’t be tampered with?
- Is it a bad idea to use undocumented kernel functions like these in production drivers?
- Should I just reimplement the crypto and parsing logic I need in kernelspace instead of going out of my way to use the userspace functionality?
- Am I just being paranoid by worrying about what malware might do? Should I suffice with a privilege-level check and some basic password/handshake scheme even if it can probably be reverse engineered rather easily? How does everyone else solve this problem?