PsSetCreateProcessNotifyRoutineEx is the newest kid in block if you wish to keep a watch on process creation or destruction in your driver. It is available in Vista SP1 onwards. You would need to use 2008 WDK (6001 onwards) to build your driver and for now, you can test your new notification routines on Vista SP1 Beta or Windows Server 2008 RC0.

PsSetCreateProcessNotifyRoutineEx is the recommended way to do process related processing in 64-bit platforms since hooking process creation calls such as NtCreateUserProcess or NtCreateProcessEx is not feasible because of Kernel Patch Protection.

PsSetCreateProcessNotifyRoutineEx notification callback looks like thus -

VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE_EX) (
__inout PEPROCESS Process,
__in HANDLE ProcessId,
__in_opt PPS_CREATE_NOTIFY_INFO CreateInfo
);

The third parameter to the callback is pointer to a PS_CREATE_NOTIFY_INFO structure which is defined in ntddk.h as below -

typedef struct _PS_CREATE_NOTIFY_INFO {
__in SIZE_T Size;
union {
__in ULONG Flags;
struct {
__in ULONG FileOpenNameAvailable : 1;
__in ULONG Reserved : 31;
};
};
__in HANDLE ParentProcessId;
__in CLIENT_ID CreatingThreadId;
__inout struct _FILE_OBJECT *FileObject;
__in PCUNICODE_STRING ImageFileName;
__in_opt PCUNICODE_STRING CommandLine;
__out NTSTATUS CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;

Clearly PsSetCreateProcessNotifyRoutineEx gives much more than process id and parent process id made available in PsSetCreateProcessNotifyRoutine callbacks on win2k onwards. Gone from your routine should be the code to figure out what path the process is being launched from, since ImageFileName (when CreateInfo->FileOpenNameAvailable is set)and CommandLine are readily available in the callback.

One also gets to know the creating process and thread (via CreatingThreadId) which may or may not be in the parent process (ParentProcessId). ParentProcessId can be set to another process in Vista onwards when calling CreateProcessAsUser which is how UAC retains parent-child relationships as mentioned by Mark Russinovich here.

When you wish to block a process creation, you will write an error status such as STATUS_ACCESS_DENIED in CreateInfo->CreationStatus.

The process termination callbacks from kernel always has CreateInfo pointer set to NULL and are for notification purposes only. In other words, you cannot block a process from termination in the callback. [This would not have been terribly useful anyway, since the termination callback happens after the last thread in the process is already gone.]

Also when you block a process creation, kernel will call your callback once more thereafter, for the blocked process as it undergoes termination.

One of the things that you need to do in your driver for PsSetCreateProcessNotifyRoutineEx to work is to compile your driver with IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY bit set in IMAGE_OPTIONAL_HEADER.DllCharacteristics [which MSDN explains as "Code Integrity checks are forced"].

If you do not have IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY bit set, you will get STATUS_ACCESS_DENIED in your driver even if it is signed or you are booted with Disable Driver Signature Enforcement. [I learnt this the hard way only to find it mentioned in the API documentation. A clear case of RTFM. But in my defense let me state that Server 2008 Beta3 has a bug that never lets this call succeed.]

The linker sets this when /INTEGRITYCHECK option is turned on. There is no other change to the generated code. Unfortunately there is no way to know whether your linker supports it until you actually compile and link, since link /? does not show this in the help text even if the linker recognizes the option. The way to set this flag in your kernel mode driver is to add the following line in your Sources file

LINKER_FLAGS=/INTEGRITYCHECK

If you are building in VS 2005 IDE, you can go to Project Properties->Configuration Properties->Linker->Command Line->Additional Options edit box and add /integritycheck in there. [If you have not applied VS 2005 SP1, this option is not recognized and you will get a linker warning.]

If this bit is set and the binary is not digitally signed, then the loader refuses to load it and you get STATUS_INVALID_IMAGE_HASH (0xC0000428) (same as Win32 error 577 or ERROR_INVALID_IMAGE_HASH) returned from process creation attempt.

If I run a simple console application with this bit set but no signature on it, the command line (cmd.exe) reports the error as "The system cannot execute the specified program." as shown below.

Error when running unsigned binary with code integrity bit set

This can be a little confusing because it is not clear that this is a signature issue. But if you are a long time windows user or have seen Lost In Translation, you probably know something does not smell right 😉

Until next time, ciao.

Tagged with →  
Share →

3 Responses to Process vigilance via PsSetCreateProcessNotifyRoutineEx

  1. varun says:

    how can i use this on windows xp or implement similar.

  2. Satya Das says:

    You can use PsSetCreateProcessNotifyRoutine or use system call intercept.

  3. […] is a pretty interesting article over at winprogger.com about the problems connected with IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY (set through […]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Looking for something?

Use the form below to search the site:


Still not finding what you're looking for? Drop us a note so we can take care of it!

Visit our friends!

A few highly recommended friends...

Set your Twitter account name in your settings to use the TwitterBar Section.