Sept 19 2017
A person creating an encrypted volume wants to keep the contents private, that is the whole point of encryption. But once the volume is mounted it becomes plaintext visible to any process running on the system. This is fine, provided the user has complete control over what is running. Alas, the current trends in software (especially true for operating systems) give more control to third parties and less to the owner of the device. It seems that Redmond (and Cupertino) have elided the Personal part of the PC and now view my computer more like a television than a personal workspace, treating it as a delivery vector for advertising and fulfilling other people's wishes.
This means the contents of the encrypted volume are safe only when the volume is not mounted. As soon as I mount the volume I need to worry about third-part code running on the computer, allowing only trusted code to read the contents. This is a very complex and perhaps even insolvable problem.
The first step is to identify the process that is requesting access to the volume. This needs to happen within the context of the IRP to minimuze the overhead of identifying an allowed access and letting it proceed; I don't want to drop down to UM on every sector read.
There are three NT functions that provide the basic information:
PsGetCurrentThread() provides an opaque handle
to the current thread.
PsIsSystemThread() tells me whether the thread is
part of the system pool.
PsGetCurrentProcessId() provides an opaque handle
to the current process.
There is little choice if the request is happening on a system thread, as stalling a system thread will most likely bring everything to a halt. So I use this as a the first filter: if the request is happening within a system thread, I allow it to proceed.
The second filter involves identifying the non-system process that is making the request. I need to make the determination immediately, without stalling the IRP. I maintain an in-memory process table that lets me look up the Process ID and find the Allow/Deny decision. Of course, the first time a new Process ID appears I need to make the Allow/Deny decision, which requires more information than just the process ID.
Unfortunately, Windows provides very little visibility into UM processes from KM. WindowsXP had a very useful API ZwQueryInformationProcess() to query information on about a process, but for whatever reason Redmond deprecated this function in Windows Vista and removed it from the standard libraries. The function is still present in Windows10 but requires me to find its address manually, then use undocumented structures to extract the information.
The good news is that I had already done this work in the NetMon project and I was able to copy/paste most of the code.
The most important information about the process is the path to the executable and the command line that was used to launch it. I can extract a (hopefully) meaningful text name from the command line that can be presented to the user. The path to the executable lets the UM app try to extract the publisher info and code signing certificate (if present).
Now I have a way to quickly identify processes from within the IRP handler, stalling the IRP only if the process is non-system and unknown. I still need to write a lot of code to manage the persistent storage of the process decision table, to be done later.
I quickly bump into a familiar problem. Any serious malware will try to obfuscate its origins, it won't appear as "MyMalware.exe". In fact, the most common carrier for virus and malware code is SvcHost.exe (for network and internet access) and Explorer.exe (for file access). Microsoft has spent decades inventing new ways to let code attach itself to Explorer and SvcHost, so now it seems as though these two are the only processes running on the system even while the disk is churning and megabytes of data are flying out into the ether. I have little choice but to allow all accesses by "Explorer.exe" even though I also know this will allow most malware through as well.
My ProcessInfo includes a list of all the DLL's that have attached themselves (code barnacles!) to Explorer.exe. My test system, which is an almost-virgin installation of Windows10, has 42 modules attached. Trying to establish the bona-fides of each module is an anti-virus / anti-malware task.
I am convinced that the major OS providers (Microsoft, Apple, and (especially!) Google) are paying only lip service to user privacy and protection. They (especially Google) have designed a security system that provides only the illusion of security, but instead trains the user to effectively disable all security to be able to do anything at all.
Every program now requires Admin privileges or a long list of app privileges (always including internet access and access to personal information) to install. As soon as I click "OK", I am granting complete access to my system: the program can install anything it wants, and I have absolutely no visiblity into what it is doing. My only choices are to to trust blindly and completely, or not install the program at all. Nearly every software publisher now abuses this dilemma by requiring access to services that are not needed and withholding use of the program as ransom for complete access to the system. This is security broken by design.
A truly owner-focused security design would let me install anything, enabling or disabling access to the set of system services of my choosing, not the publisher's. This should be an ala carte decision, not all or nothing. I can also control at runtime what system services the program can access. Every time a program wanted to contact an internet server, I would be notified and be able to respond with:
This question should be asked for any of these situations:
Would there be a market for a product that provided this level of control? Is anyone else concerned about this, or am I just paranoid?
So now I have a design decision. Do I plunge down the rabbit-hole of trying to identify which DLL within the process called ReadFile()? Or do I abandon the whole idea of process filtering as feckless and rely on a time-lock on the volume?