The team I work with has recently been faced with the challenge of making our software compatible with a third party peice of virtualization software. This software uses a kernel driver to perform hooking of the Windows native registry API (ZwCreateKey, etc). It works by hooking the calls in Ntdll. Our software is also fairly low level and in some contexts requires access to the real registry without being hooked.
We're exploring the possibility of using our own kernel driver to call ZwCreateKey, etc, on our behalf circumventing their hooking. This essentially has meant creating an NT Legacy driver and a user mode library which provides our own native registry functions. The library and driver are very simple, we simply use an IOCTL to pass all the parameters for ZwCreateKey, etc into our driver then we call the kernel version of the call and return the results.
The approach has worked well, and we appear to now have a system of reading/writing to the real registry when virtualized. The only problem is that our new system appears to circument Windows security on registry objects.
ZwCreateKey takes an access mask like so:
NTSTATUS ZwCreateKey(
__out PHANDLE KeyHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__reserved ULONG TitleIndex,
__in_opt PUNICODE_STRING Class,
__in ULONG CreateOptions,
__out_opt PULONG Disposition
);
My understanding was that although we were now running in kernel mode, we still had the context of the user's token. This should mean that the kernel version of ZwCreateKey will fail just as the user one would have if the access mask test fails. What's actually happening is that even with a limited token, when our driver is called, it's able to create keys in restricted parts HKLM when invoked by a limited user. What gives? Should we be performing the ACL checks ourselves? Do we need to do something to limit our own privileges in kernel mode? Any help much appreciated.
Check this for explanation. Basically Nt/Zw in User-mode (ntdll) are the same thing - they first perform extensive checks before actually performing the action. Where as when calling Zw functions from kernel-mode ( as is the case with a device driver) those checks are ommitted because it is assumed information coming from kernel-mode component (e.g. a driver) is to be trusted by default
Related
I'm working on a way to hook any API call to perform some verification on the function. (I'm creating a SandBox)
The first way that I think about, is with register key, and implement our own dll into MicrosoftNT to be able to redirect any defined syscall. https://www.apriorit.com/dev-blog/160-apihooks .
Problem? only work on 32 bit, and if the binarie is loading User32.dll, so it's abig issue.
The second way is to inject a dll into a process? Simple but impossible, most program is defended from those injection, so it's not possible.
The last way that I think was to modify the SSDT to change the function address by mine and redirect to the original by creating a driver. Or by InlineHook and just modify the first byte of each address that I want.
The Problem, only working on 32 bit, because windows add a PatchGuard on the Kernel, so we can't do that.
We can delete de PatchGuard but, anticheat will notice the technique.
For the Sandbox I think it won't be a problem to delete a PatchGuard.
The main problem is for real time analysis, I have no more idea how I can do to hook every API call that I want, on any windows OS. I mean on 32 and 62 bit.
I'm a beginner in this domain I started this week so I'm open to any suggestion.
You say you want to hook every API call for a sandbox but then reference the SSDT? Those are two very different things. Do you want to hook VirtualQuery(Ex) or do you want to hook NtQueryVirtualMemory? From kernel or user mode? Or maybe you're referring to all loaded module exports as well as kernel system services?
WinApi
Iterate all loaded modules as well as installing an event to hook all future modules loaded. For each one you will iterate all exports and apply a hook of your preference which all jump to some handler. This handler should be raw assembly that preserves the CPU state, calls some method that does the logging and filtering, restores CPU state, before finally jumping to the original.
Syscalls
Disable Patchguard and apply hooks to every method in the service table similar to the WinApi method described above. This is definitely not suitable for production for obvious reasons.
Use an instrumentation callback which uses ZwSetInformationProcess to redirect most syscalls to an arbitrary assembly block. You can extract the syscall id here as well as parameters. Universal support is an issue though as it wasn't introduced until W7 iirc and you have a lot of limitations prior to W10.
Map a wrapper module that has a hook for every syscall into each newly loaded process from kernel. These hooks will apply to ntdll and simply invoke an NtDeviceIoControlFile call with the syscall id and arguments, forwarding it to your kernel driver for processing. This is commonly employed by antivirus software to monitor user mode system calls without disrupting Patchguard.
The most approved method would probably be callbacks. You can register process and thread callbacks in kernel, stripping handle access at your leisure. This will give you full control over process and thread access from external processes, and you can add a file minfilter to similarly restrict access to the file system.
As a part of my project, I get an event notification every time a Service is Started or Stopped using the WMI class Win32_Service through an EventSink.
I want to detect the application which had requested "services.exe" to start a particular service.
Till now, I tried Monitoring ALPC calls between any process and "services.exe" and got a Message_ID every time a process communicates (sends/receives) any information to/from "services.exe" using the ALPC Class. I would like to know what these messages are so that I can decode a StartService() or a StopService() procedure.
Is there any way to detect which application starts/stops a service?
The best way to do this, in my opinion, would be from kernel-mode using the PsSetCreateProcessNotifyRoutine/Ex/Ex2 kernel-mode callback.
If you're going to be using PsSetCreateProcessNotifyRoutine, you will receive less information than if you were using the Extended version of the kernel-mode callback (the Ex one). However, you can still query information such as the image file path of the parent process (or the one being created) by using PsLookupProcessByProcessId to get a pointer to the _EPROCESS structure and then relying on SeLocateProcessImageName (undocumented, however it is accessible in WDK by default).
The SeLocateProcessImageName routine will rely internally on that _EPROCESS structure, since information like the path of the process image on-disk is all tracked by the Windows kernel there.
If you're going to be using the Ex version of the kernel-mode callback, then you eliminate the need to do what is mentioned above. The Ex version of the routine is more recent than the non-Ex version.
The routine prototype for the callback routine will be:
VOID
CreateProcessNotifyRoutineEx(
PEPROCESS Process,
HANDLE ProcessId,
PPS_CREATE_NOTIFY_INFO CreateInfo
)
As seen above, you get a pointer to the _PS_CREATE_NOTIFY_INFO structure. You can then access the ImageFileName and CommandLine fields to filter for services.exe (make sure you filter properly to not catch it for a rogue copy - so ensure full path indicates its the real one) and gain more insight into why it was being invoked (if such information is exposed via the command-line... I cannot remember - nonetheless, you can still detect its creation and be aware of who spawned it).
To determine the parent who was responsible for the process creation operation of services.exe (e.g. if it relied on the Service Manager which in turn resulted in the spawning of it), you can rely on the ParentProcessId field (under the _PS_CREATE_NOTIFY_INFO structure as well). The SeLocateProcessImageName trick will work perfectly here.
SeLocateProcessImageName is undocumented so here is the routine prototype:
NTSTATUS
NTAPI
SeLocateProcessImageName(
PEPROCESS Process,
PUNICODE_STRING *ImageName
);
At-least with the latest Windows 10 WDK, it's already available by default. If you wanted to though, you can use a dynamic import with MmGetSystemRoutineAddress.
Resources:
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/nf-ntddk-pssetcreateprocessnotifyroutine
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex2
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-mmgetsystemroutineaddress
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-pslookupprocessbyprocessid
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/ns-ntddk-_ps_create_notify_info
I have a program which adjusts SeDebugPrivilege and then starts to iterate through system processes and calls OpenProcess for them (and does other stuff, but it's not important now). Also the program runs in administrator mode of course. On Windows XP and Windows 7 it works fine, but on Windows 8.1 OpenProcess fails for the following system processes with ERROR_ACCESS_DENIED(5): smss.exe, csrss.exe, services.exe. As I know with SeDebugPrivilege I should be able to open these processes and retrieve a handle for them. Does anybody have a clue, what kind of magic causes this error only on Windows 8.1?
(Anyway I have the same error with the same processes for CreateToolhelp32Snapshot)
Windows 8.1 introduces the concept of a system protected process. This is documented in the context of third-party anti-malware software, but it seems reasonable to suppose that it is also used to protect particularly critical system processes.
System protected processes are an extension of the Protected Process mechanism (Microsoft Word document) introduced in Windows Vista as a DRM measure.
You cannot obtain any of these access rights for a protected process, even with debug privilege:
DELETE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
PROCESS_CREATE_THREAD
PROCESS_DUP_HANDLE
PROCESS_QUERY_INFORMATION
PROCESS_SET_QUOTA
PROCESS_SET_INFORMATION
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
You should still be able to open the process by requesting PROCESS_QUERY_LIMITED_INFORMATION access. According to the documentation, SYNCHRONIZE and PROCESS_TERMINATE access are also permitted.
It can only be done in the kernel. The best way to get the info you need would be to:
PsLookupProcessByProcessId()
KeStackAttachProcess()
ZwQueryInformationProcess() or whatever other functions you need to now call within the context of the attached process.
KeStackDetachProcess()
Or if you are just experimenting and not putting anything into production code, you can traverse the various semi-opaque structures (EPROCESS, PEB, VAD, etc) to get the information you need.
I was recently running into Access is Denied errors (error code 5 in my case), while running the Win32 OpenProcess API and then later while running CreateProcessAsUser. In my case, I was running on Windows 10, but I suspect it's similar, but since I got it working I thought I would share a couple things that helped me.
As I was using C# my Win32 method signature is as follows:
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
One key factor that effected the success of accessing the existing process, which in my case was a winlogon.exe process, was to properly defined the right "desired access" value. In my case, I used a constant "MAXIMUM_ALLOWED" defined as:
private const uint MAXIMUM_ALLOWED = 0x2000000;
This call to the service looks like this:
IntPtr hProcess = OpenProcess(MAXIMUM_ALLOWED, false, targetWinlogonProcessId);
This established the right kind of access. I was also running my process (web service) as the LocalSystem account, which had pretty good privileges. It started off as:
Please note, I was able to run this command using the SYSTEM account, by downloading PsExec.exe and running PsExec.exe -i -s cmd.exe to launch a command prompt so I could query the privileges using that account. You can find a good list of permissions here:
https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/user-rights-assignment
In my case, I wanted to add SeAssignPrimaryTokenPrivilege and SeIncreaseQuotaPrivilege, which I added via secpol.msc:
Your particular permissions required may depend on the account you're using, but I hope this helps!
I have a Windows application that interacts with some hardware. A handle to the hardware is opened with CreateFile, and we control the hardware using DeviceIoControl.
I'm attempting to update an application which uses this hardware to open the hardware in an exclusive mode, so that other programs can't access the hardware at the same time (the hardware has mutable state that I can't have changed out from under me). I do this by passing 0 as the dwShareMode parameter to CreateFile. After making this change, I am still able to run two separate instances of my application. Both calls to CreateFile in both processes are successful. Neither returns INVALID_HANDLE_VALUE.
I believe one of several things is happening, and I'm asking for help narrowing the problem down.
I badly misunderstand the dwShareMode parameter
dwShareMode doesn't have any effect on DeviceIoControl - only ReadFile or WriteFile
The driver itself is somehow responsible for respecting the dwShareMode parameter and our driver is written badly. This, sadly, isn't totally unheard of.
Edit Option 2 is nonsense. dwShareMode should prevent the 2nd CreateFile from happening, DeviceIoControl has nothing to do with it. It must be option #1 or option #3
The Question:
Is the device driver responsible for looking at the dwShareMode parameter, and rejecting requests if someone has already opened a handle without sharing, or is the OS responsible?
If the device driver is responsible, then I'm going to assume #3 is happening. If the OS is responsible, then it must be #1.
Some additional Clues:
IRP_MJ_CREATE documentation suggests that the sharing mode does indeed get passed down to the device driver
I believe that sharing rules are only enforced on some devices. In many (most?) cases enforcing sharing rules on the device object itself (as opposed to on objects within the device namespace) would make no sense.
Therefore, it must be the responsibility of the device driver to enforce these rules in those rare cases where they are required. (Either that or the device driver sets a flag to instruct the operating system to do so, but there doesn't seem to be a flag of this sort.)
In the case of a volume device, for example, you can open the device with a sharing mode of 0 even though the volume is mounted. [The documentation for CreateFile says you must use FILE_SHARE_WRITE but this does not appear to be true.]
In order to gain exclusive access to the volume, you use the FSCTL_LOCK_VOLUME control code.
[That's a file system driver, so it might not be a typical case. But I don't think it makes a difference in this context.]
Serial port and LPT drivers would be an example of a device that should probably enforce sharing rules. I think there may be some applicable sample code, perhaps this would shed light on things?
Edited to add:
I've had a look through the Windows Research Kernel source (this is essentially the same as the Windows Server 2003 kernel) and:
1) The code that opens a device object (by sending IRP_MJ_CREATE to the driver) does not appear to make any attempt to enforce the sharing mode parameter, though it does check access permissions and enforces the Exclusive flag for the driver;
2) I've also searched the code for references to the structure member that holds the requested dwShareMode. As far as I can see it is written into the relevant structure by the internal function that implements CreateFile, and later passed to the device driver, but otherwise ignored.
So, my conclusion remains the same: enforcing the sharing mode rules, or providing an alternative mechanism if appropriate, is the responsibility of the device driver.
(The kernel does, however, provide functions such as IoCheckShareAccess to assist file system drivers in enforcing sharing rules.)
In cases where we open a COM port with :
CreateFile(devname,GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
It doesnt allow another application to open the same COM port until the previous handle is closed. I would suggest walking through serenum.sys to check if it has a role here.
In Native API Microsoft exports two versions of each api call, one prefixed with Zw and one with Nt, for eg. ZwCreateThread and NtCreateThread.
My question is what is the difference between those two versions of the calls and when and why one should use Zw or Nt exclusively?
To my understanding Zw version ensures that the caller resides in kernel mode, whereas Nt doesn't.
I am also wondering about the specific meaning for Zw and Nt prefixes/abbreviations?
One can guess Nt probably refers to NT(New Technology) Windows family or Native(probably not)?
As for Zw, does it stand for something?
Update:
Aside from Larry Osterman's answer (which you should definitely read), there's another thing I should mention:
Since the NtXxx variants perform checks as though the call is coming from user-mode, this means that any buffers passed to the NtXxs function must reside in user-mode address spaces, not kernel-mode. So if you call a function like NtCreateFile in your driver and pass it pointers to kernel-mode buffers, you will get back a STATUS_ACCESS_VIOLATION because of this.
See Using Nt and Zw Versions of the Native System Services Routines.
A kernel-mode driver calls the Zw version of a native system services routine to inform the routine that the parameters come from a trusted, kernel-mode source. In this case, the routine assumes that it can safely use the parameters without first validating them. However, if the parameters might be from either a user-mode source or a kernel-mode source, the driver instead calls the Nt version of the routine, which determines, based on the history of the calling thread, whether the parameters originated in user mode or kernel mode.
Native system services routines make additional assumptions about the parameters that they receive. If a routine receives a pointer to a buffer that was allocated by a kernel-mode driver, the routine assumes that the buffer was allocated in system memory, not in user-mode memory. If the routine receives a handle that was opened by a user-mode application, the routine looks for the handle in the user-mode handle table, not in the kernel-mode handle table.
Also, Zw doesn't stand for anything. See What Does the Zw Prefix Mean?:
The Windows native system services routines have names that begin with the prefixes Nt and Zw. The Nt prefix is an abbreviation of Windows NT, but the Zw prefix has no meaning. Zw was selected partly to avoid potential naming conflicts with other APIs, and partly to avoid using any potentially useful two-letter prefixes that might be needed in the future.
I was going to leave this as a comment on Merhdad's answer but it got too long...
Mehrdad's answer is 100% accurate. It is also slightly misleading. The "PreviousMode" article linked to by the "Using Nt and Zw..." article Mehrdad goes into it in more detail. Paraphrasing:
The primary difference between the Nt and Zw API calls is that the Zw calls go through the system call dispatcher, but for drivers, Nt calls are direct calls to the API.
When a driver calls a Zw API, the only real effect of running through the system call dispatcher is that it sets KeGetPreviousMode() to KernelMode instead of UserMode (obviously to user mode code, the Zw and Nt forms are identical). When the various system calls see that ExGetPreviousMode is KernelMode, they bypass access checking (since drivers can do anything).
If a driver calls the NT form of the APIs, it's possible that it will fail because of the access checks.
A concrete example: if a driver calls NtCreateFile, the NtCreateFile will call SeAccessCheck() to see if the application which called into the driver has permissions to create the file. If that same driver called ZwCreateFile, the NtCreateFile API call won't call SeAccessCheck because ExGetPreviousMode returned KernelMode and thus the driver is assumed to have access to the file.
It's important for driver authors to understand the difference between the two since it can have profound implications for security...
Zw stands for Zero Wait (no time waste for parameters validation).