I'm writing a driver for Windows NT that provides Ring-0 access for userspace application. I want to make a utility with exclusive rights to execute any user's commands that would be protected from any external harmful influence.
Surfing the Internet I found that it is necessary to hook some native kernel functions, such as NtOpenProcess, NtTerminateProcess, NtDublicateObject, etc. I've made a working driver which protects an application but then I realized that it would be better to prevent it also from external attempts of removing the driver or forbidding its loading during OS starting like firewall. I divided the task into two parts: to prevent physical removing of the driver from \system32\drivers\ and to prevent changing/removing registry key responsible for loading the driver (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services).
The matter is that I do not understand how to hook the access to the registry key from kernel space and even not sure that it is possible: all functions from ntdll that work with registry are in the userspace, unavailable from kernelspace. Also all API hooks that I can set from userspace would be in specific proccess's memory context. So we need to inject Dll into every proccess be it current or new.
Is there a method to hook all NT-calls in one place without injecting Dll into every proccess?
You do this in wrong way. Registry calls is also nt syscalls and reside in SSDT (as another Zw* syscalls). But hooking SSDT is bad practice. Major drawbacks - its dont working on x64 systems because of PathGuard. Right way is use documented specific filtering mechanisms of OS. For registry calls it is Configuration Manager callbacks. There are some caveats for windows xp version of this callbacks (some facilities are unimplemented or bogus) but xp is dead now =). It`s very simple to use it. You can start (and end =) ) from this guide http://msdn.microsoft.com/en-us/library/windows/hardware/ff545879(v=vs.85).aspx
Related
I know that ntdll is always present in the running process but is there a way (not necessarily supported/stable/guaranteed to work) to create a file/key without ever invoking ntdll functions?
NTDLL is at the bottom of the user-mode hierarchy, some of its functions switch to kernel mode to perform their tasks. If you want to duplicate its code then I suppose there is nothing stopping you from decompiling NtCreateFile to figure out how it works. Keep in mind that on 32-bit Windows there are 3 different instructions used to enter kernel mode (depending on the CPU type), the exact way and where the transition code lives changes between versions and the system call ids change between versions (and even service packs). You can find a list of system call ids here.
I assume you are doing this to avoid people hooking your calls? Detecting your calls? Either way, I can't recommend that you try to do this. Having to test on a huge set of different Windows versions is unmanageable and your software might break on a simple Windows update at any point.
You could create a custom kernel driver that does the work for you but then you are on the hook for getting all the security correct. At least you would have documented functions to call in the kernel.
Technically, registry is stored in %WINDIR%\System32\config / %WINDIR%\SysWOW64\config, excepted your own user's registry which is stored in your own profile, in %USERPROFILE%\NTUSER.DAT.
And now, the problems...
You don't normally have even a read access to this folder, and this is true even from an elevated process. You'll need to change (and mess up a lot...) the permissions to simply read it.
Even for your own registry, you can't open the binary file - "Sharing violation"... So, for system/local machine registries... You can't in fact open ANY registry file for the current machine/session. You would need to shut down your Windows and mount its system drive in another machine/OS to be able to open - and maybe edit - registry files.
Real registry isn't a simple file like the .reg files. It's a database (you can look here for some elements on its structure). Even when having a full access to the binary files, it won't be fun to add something inside "from scratch", without any sotware support.
So, it's technically possible - after all, Windows does it, right? But I doubt that it can be done in a reasonable amount of time, and I simply can't see any benefit from doing that since, as you said, ntdll is ALWAYS present, loaded and available to be used.
If the purpose is to hack the current machine and/or bypass some lack of privileges, it's a hopeless approach, since you'll need even more privileges to do it - like being able to open your case and extract the system drive or being able to boot on another operating system on the same machine... If it's possible, then there is already tools to access the offline Windows, found on a well-known "Boot CD", so still no need to write in registry without any Windows support.
Is it possible to take a Windows driver such as a Ports class driver, then have it also set itself up as an NDIS filter (NetService class) driver by calling NdisFRegisterFilterDriver() in it's DriverEntry()? This would be essentially having the driver work double duty as a Ports and NetService class driver, but within a single code base and binary.
I'm attempting to do this and I'm seeing the call to register the NDIS driver fail, specifically with the following trace message:
[0][mp]<==ndisCreateFilterDriverRegistry, FilterServiceName 807EFA18 Status c0000001
[0][mp]==>NdisFRegisterFilterDriver: DriverObject 84C6C428
[0][mp]==>ndisCreateFilterDriverRegistry, FilterServiceName 807EFA18
[0][mp]<==ndisCreateFilterDriverRegistry, FilterServiceName 807EFA18 Status c0000001
I've looked around and it seems that the NDIS driver is heavily dependent on the values placed in the registry from the INF and the INF itself. I've tried to spoof the registry keys by adding the NetCfgInstanceId by hand and calling that value out in my code before trying to register the NDIS filter, but have hit a point where it just seems like the wrong way to go about it.
What is the recommended way to go about this? At this point I'd imagine that this would require a Ports class driver and NetService class driver separately, with some kind of composite driver to tie them together to be able to communicate, or have a way for one or the other to communicate through interprocess communication.
A stern warning
Do not attempt to "install" a filter by manually writing registry keys. As you've noticed, it's not easy, and even if you seem to get it working, it will all collapse when the OS tries to install the next LWF. Furthermore, I added some additional hardening features designed exactly to prevent people from doing this to Windows 10; you'll have to do some significant damage to the OS before you can hijack network bindings in Windows 10.
How to structure your driver package
Anyway, what you're describing is indeed possible. The way to do it is to provide the following in your driver package:
A PNP-style INF. This INF has:
The PORTS class
An AddService directive, that installs your driver service
A CopyFiles directive to bring in any files you need
Any other bits you need for the PNP device
A NetCfg-style INF. This INF has:
The NETSERVICE class
The usual LWF stuff: Characteristics=0x40000, FilterMediaTypes=xxx, FilterType=xxx, etc.
A reference to the service you installed in the other INF (HKR,Ndi,Service,,xxx)
Do not include an AddService or CopyFiles; that's already taken care of by the first INF
One .sys file. This driver does:
In DriverEntry, call NdisFRegisterFilterDriver, and pass the name of your service "xxx"
In DriverEntry, call WdfDriverCreate or fill out the DRIVER_OBJET dispatch table as you normally would for any other PNP driver
Implement FilterAttach and etc normally; implement your WDF EvtXxx or WDM IRP handlers normally
Don't forget to call NdisFDeregisterFilterDriver in EvtDriverUnload or DriverUnload, and also in the failure path for DriverEntry
How to install this fine mess
The good news is that, with these 2 INFs, you can meet your requirement of having 1 .sys file do two things. The bad news is that you've now got 2 INFs. Worse, one of the INFs is a NetCfg-style INF, so you can't just Include+Need it. The only way to install a NetCfg-style INF is to call INetCfgClassSetup::Install (or NetCfg.exe, its command-line wrapper). Windows Update only knows how to install PNP-style INFs, and PNP only knows how to Include other PNP-style INFs.
So the simplest solution is to ship an installer exe/msi that invokes the INetCfg API. If you can do that, it's simply a matter of a couple calls to SetupCopyOemInf and the INetCfg boilerplate that you can find in the bindview sample.
But, if you have to support a hardware-first installation, you need to bring out the big guns. You'll need to write a Co-Installer and include it with your driver package. The Co-Installer's job is to call the INetCfg APIs when your driver package is installed, and deregister when the package is uninstalled.
Co-Installers are generally discouraged, and are not supported for Universal drivers. So you should avoid a Co-Installer unless you've got no choice. Unfortunately I cannot think of any other way to register an NDIS LWF when a PNP device driver is installed through Windows Update. (This doesn't mean there isn't a crafty way to do it; I don't know everything.)
Note that you'd need a Co-Installer anyway even if you were shipping 2 .sys files. The need to call INetCfg doesn't change just because you merged the driver binaries.
Limitations
You'll have a full-fledged NDIS LWF driver, as well as a full-fledged PNP device driver. The only (minor) thing that doesn't work is that you cannot call NdisRegisterDeviceEx in this driver. The reason is that when you call NdisRegisterDeviceEx from a LWF, NDIS will attempt to co-opt your driver's dispatch table. But in this PNP+LWF dual driver, the dispatch table is owned by WDF or by you. This limitation is no problem, since you can call WdfDeviceCreate, and this routine is easier to use and has more features than the NDIS one anyway.
With the above configuration, the driver service is owned by PNP. That means the lifetime of your .sys file is owned by PNP. You cannot manually "net start" a PNP driver service; the only way to get your .sys file loaded is to actually enumerate your hardware. That means you can't have your NDIS LWF running when the hardware is not present. Typically this is what you'd want anyway. If it's not, you can try messing with the ServiceName directive, but there's some weird caveats with that, and I don't fully understand it myself.
I'm trying to develop a dual purpose driver that performs certain tasks at boot time, and other unrelated tasks after Windows has already started. It's developed as a boot start driver. I understand that the proper way to do this may be to develop 2 separate drivers, but I'd prefer to only go through the WinQual process once. There's also the added benefit of performing only one driver install in my app versus two. It needs to work on Vista through Win8 x86 & 64.
So what I'm really looking for is a safe way to determine in DriverInit if the system is in the process of booting, or if it's already up and running. The driver will initially be utilized when Windows has already started, then enabled at boot time after the next reboot. The DriverInit code needs to be different for both scenarios.
Is there a registry key that is or is not present?
Can I determine if a user is logged-in in DriverInit?
Is there a call I can make that will determine if Windows is booting?
I'm not an expert at driver writing, so thanks in advance for any advice.
Technically, glagolig's answer is probably the correct way to solve this.
The solution for my particular issue was a little different. There are 2 mutually exclusive use cases were the driver is either needed as a SERVICE_DEMAND_START driver after Windows is up and running, or as a SERVICE_BOOT_START driver with boot time functionality. The situation never arises were I need the functionality of both cases at the same time in the same Windows session.
The driver is initially installed as a SERVICE_DEMAND_START driver (this is the one that is going to WinQual). It is then changed to SERVICE_BOOT_START in the registry on the new drive that will be booted. All the driver entry points (DriverEntry, AddDevice, etc) that are different for each use case read the 'Start' value in the driver's service registry key to determine how it needs to operate.
It hasn't passed yet, but I'm fairly certain that I can change the start type of the driver in the registry without affecting Window's digital signature enforcement.
At the time boot-start drivers are loaded Windows has not created any user-mode processes yet. Try to acquire a handle to some process that is supposed to be created later on during Windows startup. For example, smss.exe, csrss.exe or wininit.exe . (Processes with these names existed for many years, it is very unlikely that Microdoft abandons them in the future while still allowing existing kernel mode modules to run.) Use ZwOpenProcess with POBJECT_ATTRIBUTES pointing to one of those process' names. If the call fails you are at boot time.
Also you may study Windows startup described in "Windows Internals" by Russinovich and Solomon. Most likely you will get a number of other ideas.
I've answered a similar question elsewhere on SO. The short version is that what you're asking is not normal driver behavior, so no API exists to support this. You can add in heuristics to tell you this, but they'll remain heuristics.
You can use IoGetBootDiskInformation to check if you are loaded post or, during boot. It will return STATUS_TOO_LATE if this API is called post reboot.
Is there any bottleneck above the physical the cpu and HAL? Or are there multiple ways a process could start under Windows XP, Vista, or 7, that don't invovle CreateProcess at some point?
Given the comment on your question:
Building an Anti-Executable driver, just planning, wondering if controlling createprocess would be enough.
No it wouldn't be enough if security is your concern. There is NtCreateProcess below that one for example. And those aren't the only ones.
The best way provided by the system is a file system filter driver. In fact the WDK comes with samples that require only a moderate amount of change to do what you're asking. Since you asked about XP you can use a minifilter if you can get away with support for XP SP1 and later.
PsSetLoadImageNotifyRoutine and PsSetCreateProcessNotifyRoutine are unfortunately only notifications. So they don't allow to do anything about the event that they notify about. And you really shouldn't attempt to work around this.
In the old times I have seen some clever implementations using SSDT hooks on ZwCreateSection that would exchange the returned handle with one to an executable that shows an error message. Since the executable itself sees the original command line, it can then show a nice error message informing the user that the command has been banned for reasons xyz. However, with Vista and later and even on XP and 2003 64bit (x64), it's going to be harder to write the SSDT hooks. Not to mention that everyone would frown upon it, that it requires quite extensive experience to get it right (and even then it often has flaws that can cause havoc) and that you can forget any certifications you may be aspiring for in the Windows Logo process.
Conclusion: use a file system filter driver to deny access to unwanted executables. With a minifilter the learning curve will be moderate, with a legacy filter I'll recommend you take a few courses first and then start your first attempts.
Looking through a quick disassembly of CreateProcess, it appears that the two main things it does are:
Call NtCreateUserProcess (this is syscall 0xAA) to actually create the process structures in the kernel (PEB, etc.)
Start the new process with a call to NtResumeThread (syscall 0x4F).
The Windows Internals books certainly detail this process very well.
I'm not sure if there are designated hooks in the kernel which would allow you to create your anti-executable driver. It used to be that you could hook the "System Service Dispatch Table" to change how these system calls behaved. But now, technologies like PatchGuard prevent a driver from doing this (and allowing the system to run).
I read a little bit and I find out that SSDT hooks using drivers in Windows 7 x64 systems are harder, on purpose because of Patch Guard/Driver Signing while in x32 systems that doesn't happen.
So, is there any other alternative for x64 systems? I mean, is there any other way that I could go to achieve the same result? (global hook a ntdll api)
You could implement User Mode hooks using the DLL Injection method as this works on both x86 and x64. If you want to make the hook global you will need to inject the DLL into every process including newly created ones.
SSDT is not allowed in x64.
File system or mini-filter driver is a way to alter any default system behavior.
What do you want to achieve?
It's up to what your target is. If you need to prevent malicious operation on process or thread, you can Use NotifyRoutine or ObRegisterCallbacks instead. Or you are able to use minifilter to monitor file operation.