From 9da61ad2c8305a9799bc3ef169972b62bb6fc9b8 Mon Sep 17 00:00:00 2001 From: wj32 Date: Sun, 26 Jul 2009 06:50:37 +0000 Subject: [PATCH] many improvements to KphSs git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1633 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/KProcessHacker/HACKING.txt | 5 +- trunk/KProcessHacker/i386/kprocesshacker.sys | Bin 35328 -> 38400 bytes trunk/KProcessHacker/include/kph.h | 14 + trunk/KProcessHacker/include/kprocesshacker.h | 7 +- trunk/KProcessHacker/include/sysservice.h | 171 ++++- trunk/KProcessHacker/include/sysservicedata.h | 156 ++++ trunk/KProcessHacker/include/sysservicep.h | 450 ++++++++++-- trunk/KProcessHacker/include/version.h | 7 +- trunk/KProcessHacker/kprocesshacker.c | 183 ++--- trunk/KProcessHacker/ob.c | 111 +++ trunk/KProcessHacker/sources | 1 + trunk/KProcessHacker/sysservice.c | 678 ++++++++++++++---- trunk/KProcessHacker/sysservicedata.c | 160 +++++ trunk/KProcessHacker/version.c | 19 +- trunk/ProcessHacker.Native/KProcessHacker.cs | 127 +++- 15 files changed, 1764 insertions(+), 325 deletions(-) create mode 100644 trunk/KProcessHacker/include/sysservicedata.h create mode 100644 trunk/KProcessHacker/sysservicedata.c diff --git a/trunk/KProcessHacker/HACKING.txt b/trunk/KProcessHacker/HACKING.txt index 8bec4e5fd..00c104cfa 100644 --- a/trunk/KProcessHacker/HACKING.txt +++ b/trunk/KProcessHacker/HACKING.txt @@ -54,11 +54,14 @@ following files contain "ported" ReactOS code (with modifications): - Contains Windows-version-specific data. == POOL TAGS == +PhAB: System service logging argument block. sysservice.h PhCH: Client handle table. kprocesshacker.h +PhCt: System service logging argument capture temporary buffer. sysservicep.h PhCU: Captured Unicode string. kph.h -PhEB: System service logging event block. sysservicep.h +PhEB: System service logging event block. sysservice.h PhOb: Object manager object. refp.h PhPC: Pool-based virtual memory copying. mm.h PhPr: Protection entry. protect.h +PhSc: System service call entry. sysservicedata.h PhSD: Processor lock DPC storage. sync.h PhSt: Stack back trace. ps.h diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys index b4699c76d05becb504ac197885af47e9119873ea..12526a8b39ac9ddac1e8768b818a470a4f5776e7 100644 GIT binary patch literal 38400 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 CshCp$ diff --git a/trunk/KProcessHacker/include/kph.h b/trunk/KProcessHacker/include/kph.h index b4c073d0b..a91c62762 100644 --- a/trunk/KProcessHacker/include/kph.h +++ b/trunk/KProcessHacker/include/kph.h @@ -306,6 +306,20 @@ NTSTATUS KphQueryInformationDriver( __in KPROCESSOR_MODE AccessMode ); +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + NTSTATUS KphQueryProcessHandles( __in HANDLE ProcessHandle, __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer, diff --git a/trunk/KProcessHacker/include/kprocesshacker.h b/trunk/KProcessHacker/include/kprocesshacker.h index 6103b16d9..bb51d12e8 100644 --- a/trunk/KProcessHacker/include/kprocesshacker.h +++ b/trunk/KProcessHacker/include/kprocesshacker.h @@ -86,7 +86,9 @@ #define KPH_SSREF KPH_CTL_CODE(42) #define KPH_SSUNREF KPH_CTL_CODE(43) #define KPH_SSCREATECLIENTENTRY KPH_CTL_CODE(44) -#define KPH_SSCREATEPROCESSENTRY KPH_CTL_CODE(45) +#define KPH_SSCREATERULESETENTRY KPH_CTL_CODE(45) +#define KPH_SSREMOVERULE KPH_CTL_CODE(46) +#define KPH_SSADDPROCESSIDRULE KPH_CTL_CODE(47) NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); VOID DriverUnload(PDRIVER_OBJECT DriverObject); @@ -113,6 +115,9 @@ typedef struct _KPH_CLIENT_ENTRY LONG SsStartCount; } KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY; +VOID SsRef(LONG count); +VOID SsUnref(LONG count); + VOID NTAPI ClientEntryDeleteProcedure( __in PVOID Object, __in ULONG Flags, diff --git a/trunk/KProcessHacker/include/sysservice.h b/trunk/KProcessHacker/include/sysservice.h index a7afc1b25..06dd8a0a3 100644 --- a/trunk/KProcessHacker/include/sysservice.h +++ b/trunk/KProcessHacker/include/sysservice.h @@ -24,18 +24,136 @@ #define _SYSSERVICE_H #include "kph.h" +#include "sysservicedata.h" -/* If neither mode flags are specified, both modes are assumed. */ -#define KPHSS_LOG_USER_MODE 0x00000001 -#define KPHSS_LOG_KERNEL_MODE 0x00000002 -#define KPHSS_LOG_VALID_FLAGS 0x00000003 +/* Define opaque object types */ struct _KPHSS_CLIENT_ENTRY; typedef struct _KPHSS_CLIENT_ENTRY *PKPHSS_CLIENT_ENTRY; -struct _KPHSS_PROCESS_ENTRY; -typedef struct _KPHSS_PROCESS_ENTRY *PKPHSS_PROCESS_ENTRY; +struct _KPHSS_RULESET_ENTRY; +typedef struct _KPHSS_RULESET_ENTRY *PKPHSS_RULESET_ENTRY; +struct _KPHSS_RULE_ENTRY; +typedef struct _KPHSS_RULE_ENTRY *PKPHSS_RULE_ENTRY; + +/* Object types */ + +#ifndef _SYSSERVICE_PRIVATE +extern PKPH_OBJECT_TYPE KphSsClientEntryType; +extern PKPH_OBJECT_TYPE KphSsRuleSetEntryType; +extern PKPH_OBJECT_TYPE KphSsRuleEntryType; +#endif + +/* Ruleset types */ + +typedef enum _KPHSS_RULESET_ACTION +{ + LogRuleSetAction, + MaxRuleSetAction +} KPHSS_RULESET_ACTION; + +/* Rule types */ + +typedef enum _KPHSS_FILTER_TYPE +{ + IncludeFilterType, + ExcludeFilterType, + MaxFilterType +} KPHSS_FILTER_TYPE; + +typedef enum _KPHSS_RULE_TYPE +{ + ProcessIdRuleType, + ThreadIdRuleType, + PreviousModeRuleType, + NumberRuleType, + MaxRuleType +} KPHSS_RULE_TYPE; + +/* Block types */ + +#define KPHSS_BLOCK_SUCCESS(Status) (NT_SUCCESS(Status) && (Status) != STATUS_TIMEOUT) + +typedef enum _KPHSS_BLOCK_TYPE +{ + ResetBlockType, + EventBlockType, + ArgumentBlockType +} KPHSS_BLOCK_TYPE; + +typedef struct _KPHSS_BLOCK_HEADER +{ + ULONG Size; /* a.k.a. NextEntryOffset */ + ULONG Type; +} KPHSS_BLOCK_HEADER, *PKPHSS_BLOCK_HEADER; + +typedef struct _KPHSS_RESET_BLOCK +{ + KPHSS_BLOCK_HEADER Header; +} KPHSS_RESET_BLOCK, *PKPHSS_RESET_BLOCK; + +#define TAG_EVENT_BLOCK ('BEhP') + +#define KPHSS_EVENT_PROBE_ARGUMENTS_FAILED 0x00000001 +#define KPHSS_EVENT_COPY_ARGUMENTS_FAILED 0x00000002 +#define KPHSS_EVENT_KERNEL_MODE 0x00000004 +#define KPHSS_EVENT_USER_MODE 0x00000008 + +typedef struct _KPHSS_EVENT_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + ULONG Flags; + LARGE_INTEGER Time; + CLIENT_ID ClientId; + + /* The system service number. */ + ULONG Number; + /* The number of ULONG arguments to the system service. */ + ULONG NumberOfArguments; + ULONG ArgumentsOffset; + + /* The number of PVOIDs in the trace. */ + ULONG TraceCount; + ULONG TraceOffset; +} KPHSS_EVENT_BLOCK, *PKPHSS_EVENT_BLOCK; + +/* Argument Blocks + * + * These blocks provide additional information about + * arguments. + */ + +#define TAG_ARGUMENT_BLOCK ('BAhP') + +#define KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize) \ + (FIELD_OFFSET(KPHSS_ARGUMENT_BLOCK, Normal) + InnerSize) + +typedef struct _KPHSS_ARGUMENT_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + ULONG Index; + KPHSS_ARGUMENT_TYPE Type; + + union + { + ULONG Normal; + + LARGE_INTEGER Simple; + KPHSS_HANDLE Handle; + KPHSS_STRING String; + KPHSS_WSTRING WString; + KPHSS_ANSI_STRING AnsiString; + KPHSS_UNICODE_STRING UnicodeString; + KPHSS_OBJECT_ATTRIBUTES ObjectAttributes; + CLIENT_ID ClientId; + CONTEXT Context; + KPHSS_INITIAL_TEB InitialTeb; + }; +} KPHSS_ARGUMENT_BLOCK, *PKPHSS_ARGUMENT_BLOCK; + +/* Functions */ NTSTATUS KphSsLogInit(); +NTSTATUS KphSsLogDeinit(); NTSTATUS KphSsLogStart(); NTSTATUS KphSsLogStop(); @@ -49,11 +167,44 @@ NTSTATUS KphSsCreateClientEntry( __in KPROCESSOR_MODE AccessMode ); -NTSTATUS KphSsCreateProcessEntry( - __out PKPHSS_PROCESS_ENTRY *ProcessEntry, +NTSTATUS KphSsCreateRuleSetEntry( + __out PKPHSS_RULESET_ENTRY *RuleSetEntry, __in PKPHSS_CLIENT_ENTRY ClientEntry, - __in HANDLE TargetProcessHandle, - __in ULONG Flags + __in KPHSS_FILTER_TYPE DefaultFilterType, + __in KPHSS_RULESET_ACTION Action + ); + +NTSTATUS KphSsRemoveRule( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in HANDLE RuleEntryHandle + ); + +NTSTATUS KphSsAddProcessIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ProcessId + ); + +NTSTATUS KphSsAddThreadIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ThreadId + ); + +NTSTATUS KphSsAddPreviousModeRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphSsAddNumberRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in ULONG Number ); #endif diff --git a/trunk/KProcessHacker/include/sysservicedata.h b/trunk/KProcessHacker/include/sysservicedata.h new file mode 100644 index 000000000..2a6a1b279 --- /dev/null +++ b/trunk/KProcessHacker/include/sysservicedata.h @@ -0,0 +1,156 @@ +/* + * Process Hacker Driver - + * system service logging (data) + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#ifndef _SYSSERVICEDATA_H +#define _SYSSERVICEDATA_H + +#include "kph.h" + +typedef enum _KPHSS_ARGUMENT_TYPE +{ + /* Having argument info for out variables is very rare + * because usually the caller does not fill in anything + * in the variable. In some cases, however, the caller + * does specify a length (usually Length, or MaximumLength). + * + * Note that with the exception of a few types such as + * HANDLE, all types listed here are POINTER TYPES + * (although a handle is the size of a pointer). This + * is because non-pointer arguments are already recorded + * in the event block. + */ + + /* Anything passed by value */ + NormalArgument = 0, + + /* PBOOLEAN */ + Int8Argument, + /* P(U)SHORT */ + Int16Argument, + /* P(U)LONG */ + Int32Argument, + /* P(U)LARGE_INTEGER */ + Int64Argument, + /* HANDLE */ + /* Only object manager handles, no fake handles. */ + HandleArgument, + /* PSTR */ + StringArgument, + /* PWSTR */ + WStringArgument, + /* PANSI_STRING */ + AnsiStringArgument, + /* PUNICODE_STRING */ + UnicodeStringArgument, + /* POBJECT_ATTRIBUTES */ + ObjectAttributesArgument, + /* PCLIENT_ID */ + ClientIdArgument, + /* PCONTEXT */ + ContextArgument, + /* PINITIAL_TEB */ + InitialTebArgument +} KPHSS_ARGUMENT_TYPE; + +typedef struct _KPHSS_HANDLE +{ + ULONG TypeNameOffset; /* KPHSS_WSTRING */ + ULONG NameOffset; /* KPHSS_WSTRING */ +} KPHSS_HANDLE, *PKPHSS_HANDLE; + +typedef struct _KPHSS_STRING +{ + USHORT Length; + CHAR Buffer[1]; +} KPHSS_STRING, *PKPHSS_STRING; + +typedef struct _KPHSS_WSTRING +{ + USHORT Length; + WCHAR Buffer[1]; +} KPHSS_WSTRING, *PKPHSS_WSTRING; + +typedef struct _KPHSS_ANSI_STRING +{ + USHORT Length; + USHORT MaximumLength; + PSTR Pointer; + CHAR Buffer[1]; +} KPHSS_ANSI_STRING, *PKPHSS_ANSI_STRING; + +typedef struct _KPHSS_UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Pointer; + WCHAR Buffer[1]; +} KPHSS_UNICODE_STRING, *PKPHSS_UNICODE_STRING; + +typedef struct _KPHSS_OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; + + ULONG RootDirectoryOffset; /* KPHSS_HANDLE */ + ULONG ObjectNameOffset; /* KPHSS_UNICODE_STRING */ +} KPHSS_OBJECT_ATTRIBUTES, *PKPHSS_OBJECT_ATTRIBUTES; + +typedef struct _KPHSS_INITIAL_TEB +{ + struct + { + PVOID OldStackBase; + PVOID OldStackLimit; + } OldInitialTeb; + PVOID StackBase; + PVOID StackLimit; + PVOID StackAllocationBase; +} KPHSS_INITIAL_TEB, *PKPHSS_INITIAL_TEB; + +#ifndef _SYSSERVICEDATA_PRIVATE +extern RTL_GENERIC_TABLE KphSsCallTable; +#endif + +#define TAG_CALL_ENTRY ('cShP') + +#define KPHSS_MAXIMUM_ARGUMENT_BLOCKS 10 + +typedef struct _KPHSS_CALL_ENTRY +{ + PULONG Number; + PSTR Name; + ULONG NumberOfArguments; + KPHSS_ARGUMENT_TYPE Arguments[KPHSS_MAXIMUM_ARGUMENT_BLOCKS]; +} KPHSS_CALL_ENTRY, *PKPHSS_CALL_ENTRY; + +VOID KphSsDataInit(); +VOID KphSsDataDeinit(); + +PKPHSS_CALL_ENTRY KphSsLookupCallEntry( + __in ULONG Number + ); + +#endif \ No newline at end of file diff --git a/trunk/KProcessHacker/include/sysservicep.h b/trunk/KProcessHacker/include/sysservicep.h index 06b8000e8..5983cdfb8 100644 --- a/trunk/KProcessHacker/include/sysservicep.h +++ b/trunk/KProcessHacker/include/sysservicep.h @@ -39,73 +39,367 @@ typedef VOID (NTAPI *PKPHPSS_KIFASTCALLENTRYPROC)( __in PKTHREAD Thread ); +/* Client entries + * + * Client entries describe a process and a circular buffer which + * receives logging events. + */ + typedef struct _KPHSS_CLIENT_ENTRY { PEPROCESS Process; + + /* Buffer */ PKSEMAPHORE ReadSemaphore; PKSEMAPHORE WriteSemaphore; FAST_MUTEX BufferMutex; PVOID BufferBase; ULONG BufferSize; ULONG BufferCursor; + + /* Statistics */ + ULONG NumberOfBlocksWritten; /* excludes reset blocks */ + ULONG NumberOfBlocksDropped; } KPHSS_CLIENT_ENTRY, *PKPHSS_CLIENT_ENTRY; -#define KPHSS_PROCESS_ENTRY(ListEntry) \ - CONTAINING_RECORD((ListEntry), KPHSS_PROCESS_ENTRY, ProcessListEntry) -#define KPHSS_PROCESS_ENTRY_LIMIT 10 +/* Rulesets + * + * Rulesets contain a list of rules and an action to take if a + * system service matches the set of rules. + */ -typedef struct _KPHSS_PROCESS_ENTRY +#define KPHSS_RULESET_ENTRY(ListEntry) \ + CONTAINING_RECORD((ListEntry), KPHSS_RULESET_ENTRY, RuleSetListEntry) +#define KPHSS_RULESET_ENTRY_LIMIT 10 +#define KPHSS_RULE_HANDLE_INCREMENT 4 + +typedef struct _KPHSS_RULESET_ENTRY { - LIST_ENTRY ProcessListEntry; - + LIST_ENTRY RuleSetListEntry; + /* The client is referenced. */ PKPHSS_CLIENT_ENTRY Client; - PEPROCESS TargetProcess; - ULONG Flags; -} KPHSS_PROCESS_ENTRY, *PKPHSS_PROCESS_ENTRY; - -typedef enum _KPHPSS_BLOCK_TYPE -{ - ResetBlockType, - EventBlockType -} KPHPSS_BLOCK_TYPE; - -typedef struct _KPHPSS_BLOCK_HEADER -{ - ULONG Size; /* a.k.a. NextEntryOffset */ - ULONG Type; -} KPHPSS_BLOCK_HEADER, *PKPHPSS_BLOCK_HEADER; - -typedef struct _KPHPSS_RESET_BLOCK -{ - KPHPSS_BLOCK_HEADER Header; -} KPHPSS_RESET_BLOCK, *PKPHPSS_RESET_BLOCK; - -#define TAG_EVENT_BLOCK ('BEhP') - -#define KPHPSS_EVENT_BLOCK_MAX_SIZE 0x200 - -#define KPHPSS_EVENT_PROBE_ARGUMENTS_FAILED 0x00000001 -#define KPHPSS_EVENT_COPY_ARGUMENTS_FAILED 0x00000002 -#define KPHPSS_EVENT_KERNEL_MODE 0x00000004 -#define KPHPSS_EVENT_USER_MODE 0x00000008 - -typedef struct _KPHPSS_EVENT_BLOCK -{ - KPHPSS_BLOCK_HEADER Header; - ULONG Flags; - LARGE_INTEGER Time; - CLIENT_ID ClientId; - /* The system service number. */ - ULONG Number; - /* The number of ULONG arguments to the system service. */ - ULONG NumberOfArguments; - ULONG ArgumentsOffset; + KPHSS_RULESET_ACTION Action; + KPHSS_FILTER_TYPE DefaultFilterType; - /* The number of PVOIDs in the trace. */ - ULONG TraceCount; - ULONG TraceOffset; -} KPHPSS_EVENT_BLOCK, *PKPHPSS_EVENT_BLOCK; + ULONG NextRuleHandle; + FAST_MUTEX RuleListMutex; + /* A list of rules. Each rule is referenced when stored. */ + LIST_ENTRY RuleListHead; +} KPHSS_RULESET_ENTRY, *PKPHSS_RULESET_ENTRY; + +/* Rules */ + +#define KPHSS_RULE_ENTRY(ListEntry) \ + CONTAINING_RECORD((ListEntry), KPHSS_RULE_ENTRY, RuleListEntry) + +typedef struct _KPHSS_RULE_ENTRY +{ + BOOLEAN Initialized; + HANDLE Handle; + LIST_ENTRY RuleListEntry; + + KPHSS_FILTER_TYPE FilterType; + KPHSS_RULE_TYPE RuleType; + + union + { + struct + { + HANDLE ProcessId; + } ProcessIdRule; + struct + { + HANDLE ThreadId; + } ThreadIdRule; + struct + { + KPROCESSOR_MODE PreviousMode; + } PreviousModeRule; + struct + { + ULONG Number; + } NumberRule; + }; +} KPHSS_RULE_ENTRY, *PKPHSS_RULE_ENTRY; + +typedef enum _KPHSS_SEQUENCE_MODE +{ + NoSequence, + StartSequence, + InSequence, + EndSequence +} KPHSS_SEQUENCE_MODE; + +#define TAG_CAPTURE_TEMP_BUFFER ('tChP') + +FORCEINLINE PKPHSS_ARGUMENT_BLOCK KphpSsAllocateArgumentBlock( + __in ULONG InnerSize, + __in KPHSS_ARGUMENT_TYPE Type + ) +{ + PKPHSS_ARGUMENT_BLOCK argumentBlock; + ULONG size; + + size = KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize); + argumentBlock = ExAllocatePoolWithTag( + PagedPool, + size, + TAG_ARGUMENT_BLOCK + ); + + if (!argumentBlock) + return NULL; + + argumentBlock->Header.Type = ArgumentBlockType; + argumentBlock->Header.Size = size; + argumentBlock->Type = Type; + + return argumentBlock; +} + +FORCEINLINE NTSTATUS KphpSsCaptureSimple( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PVOID Argument, + __in KPHSS_ARGUMENT_TYPE Type + ) +{ + PKPHSS_ARGUMENT_BLOCK argumentBlock; + ULONG size; + LARGE_INTEGER value; + + switch (Type) + { + case Int8Argument: + size = sizeof(BOOLEAN); + break; + case Int16Argument: + size = sizeof(SHORT); + break; + case Int32Argument: + size = sizeof(LONG); + break; + case Int64Argument: + size = sizeof(LARGE_INTEGER); + break; + default: + return STATUS_INVALID_PARAMETER_3; + } + + __try + { + ProbeForRead(Argument, size, 1); + memcpy(&value, Argument, size); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + argumentBlock = KphpSsAllocateArgumentBlock(size, Type); + + if (!argumentBlock) + return STATUS_INSUFFICIENT_RESOURCES; + + memcpy(&argumentBlock->Simple, &value, size); + *ArgumentBlock = argumentBlock; + + return STATUS_SUCCESS; +} + +#define CAPTURE_HANDLE_BUFFER_SIZE 0x400 + +FORCEINLINE NTSTATUS KphpSsCaptureHandle( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in HANDLE Argument + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + PVOID object; + PUNICODE_STRING objectTypeName; + PUNICODE_STRING objectNameInfo; + ULONG returnLength; + PKPHSS_WSTRING wString; + + /* Reference the object. */ + status = ObReferenceObjectByHandle( + Argument, + 0, + NULL, + KernelMode, + &object, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Get a pointer to the UNICODE_STRING containing the + * object type name. + */ + objectTypeName = (PUNICODE_STRING)KVOFF( + OBJECT_TO_OBJECT_HEADER(object)->Type, + OffOtName + ); + + /* Allocate a buffer for name information. */ + objectNameInfo = ExAllocatePoolWithTag( + PagedPool, + CAPTURE_HANDLE_BUFFER_SIZE, + TAG_CAPTURE_TEMP_BUFFER + ); + + if (!objectNameInfo) + goto CleanupObject; + + /* Query the name of the object. */ + status = KphQueryNameObject( + object, + objectNameInfo, + CAPTURE_HANDLE_BUFFER_SIZE, + &returnLength + ); + + if (!NT_SUCCESS(status)) + goto CleanupName; + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock( + sizeof(KPHSS_HANDLE) + sizeof(KPHSS_WSTRING) + sizeof(KPHSS_WSTRING) + + objectTypeName->Length + objectNameInfo->Length, + HandleArgument + ); + + if (!argumentBlock) + goto CleanupName; + + /* Copy the type name into the block. */ + argumentBlock->Handle.TypeNameOffset = sizeof(KPHSS_HANDLE); + wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(&argumentBlock->Handle, argumentBlock->Handle.TypeNameOffset); + wString->Length = objectTypeName->Length; + memcpy(&wString->Buffer, objectTypeName->Buffer, wString->Length); + + /* Copy the object name into the block. */ + argumentBlock->Handle.NameOffset = + argumentBlock->Handle.TypeNameOffset + sizeof(KPHSS_WSTRING) + + wString->Length; + wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(&argumentBlock->Handle, argumentBlock->Handle.NameOffset); + wString->Length = objectNameInfo->Length; + memcpy(&wString->Buffer, objectNameInfo->Buffer, wString->Length); + + *ArgumentBlock = argumentBlock; + +CleanupName: + ExFreePoolWithTag(objectNameInfo, TAG_CAPTURE_TEMP_BUFFER); +CleanupObject: + ObDereferenceObject(object); + + return status; +} + +/* KphpSsMatchRuleSetEntry + * + * Determines if a ruleset is relevant to an event. + * + * Note: This function is inlined for performance reasons. + */ +FORCEINLINE BOOLEAN KphpSsMatchRuleSetEntry( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments, + __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable, + __in PKTHREAD Thread, + __in KPROCESSOR_MODE PreviousMode + ) +{ + PLIST_ENTRY currentListEntry; + BOOLEAN isRuleSetMatch = FALSE; + + /* Get the default filter type. If it is the Include + * filter type, we assume the ruleset matches. If it + * is the Exclude filter type, we assume it doesn't. + */ + if (RuleSetEntry->DefaultFilterType == IncludeFilterType) + isRuleSetMatch = TRUE; + else if (RuleSetEntry->DefaultFilterType == ExcludeFilterType) + isRuleSetMatch = FALSE; + + ExAcquireFastMutex(&RuleSetEntry->RuleListMutex); + + currentListEntry = RuleSetEntry->RuleListHead.Flink; + + while (currentListEntry != &RuleSetEntry->RuleListHead) + { + PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry); + BOOLEAN isRuleMatch = FALSE; + + /* Check if the rule is initialized. */ + if (!ruleEntry->Initialized) + { + currentListEntry = currentListEntry->Flink; + continue; + } + + /* Attempt to match the rule. All rule types are + * considered in this one function. + */ + switch (ruleEntry->RuleType) + { + case ProcessIdRuleType: + if (PsGetProcessId(IoThreadToProcess(Thread)) == + ruleEntry->ProcessIdRule.ProcessId) + isRuleMatch = TRUE; + break; + case ThreadIdRuleType: + if (PsGetThreadId(Thread) == ruleEntry->ThreadIdRule.ThreadId) + isRuleMatch = TRUE; + break; + case PreviousModeRuleType: + if (PreviousMode == ruleEntry->PreviousModeRule.PreviousMode) + isRuleMatch = TRUE; + break; + case NumberRuleType: + if (Number == ruleEntry->NumberRule.Number) + isRuleMatch = TRUE; + break; + } + + /* Now that we have attempted to match the rule, we + * must look at the rule filter type to determine + * whether we should continue: + * + * * For the Include filter type, we note that the + * we have a match, but we still have to continue + * going down the rule list since there may be + * Exclude filters. + * * For the Exclude filter type, we can simply stop + * the matching and return - Exclude filters take + * precedence. + */ + if (isRuleMatch) + { + if (ruleEntry->FilterType == IncludeFilterType) + { + isRuleSetMatch = TRUE; + } + else if (ruleEntry->FilterType == ExcludeFilterType) + { + isRuleSetMatch = FALSE; + break; + } + } + + currentListEntry = currentListEntry->Flink; + } + + ExReleaseFastMutex(&RuleSetEntry->RuleListMutex); + + return isRuleSetMatch; +} + +/* Functions */ VOID NTAPI KphpSsClientEntryDeleteProcedure( __in PVOID Object, @@ -113,14 +407,27 @@ VOID NTAPI KphpSsClientEntryDeleteProcedure( __in SIZE_T Size ); -VOID NTAPI KphpSsProcessEntryDeleteProcedure( +VOID NTAPI KphpSsRuleSetEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags, + __in SIZE_T Size + ); + +NTSTATUS KphpSsAddRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPHSS_RULE_TYPE RuleType + ); + +VOID NTAPI KphpSsRuleEntryDeleteProcedure( __in PVOID Object, __in ULONG Flags, __in SIZE_T Size ); NTSTATUS KphpSsCreateEventBlock( - __out PKPHPSS_EVENT_BLOCK *EventBlock, + __out PKPHSS_EVENT_BLOCK *EventBlock, __in PKTHREAD Thread, __in ULONG Number, __in ULONG *Arguments, @@ -128,12 +435,24 @@ NTSTATUS KphpSsCreateEventBlock( ); VOID KphpSsFreeEventBlock( - __in PKPHPSS_EVENT_BLOCK EventBlock + __in PKPHSS_EVENT_BLOCK EventBlock + ); + +NTSTATUS KphpSsCreateArgumentBlock( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in ULONG Number, + __in ULONG Argument, + __in ULONG Index + ); + +VOID KphpSsFreeArgumentBlock( + __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock ); NTSTATUS KphpSsWriteBlock( __in PKPHSS_CLIENT_ENTRY ClientEntry, - __in PKPHPSS_BLOCK_HEADER Block + __in_opt PKPHSS_BLOCK_HEADER Block, + __in KPHSS_SEQUENCE_MODE SequenceMode ); VOID NTAPI KphpSsLogSystemServiceCall( @@ -146,25 +465,4 @@ VOID NTAPI KphpSsLogSystemServiceCall( VOID NTAPI KphpSsNewKiFastCallEntry(); -/* KphpSsIsProcessEntryRelevant - * - * Returns whether a system service call should be logged based on - * a process entry. - */ -FORCEINLINE BOOLEAN KphpSsIsProcessEntryRelevant( - __in PKPHSS_PROCESS_ENTRY ProcessEntry, - __in PEPROCESS Process, - __in KPROCESSOR_MODE PreviousMode - ) -{ - return - /* Check if the process entry is referring to the caller. */ - ProcessEntry->TargetProcess == Process && - /* Check the mode. */ - ( - ((ProcessEntry->Flags & KPHSS_LOG_USER_MODE) && (PreviousMode == UserMode)) || - ((ProcessEntry->Flags & KPHSS_LOG_KERNEL_MODE) && (PreviousMode == KernelMode)) - ); -} - #endif diff --git a/trunk/KProcessHacker/include/version.h b/trunk/KProcessHacker/include/version.h index fb3f1aa7c..c2ed977c9 100644 --- a/trunk/KProcessHacker/include/version.h +++ b/trunk/KProcessHacker/include/version.h @@ -96,6 +96,7 @@ EXT ULONG OffEpProtectedProcessOff; EXT ULONG OffEpProtectedProcessBit; EXT ULONG OffEpRundownProtect; EXT ULONG OffOhBody; +EXT ULONG OffOtName; EXT ULONG OffOtiGenericMapping; EXT ULONG OffOtiOpenProcedure; @@ -108,6 +109,10 @@ EXT KV_SCANPROC PspTerminateThreadByPointerScan SCANNULL; /* System Call Numbers */ -EXT ULONG SysCallZwContinue; +EXT ULONG SsNtAddAtom; +EXT ULONG SsNtAlertResumeThread; +EXT ULONG SsNtClose; +EXT ULONG SsNtContinue; +EXT ULONG SsNtDelayExecution; #endif diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c index 3421e37a8..59e53d486 100644 --- a/trunk/KProcessHacker/kprocesshacker.c +++ b/trunk/KProcessHacker/kprocesshacker.c @@ -192,6 +192,13 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject) ExReleaseFastMutex(&ProtectionMutex); + /* Make sure system service logging is disabled. */ + if (SsStartCount > 0) + SsUnref(SsStartCount); + + /* Free system service logging structures. */ + KphSsLogDeinit(); + /* Free all objects in the object manager. */ KphRefDeinit(); @@ -475,62 +482,6 @@ NTSTATUS ReferenceClientHandle( return status; } -/* from YAPM */ -NTSTATUS GetObjectName(PFILE_OBJECT FileObject, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength) -{ - ULONG nameLength = 0; - PFILE_OBJECT relatedFile; - PVOID name = Buffer; - - if (FileObject->DeviceObject) - { - ObQueryNameString((PVOID)FileObject->DeviceObject, name, BufferLength, ReturnLength); - (PCHAR)name += *ReturnLength - 2; /* minus the null terminator */ - BufferLength -= *ReturnLength - 2; - } - else - { - /* It's a UNICODE_STRING. we need to subtract the space - * Length and MaximumLength take up. - */ - (PCHAR)name += 4; - BufferLength -= 4; - } - - if (!FileObject->FileName.Buffer) - return STATUS_SUCCESS; - - relatedFile = FileObject; - - do - { - nameLength += relatedFile->FileName.Length; - relatedFile = relatedFile->RelatedFileObject; - } - while (relatedFile); - - *ReturnLength += nameLength; - - if (nameLength > BufferLength) - { - return STATUS_BUFFER_TOO_SMALL; - } - - (PCHAR)name += nameLength; - *(PUSHORT)name = 0; - - relatedFile = FileObject; - do - { - (PCHAR)name -= relatedFile->FileName.Length; - memcpy(name, relatedFile->FileName.Buffer, relatedFile->FileName.Length); - relatedFile = relatedFile->RelatedFileObject; - } - while (relatedFile); - - return STATUS_SUCCESS; -} - PCHAR GetIoControlName(ULONG ControlCode) { switch (ControlCode) @@ -623,8 +574,12 @@ PCHAR GetIoControlName(ULONG ControlCode) return "SsUnref"; case KPH_SSCREATECLIENTENTRY: return "SsCreateClientEntry"; - case KPH_SSCREATEPROCESSENTRY: - return "SsCreateProcessEntry"; + case KPH_SSCREATERULESETENTRY: + return "SsCreateRuleSetEntry"; + case KPH_SSREMOVERULE: + return "SsRemoveRule"; + case KPH_SSADDPROCESSIDRULE: + return "SsAddProcessIdRule"; default: return "Unknown"; } @@ -731,22 +686,14 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) __try { - if (((PFILE_OBJECT)object)->Busy || ((PFILE_OBJECT)object)->Waiters) - { - status = GetObjectName((PFILE_OBJECT)object, dataBuffer, outLength, &retLength); - ObDereferenceObject(object); - } - else - { - status = ObQueryNameString( - object, (POBJECT_NAME_INFORMATION)dataBuffer, outLength, &retLength); - ObDereferenceObject(object); - } + status = KphQueryNameFileObject(object, dataBuffer, outLength, &retLength); } __except (EXCEPTION_EXECUTE_HANDLER) { - status = STATUS_ACCESS_VIOLATION; + status = GetExceptionCode(); } + + ObDereferenceObject(object); } break; @@ -1302,7 +1249,7 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) { HANDLE ProcessHandle; HANDLE Handle; - ULONG ObjectInformationClass; + OBJECT_INFORMATION_CLASS ObjectInformationClass; } *args = dataBuffer; struct { @@ -2006,24 +1953,24 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) } break; - /* SsCreateProcessEntry + /* SsCreateRuleSetEntry * - * Creates a system service logging process entry. + * Creates a system service logging ruleset entry. */ - case KPH_SSCREATEPROCESSENTRY: + case KPH_SSCREATERULESETENTRY: { struct { HANDLE ClientEntryHandle; - HANDLE TargetProcessHandle; - ULONG Flags; + KPHSS_FILTER_TYPE DefaultFilterType; + KPHSS_RULESET_ACTION Action; } *args = dataBuffer; struct { - HANDLE ProcessEntryHandle; + HANDLE RuleSetEntryHandle; } *ret = dataBuffer; PKPHSS_CLIENT_ENTRY clientEntry; - PKPHSS_PROCESS_ENTRY processEntry; + PKPHSS_RULESET_ENTRY ruleSetEntry; CHECK_IN_OUT_LENGTH; @@ -2032,19 +1979,87 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) if (!NT_SUCCESS(status)) goto IoControlEnd; - status = KphSsCreateProcessEntry( - &processEntry, + status = KphSsCreateRuleSetEntry( + &ruleSetEntry, clientEntry, - args->TargetProcessHandle, - args->Flags + args->DefaultFilterType, + args->Action ); KphDereferenceObject(clientEntry); if (!NT_SUCCESS(status)) goto IoControlEnd; - status = CreateClientHandle(NULL, processEntry, &ret->ProcessEntryHandle); - KphDereferenceObject(processEntry); + status = CreateClientHandle(NULL, ruleSetEntry, &ret->RuleSetEntryHandle); + KphDereferenceObject(ruleSetEntry); + retLength = sizeof(*ret); + } + break; + + /* SsRemoveRule + * + * Removes a rule from a ruleset. + */ + case KPH_SSREMOVERULE: + { + struct + { + HANDLE RuleSetEntryHandle; + HANDLE RuleEntryHandle; + } *args = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + + CHECK_IN_LENGTH; + + status = ReferenceClientHandle(NULL, args->RuleSetEntryHandle, &ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = KphSsRemoveRule(ruleSetEntry, args->RuleEntryHandle); + KphDereferenceObject(ruleSetEntry); + } + break; + + /* SsAddProcessIdRule + * + * Adds a process ID rule to a ruleset. + */ + case KPH_SSADDPROCESSIDRULE: + { + struct + { + HANDLE RuleSetEntryHandle; + KPHSS_FILTER_TYPE FilterType; + HANDLE ProcessId; + } *args = dataBuffer; + struct + { + HANDLE RuleEntryHandle; + } *ret = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + PKPHSS_RULE_ENTRY ruleEntry; + + CHECK_IN_OUT_LENGTH; + + status = ReferenceClientHandle(NULL, args->RuleSetEntryHandle, &ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = KphSsAddProcessIdRule( + &ruleEntry, + ruleSetEntry, + args->FilterType, + args->ProcessId + ); + KphDereferenceObject(ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = CreateClientHandle(NULL, ruleEntry, &ret->RuleEntryHandle); + KphDereferenceObject(ruleEntry); retLength = sizeof(*ret); } break; diff --git a/trunk/KProcessHacker/ob.c b/trunk/KProcessHacker/ob.c index ccc055b6b..7e20ecd59 100644 --- a/trunk/KProcessHacker/ob.c +++ b/trunk/KProcessHacker/ob.c @@ -280,6 +280,117 @@ NTSTATUS KphOpenNamedObject( return status; } +/* KphQueryFileObjectName + * + * Queries the name of a file object. + * + * From YAPM. + */ +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + ULONG returnLength = 0; + ULONG nameLength = 0; + /* Pointer to the parent of the current file object. */ + PFILE_OBJECT relatedFileObject; + PVOID name = Buffer; + + /* Check if the file object has an associated device. */ + if (FileObject->DeviceObject) + { + /* Query the name of the device (e.g. "\Device\HarddiskVolume1"). */ + ObQueryNameString(FileObject->DeviceObject, name, BufferLength, &returnLength); + /* Add on the length, in bytes, of the name we just queried + * (minus the null terminator, since the return length + * includes that). + */ + (PCHAR)name += returnLength - sizeof(WCHAR); + BufferLength -= returnLength - sizeof(WCHAR); + } + else + { + (PCHAR)name += sizeof(UNICODE_STRING); + BufferLength -= sizeof(UNICODE_STRING); + } + + if (!FileObject->FileName.Buffer) + return STATUS_SUCCESS; + + /* Walk up the file object tree to get the total length needed. */ + + relatedFileObject = FileObject; + + do + { + nameLength += relatedFileObject->FileName.Length; + relatedFileObject = relatedFileObject->RelatedFileObject; + } + while (relatedFileObject); + + returnLength += nameLength; + + if (nameLength + sizeof(UNICODE_STRING) > BufferLength) + { + return STATUS_BUFFER_TOO_SMALL; + } + + /* We are going to copy over the individual paths in reverse order. */ + + (PCHAR)name += nameLength; + /* Write the null terminator. */ + *(PUSHORT)name = 0; + + relatedFileObject = FileObject; + do + { + (PCHAR)name -= relatedFileObject->FileName.Length; + memcpy(name, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length); + relatedFileObject = relatedFileObject->RelatedFileObject; + } + while (relatedFileObject); + + /* Write some length information. */ + /* FIXME: Is the null terminator always present? */ + Buffer->Length = (USHORT)(returnLength - sizeof(UNICODE_STRING) - sizeof(WCHAR)); + + if (ReturnLength) + *ReturnLength = returnLength; + + return STATUS_SUCCESS; +} + +/* KphQueryObjectName + * + * Queries the name of an object. + */ +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + if ( + OBJECT_TO_OBJECT_HEADER(Object)->Type == *IoFileObjectType && + (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters) + ) + { + status = KphQueryNameFileObject((PFILE_OBJECT)Object, Buffer, BufferLength, ReturnLength); + } + else + { + status = ObQueryNameString(Object, (POBJECT_NAME_INFORMATION)Buffer, BufferLength, ReturnLength); + } + + return status; +} + /* KphQueryProcessHandles * * Queries a process handle table. diff --git a/trunk/KProcessHacker/sources b/trunk/KProcessHacker/sources index 399ce6505..c870dd2de 100644 --- a/trunk/KProcessHacker/sources +++ b/trunk/KProcessHacker/sources @@ -15,6 +15,7 @@ SOURCES= \ protect.c \ sync.c \ sysservice.c \ + sysservicedata.c \ trace.c \ \ io.c \ diff --git a/trunk/KProcessHacker/sysservice.c b/trunk/KProcessHacker/sysservice.c index b8f5b8a0f..3deb135f7 100644 --- a/trunk/KProcessHacker/sysservice.c +++ b/trunk/KProcessHacker/sysservice.c @@ -36,6 +36,7 @@ extern PDRIVER_OBJECT KphDriverObject; +/* A fast mutex guarding starting/stopping system service logging. */ FAST_MUTEX KphSsMutex; /* Whether system service logging has been initialized. */ BOOLEAN KphSsInitialized = FALSE; @@ -44,11 +45,17 @@ KPH_HOOK KphSsKiFastCallEntryHook; /* The number of active loggers. */ ULONG KphSsNumberOfActiveLoggers = 0; +/* The object type for client entries. */ PKPH_OBJECT_TYPE KphSsClientEntryType; -PKPH_OBJECT_TYPE KphSsProcessEntryType; +/* The object type for ruleset entries. */ +PKPH_OBJECT_TYPE KphSsRuleSetEntryType; +/* The object type for rule entries. */ +PKPH_OBJECT_TYPE KphSsRuleEntryType; -FAST_MUTEX KphSsProcessListMutex; -LIST_ENTRY KphSsProcessListHead; +/* A fast mutex guarding all accesses to the ruleset list. */ +FAST_MUTEX KphSsRuleSetListMutex; +/* The list of ruleset entries. */ +LIST_ENTRY KphSsRuleSetListHead; /* KphSsLogInit * @@ -58,10 +65,13 @@ NTSTATUS KphSsLogInit() { NTSTATUS status = STATUS_SUCCESS; + /* Initialize the system service call data. */ + KphSsDataInit(); + /* Initialize the process list. */ - InitializeListHead(&KphSsProcessListHead); + InitializeListHead(&KphSsRuleSetListHead); ExInitializeFastMutex(&KphSsMutex); - ExInitializeFastMutex(&KphSsProcessListMutex); + ExInitializeFastMutex(&KphSsRuleSetListMutex); /* Initialize the object types. */ status = KphCreateObjectType( @@ -74,9 +84,9 @@ NTSTATUS KphSsLogInit() return status; status = KphCreateObjectType( - &KphSsProcessEntryType, + &KphSsRuleSetEntryType, NonPagedPool, - KphpSsProcessEntryDeleteProcedure + KphpSsRuleSetEntryDeleteProcedure ); if (!NT_SUCCESS(status)) @@ -85,9 +95,33 @@ NTSTATUS KphSsLogInit() return status; } + status = KphCreateObjectType( + &KphSsRuleEntryType, + NonPagedPool, + NULL + ); + + if (!NT_SUCCESS(status)) + { + KphDereferenceObject(KphSsClientEntryType); + KphDereferenceObject(KphSsRuleSetEntryType); + return status; + } + return status; } +/* KphSsLogDeinit + * + * Frees system service logging data. + */ +NTSTATUS KphSsLogDeinit() +{ + KphSsDataDeinit(); + + return STATUS_SUCCESS; +} + /* KphSsLogStart * * Starts system service logging. @@ -167,7 +201,7 @@ NTSTATUS KphSsLogStop() * * Creates a client entry which describes a client of the * system service logger. Clients receieve system service log events. - * Note that a client may have several process entries associated + * Note that a client may have several ruleset entries associated * with it. * * ClientEntry: A variable which receives a pointer to the client entry. @@ -284,6 +318,8 @@ NTSTATUS KphSsCreateClientEntry( clientEntry->BufferBase = BufferBase; clientEntry->BufferSize = BufferSize; clientEntry->BufferCursor = 0; + clientEntry->NumberOfBlocksWritten = 0; + clientEntry->NumberOfBlocksDropped = 0; *ClientEntry = clientEntry; @@ -307,91 +343,291 @@ VOID NTAPI KphpSsClientEntryDeleteProcedure( ObDereferenceObject(clientEntry->WriteSemaphore); } -/* KphSsCreateProcessEntry +/* KphSsCreateRuleSetEntry * - * Creates a process entry which describes a process for which - * system services will be logged. + * Creates a ruleset entry which contains a list of rules + * and an action to perform. */ -NTSTATUS KphSsCreateProcessEntry( - __out PKPHSS_PROCESS_ENTRY *ProcessEntry, +NTSTATUS KphSsCreateRuleSetEntry( + __out PKPHSS_RULESET_ENTRY *RuleSetEntry, __in PKPHSS_CLIENT_ENTRY ClientEntry, - __in HANDLE TargetProcessHandle, - __in ULONG Flags + __in KPHSS_FILTER_TYPE DefaultFilterType, + __in KPHSS_RULESET_ACTION Action ) { NTSTATUS status = STATUS_SUCCESS; - PKPHSS_PROCESS_ENTRY processEntry; - PEPROCESS processObject; + PKPHSS_RULESET_ENTRY ruleSetEntry; - /* Check if the flags are valid. */ - if ((Flags & KPHSS_LOG_VALID_FLAGS) != Flags) - return STATUS_INVALID_PARAMETER_4; + /* Make sure the action is valid. */ + if (Action < LogRuleSetAction || Action >= MaxRuleSetAction) + return STATUS_INVALID_PARAMETER_3; - /* If the caller didn't specify any mode flags, assume both modes. */ - if (!(Flags & (KPHSS_LOG_USER_MODE | KPHSS_LOG_KERNEL_MODE))) - Flags |= KPHSS_LOG_USER_MODE | KPHSS_LOG_KERNEL_MODE; - - /* Reference the process object. Note that we don't actually - * need to keep the process object alive since we don't - * access it at any point. - */ - status = ObReferenceObjectByHandle( - TargetProcessHandle, - 0, - *PsProcessType, - KernelMode, - &processObject, - NULL - ); - - if (!NT_SUCCESS(status)) - return status; - - ObDereferenceObject(processObject); - - /* Create the process entry object. */ + /* Create the ruleset object. */ status = KphCreateObject( - &processEntry, - sizeof(KPHSS_PROCESS_ENTRY), + &ruleSetEntry, + sizeof(KPHSS_RULESET_ENTRY), 0, - KphSsProcessEntryType, + KphSsRuleSetEntryType, 0 ); if (!NT_SUCCESS(status)) return status; + /* Initialize the ruleset object. */ KphReferenceObject(ClientEntry); - processEntry->Client = ClientEntry; - processEntry->TargetProcess = processObject; - processEntry->Flags = Flags; + ruleSetEntry->Client = ClientEntry; + ruleSetEntry->DefaultFilterType = DefaultFilterType; + ruleSetEntry->Action = Action; + ruleSetEntry->NextRuleHandle = 4; + ExInitializeFastMutex(&ruleSetEntry->RuleListMutex); + InitializeListHead(&ruleSetEntry->RuleListHead); - ExAcquireFastMutex(&KphSsProcessListMutex); - InsertHeadList(&KphSsProcessListHead, &processEntry->ProcessListEntry); - ExReleaseFastMutex(&KphSsProcessListMutex); + /* Add the ruleset to the list. */ + ExAcquireFastMutex(&KphSsRuleSetListMutex); + InsertHeadList(&KphSsRuleSetListHead, &ruleSetEntry->RuleSetListEntry); + ExReleaseFastMutex(&KphSsRuleSetListMutex); - *ProcessEntry = processEntry; + *RuleSetEntry = ruleSetEntry; return status; } -/* KphpSsProcessEntryDeleteProcedure +/* KphpSsRuleSetEntryDeleteProcedure * - * Performs cleanup for a process entry. + * Performs cleanup for a ruleset entry. */ -VOID NTAPI KphpSsProcessEntryDeleteProcedure( +VOID NTAPI KphpSsRuleSetEntryDeleteProcedure( __in PVOID Object, __in ULONG Flags, __in SIZE_T Size ) { - PKPHSS_PROCESS_ENTRY processEntry = (PKPHSS_PROCESS_ENTRY)Object; + PKPHSS_RULESET_ENTRY ruleSetEntry = (PKPHSS_RULESET_ENTRY)Object; + PLIST_ENTRY currentRuleListEntry; - KphDereferenceObject(processEntry->Client); + /* Dereference the client entry. */ + KphDereferenceObject(ruleSetEntry->Client); - ExAcquireFastMutex(&KphSsProcessListMutex); - RemoveEntryList(&processEntry->ProcessListEntry); - ExReleaseFastMutex(&KphSsProcessListMutex); + /* Dereference all rules in the ruleset. */ + ExAcquireFastMutex(&ruleSetEntry->RuleListMutex); + + currentRuleListEntry = ruleSetEntry->RuleListHead.Flink; + + while (currentRuleListEntry != &ruleSetEntry->RuleListHead) + { + KphDereferenceObject(KPHSS_RULE_ENTRY(currentRuleListEntry)); + currentRuleListEntry = currentRuleListEntry->Flink; + } + + ExReleaseFastMutex(&ruleSetEntry->RuleListMutex); + + /* Remove the ruleset from the list. */ + ExAcquireFastMutex(&KphSsRuleSetListMutex); + RemoveEntryList(&ruleSetEntry->RuleSetListEntry); + ExReleaseFastMutex(&KphSsRuleSetListMutex); +} + +/* KphSsAddProcessIdRule + * + * Adds a process ID rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddProcessIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ProcessId + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ProcessIdRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->ProcessIdRule.ProcessId = ProcessId; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddThreadIdRule + * + * Adds a thread ID rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddThreadIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ThreadId + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ThreadIdRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->ThreadIdRule.ThreadId = ThreadId; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddPreviousModeRule + * + * Adds a previous mode rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddPreviousModeRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, PreviousModeRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->PreviousModeRule.PreviousMode = PreviousMode; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddNumberRule + * + * Adds a system service number rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddNumberRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in ULONG Number + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, NumberRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->NumberRule.Number = Number; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsRemoveRule + * + * Removes a rule entry from a ruleset entry. + */ +NTSTATUS KphSsRemoveRule( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in HANDLE RuleEntryHandle + ) +{ + PLIST_ENTRY currentListEntry; + + ExAcquireFastMutex(&RuleSetEntry->RuleListMutex); + + currentListEntry = RuleSetEntry->RuleListHead.Flink; + + while (currentListEntry != &RuleSetEntry->RuleListHead) + { + PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry); + + if (ruleEntry->Handle == RuleEntryHandle) + { + RemoveEntryList(&ruleEntry->RuleListEntry); + ExReleaseFastMutex(&RuleSetEntry->RuleListMutex); + + return STATUS_SUCCESS; + } + + currentListEntry = currentListEntry->Flink; + } + + ExReleaseFastMutex(&RuleSetEntry->RuleListMutex); + + return STATUS_INVALID_PARAMETER_2; +} + +/* KphpSsAddRule + * + * Adds a rule entry to a ruleset entry. + */ +NTSTATUS KphpSsAddRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPHSS_RULE_TYPE RuleType + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Make sure the filter/rule type is valid. */ + if (FilterType < IncludeFilterType || FilterType >= MaxFilterType) + return STATUS_INVALID_PARAMETER_3; + if (RuleType < ProcessIdRuleType || RuleType >= MaxRuleType) + return STATUS_INVALID_PARAMETER_4; + + /* Create the rule entry object. */ + status = KphCreateObject( + &ruleEntry, + sizeof(KPHSS_RULE_ENTRY), + 0, + KphSsRuleEntryType, + 0 + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the object. */ + ruleEntry->Initialized = FALSE; + ruleEntry->FilterType = FilterType; + ruleEntry->RuleType = RuleType; + + /* Get a handle for the rule. */ + ruleEntry->Handle = (HANDLE)InterlockedExchangeAdd( + &RuleSetEntry->NextRuleHandle, + KPHSS_RULE_HANDLE_INCREMENT + ); + + /* Add the rule to the ruleset. */ + ExAcquireFastMutex(&RuleSetEntry->RuleListMutex); + InsertTailList(&RuleSetEntry->RuleListHead, &ruleEntry->RuleListEntry); + ExReleaseFastMutex(&RuleSetEntry->RuleListMutex); + /* Add a reference for the rule being on the list. */ + KphReferenceObject(ruleEntry); + + *RuleEntry = ruleEntry; + + return status; } /* KphpSsCreateEventBlock @@ -405,14 +641,14 @@ VOID NTAPI KphpSsProcessEntryDeleteProcedure( * NumberOfArguments: The number of arguments, in ULONGs. */ NTSTATUS KphpSsCreateEventBlock( - __out PKPHPSS_EVENT_BLOCK *EventBlock, + __out PKPHSS_EVENT_BLOCK *EventBlock, __in PKTHREAD Thread, __in ULONG Number, __in ULONG *Arguments, __in ULONG NumberOfArguments ) { - PKPHPSS_EVENT_BLOCK eventBlock; + PKPHSS_EVENT_BLOCK eventBlock; KPROCESSOR_MODE previousMode; ULONG eventBlockSize; ULONG argumentsSize; @@ -451,11 +687,7 @@ NTSTATUS KphpSsCreateEventBlock( /* Calculate the size of the event block. */ argumentsSize = NumberOfArguments * sizeof(ULONG); traceSize = capturedFrames * sizeof(PVOID); - eventBlockSize = sizeof(KPHPSS_EVENT_BLOCK) + argumentsSize + traceSize; - - /* Check if the event block is too large. */ - if (eventBlockSize > KPHPSS_EVENT_BLOCK_MAX_SIZE) - return STATUS_UNSUCCESSFUL; + eventBlockSize = sizeof(KPHSS_EVENT_BLOCK) + argumentsSize + traceSize; /* Allocate the event block. */ eventBlock = ExAllocatePoolWithTag(PagedPool, eventBlockSize, TAG_EVENT_BLOCK); @@ -472,15 +704,15 @@ NTSTATUS KphpSsCreateEventBlock( eventBlock->ClientId.UniqueProcess = PsGetProcessId(IoThreadToProcess(Thread)); eventBlock->Number = Number; eventBlock->NumberOfArguments = NumberOfArguments; - eventBlock->ArgumentsOffset = sizeof(KPHPSS_EVENT_BLOCK); + eventBlock->ArgumentsOffset = sizeof(KPHSS_EVENT_BLOCK); eventBlock->TraceCount = capturedFrames; - eventBlock->TraceOffset = sizeof(KPHPSS_EVENT_BLOCK) + argumentsSize; + eventBlock->TraceOffset = sizeof(KPHSS_EVENT_BLOCK) + argumentsSize; /* Set the flags according to the previous mode. */ if (previousMode == UserMode) - eventBlock->Flags |= KPHPSS_EVENT_USER_MODE; + eventBlock->Flags |= KPHSS_EVENT_USER_MODE; else if (previousMode == KernelMode) - eventBlock->Flags |= KPHPSS_EVENT_KERNEL_MODE; + eventBlock->Flags |= KPHSS_EVENT_KERNEL_MODE; /* Probe and copy the arguments. */ if (previousMode != KernelMode) @@ -491,7 +723,7 @@ NTSTATUS KphpSsCreateEventBlock( } __except (EXCEPTION_EXECUTE_HANDLER) { - eventBlock->Flags |= KPHPSS_EVENT_PROBE_ARGUMENTS_FAILED; + eventBlock->Flags |= KPHSS_EVENT_PROBE_ARGUMENTS_FAILED; } } @@ -502,7 +734,7 @@ NTSTATUS KphpSsCreateEventBlock( } __except (EXCEPTION_EXECUTE_HANDLER) { - eventBlock->Flags |= KPHPSS_EVENT_COPY_ARGUMENTS_FAILED; + eventBlock->Flags |= KPHSS_EVENT_COPY_ARGUMENTS_FAILED; } /* Copy the stack trace. */ @@ -519,19 +751,104 @@ NTSTATUS KphpSsCreateEventBlock( * Frees an event block created by KphpSsCreateEventBlock. */ VOID KphpSsFreeEventBlock( - __in PKPHPSS_EVENT_BLOCK EventBlock + __in PKPHSS_EVENT_BLOCK EventBlock ) { ExFreePoolWithTag(EventBlock, TAG_EVENT_BLOCK); } +/* KphpSsCreateArgumentBlock + * + * Allocates and initializes an argument block. + */ +NTSTATUS KphpSsCreateArgumentBlock( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in ULONG Number, + __in ULONG Argument, + __in ULONG Index + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + PKPHSS_CALL_ENTRY callEntry; + KPHSS_ARGUMENT_TYPE argumentType; + + /* Get a pointer to the call entry for the system service. + * If we don't have one, we can't proceed. + */ + callEntry = KphSsLookupCallEntry(Number); + + if (!callEntry) + return STATUS_INVALID_PARAMETER_2; + + /* Validate the argument index. */ + if (Index >= callEntry->NumberOfArguments) + return STATUS_INVALID_PARAMETER_3; + + /* Is this a normal argument? If so, there's no point + * creating an argument block since the data is already + * in the event block. + */ + argumentType = callEntry->Arguments[Index]; + + if (argumentType == NormalArgument) + return STATUS_UNSUCCESSFUL; + + /* Capture the argument. */ + + switch (argumentType) + { + case Int8Argument: + case Int16Argument: + case Int32Argument: + case Int64Argument: + status = KphpSsCaptureSimple( + &argumentBlock, + (PVOID)Argument, + argumentType + ); + break; + case HandleArgument: + status = KphpSsCaptureHandle( + &argumentBlock, + (HANDLE)Argument + ); + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (!NT_SUCCESS(status)) + return status; + + /* Put the index in. */ + argumentBlock->Index = Index; + + *ArgumentBlock = argumentBlock; + + return status; +} + +/* KphpSsFreeArgumentBlock + * + * Frees an argument block created by KphpSsCreateArgumentBlock. + */ +VOID KphpSsFreeArgumentBlock( + __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock + ) +{ + ExFreePoolWithTag(ArgumentBlock, TAG_ARGUMENT_BLOCK); +} + /* KphpSsWriteBlock * * Writes a block into client memory. */ NTSTATUS KphpSsWriteBlock( __in PKPHSS_CLIENT_ENTRY ClientEntry, - __in PKPHPSS_BLOCK_HEADER Block + __in_opt PKPHSS_BLOCK_HEADER Block, + __in KPHSS_SEQUENCE_MODE SequenceMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -541,7 +858,35 @@ NTSTATUS KphpSsWriteBlock( zeroTimeout.QuadPart = 0; - ExAcquireFastMutex(&ClientEntry->BufferMutex); + /* Take care of the sequence mode. If it isn't + * NoSequence, it is effectively a way for the caller + * to control the buffer mutex. + */ + if (SequenceMode == StartSequence) + { + ExAcquireFastMutex(&ClientEntry->BufferMutex); + return STATUS_SUCCESS; + } + else if (SequenceMode == EndSequence) + { + ExReleaseFastMutex(&ClientEntry->BufferMutex); + return STATUS_SUCCESS; + } + else + { + /* If we aren't manipulating the mutex, we need + * a block to write. + */ + if (!Block) + return STATUS_INVALID_PARAMETER_2; + + /* If we're in a sequence, don't acquire the mutex + * because the caller would have acquired it using + * StartSequence already. + */ + if (SequenceMode != InSequence) + ExAcquireFastMutex(&ClientEntry->BufferMutex); + } /* Try to acquire the write semaphore. If we can't acquire * it immediately, drop the block. @@ -554,13 +899,15 @@ NTSTATUS KphpSsWriteBlock( &zeroTimeout ); - if (!NT_SUCCESS(status) || status == STATUS_TIMEOUT) + if (!KPHSS_BLOCK_SUCCESS(status)) { if (status == STATUS_TIMEOUT) - dfprintf("Ss: WARNING: Dropped block (server %#x).\n", ClientEntry->BufferCursor); + { + dprintf("Ss: WARNING: Dropped block (server %#x).\n", ClientEntry->BufferCursor); + ClientEntry->NumberOfBlocksDropped++; + } - ExReleaseFastMutex(&ClientEntry->BufferMutex); - return status; + goto CleanupBufferMutex; } availableSpace = ClientEntry->BufferSize - ClientEntry->BufferCursor; @@ -574,23 +921,23 @@ NTSTATUS KphpSsWriteBlock( */ /* Check if we have enough space for a block header. */ - if (availableSpace < sizeof(KPHPSS_BLOCK_HEADER)) + if (availableSpace < sizeof(KPHSS_BLOCK_HEADER)) { /* Not enough space. Reset the cursor. */ - dfprintf("Ss: Implicit cursor reset (server %#x).\n", ClientEntry->BufferCursor); + dprintf("Ss: Implicit cursor reset (server %#x).\n", ClientEntry->BufferCursor); ClientEntry->BufferCursor = 0; availableSpace = ClientEntry->BufferSize; } /* Check if we have enough space for the block. */ else if (availableSpace < Block->Size) { - KPHPSS_RESET_BLOCK resetBlock; + KPHSS_RESET_BLOCK resetBlock; /* Not enough space for the block, but enough space * for a reset block. Write the reset block and reset * the cursor. */ - resetBlock.Header.Size = sizeof(KPHPSS_RESET_BLOCK); + resetBlock.Header.Size = sizeof(KPHSS_RESET_BLOCK); resetBlock.Header.Type = ResetBlockType; /* Attach to the client process and copy the block. */ @@ -607,12 +954,11 @@ NTSTATUS KphpSsWriteBlock( __except (EXCEPTION_EXECUTE_HANDLER) { KphDetachProcess(&attachState); - ExReleaseFastMutex(&ClientEntry->BufferMutex); - - return GetExceptionCode(); + status = GetExceptionCode(); + goto CleanupBufferMutex; } - dfprintf("Ss: Wrote reset block (server %#x).\n", ClientEntry->BufferCursor); + dprintf("Ss: Wrote reset block (server %#x).\n", ClientEntry->BufferCursor); KphDetachProcess(&attachState); ClientEntry->BufferCursor = 0; availableSpace = ClientEntry->BufferSize; @@ -626,8 +972,8 @@ NTSTATUS KphpSsWriteBlock( if (availableSpace < Block->Size) { dfprintf("Ss: WARNING: Insufficient buffer size (server %#x).\n", ClientEntry->BufferCursor); - ExReleaseFastMutex(&ClientEntry->BufferMutex); - return STATUS_BUFFER_TOO_SMALL; + status = STATUS_BUFFER_TOO_SMALL; + goto CleanupBufferMutex; } /* Time to copy the block into the buffer. @@ -646,8 +992,8 @@ NTSTATUS KphpSsWriteBlock( { dfprintf("Ss: ERROR: Could not write to the client buffer (server %#x)!\n", ClientEntry->BufferCursor); KphDetachProcess(&attachState); - ExReleaseFastMutex(&ClientEntry->BufferMutex); - return GetExceptionCode(); + status = GetExceptionCode(); + goto CleanupBufferMutex; } KphDetachProcess(&attachState); @@ -665,15 +1011,18 @@ NTSTATUS KphpSsWriteBlock( __except (EXCEPTION_EXECUTE_HANDLER) { dfprintf("Ss: ERROR: Could not release read semaphore (server %#x)!\n", ClientEntry->BufferCursor); - ExReleaseFastMutex(&ClientEntry->BufferMutex); - return GetExceptionCode(); + status = GetExceptionCode(); + goto CleanupBufferMutex; } ClientEntry->BufferCursor += Block->Size; + ClientEntry->NumberOfBlocksWritten++; - dfprintf("Ss: Wrote block (server %#x).\n", ClientEntry->BufferCursor); + dprintf("Ss: Wrote block (server %#x).\n", ClientEntry->BufferCursor); - ExReleaseFastMutex(&ClientEntry->BufferMutex); +CleanupBufferMutex: + if (SequenceMode != InSequence) + ExReleaseFastMutex(&ClientEntry->BufferMutex); return status; } @@ -694,13 +1043,14 @@ VOID NTAPI KphpSsLogSystemServiceCall( __in PKTHREAD Thread ) { + NTSTATUS status = STATUS_SUCCESS; KPROCESSOR_MODE previousMode; - PEPROCESS process; PLIST_ENTRY currentListEntry; - PKPHSS_PROCESS_ENTRY processEntryArray[KPHSS_PROCESS_ENTRY_LIMIT]; - ULONG processEntryCount; - PKPHPSS_EVENT_BLOCK eventBlock; - ULONG i; + PKPHSS_RULESET_ENTRY ruleSetEntryArray[KPHSS_RULESET_ENTRY_LIMIT]; + ULONG ruleSetEntryCount; + PKPHSS_EVENT_BLOCK eventBlock; + PKPHSS_ARGUMENT_BLOCK argumentBlockArray[KPHSS_MAXIMUM_ARGUMENT_BLOCKS]; + ULONG i, j; previousMode = KeGetPreviousMode(); /* Ignore the Thread argument. Replace it with our own. */ @@ -730,7 +1080,7 @@ VOID NTAPI KphpSsLogSystemServiceCall( * we caused an exception somewhere. */ if ( ServiceTable->Base == __KeServiceDescriptorTable->Base && - Number == SysCallZwContinue && + Number == SsNtContinue && NumberOfArguments == 2 && previousMode == KernelMode ) @@ -756,53 +1106,53 @@ VOID NTAPI KphpSsLogSystemServiceCall( } } - /* Build the process entry array by going through the process + /* Build the ruleset entry array by going through the ruleset * list, referencing each relevant one and copying them into * the local array. This we way don't hold the mutex for too * long. */ - process = IoThreadToProcess(Thread); + ExAcquireFastMutex(&KphSsRuleSetListMutex); - if (!process) /* should never happen */ - { - dfprintf("Ss: ERROR: No process for thread!\n"); - return; - } - - ExAcquireFastMutex(&KphSsProcessListMutex); - - currentListEntry = KphSsProcessListHead.Flink; - processEntryCount = 0; + currentListEntry = KphSsRuleSetListHead.Flink; + ruleSetEntryCount = 0; while ( - currentListEntry != &KphSsProcessListHead && - processEntryCount < KPHSS_PROCESS_ENTRY_LIMIT + currentListEntry != &KphSsRuleSetListHead && + ruleSetEntryCount < KPHSS_RULESET_ENTRY_LIMIT ) { - PKPHSS_PROCESS_ENTRY processEntry = KPHSS_PROCESS_ENTRY(currentListEntry); + PKPHSS_RULESET_ENTRY ruleSetEntry = KPHSS_RULESET_ENTRY(currentListEntry); if ( - KphpSsIsProcessEntryRelevant(processEntry, process, previousMode) && - /* Make sure the process entry isn't being destroyed. */ - !KphIsDestroyedObject(processEntry) + KphpSsMatchRuleSetEntry( + ruleSetEntry, + Number, + Arguments, + NumberOfArguments, + ServiceTable, + Thread, + previousMode + ) && + /* Make sure the ruleset entry isn't being destroyed. */ + !KphIsDestroyedObject(ruleSetEntry) ) { - /* Reference and store the process entry in the local array. */ - KphReferenceObject(processEntry); - processEntryArray[processEntryCount] = processEntry; - processEntryCount++; + /* Reference and store the ruleset entry in the local array. */ + KphReferenceObject(ruleSetEntry); + ruleSetEntryArray[ruleSetEntryCount] = ruleSetEntry; + ruleSetEntryCount++; } currentListEntry = currentListEntry->Flink; } - ExReleaseFastMutex(&KphSsProcessListMutex); + ExReleaseFastMutex(&KphSsRuleSetListMutex); - /* If we didn't find any process entries, don't bother creating the + /* If we didn't find any ruleset entries, don't bother creating the * event block. */ - if (processEntryCount == 0) + if (ruleSetEntryCount == 0) return; /* We have work to do. Create an event block first. */ @@ -818,18 +1168,78 @@ VOID NTAPI KphpSsLogSystemServiceCall( return; } - /* Go through the process entry array and write the block to each - * client. While we're doing that we can also dereference each - * process entry. + /* Create the argument blocks. If we fail to create one, + * set the array entry to NULL and we'll skip it later. */ - for (i = 0; i < processEntryCount; i++) + + for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++) { - KphpSsWriteBlock(processEntryArray[i]->Client, &eventBlock->Header); - KphDereferenceObject(processEntryArray[i]); + ULONG argument; + + __try + { + /* We'll assume the arguments have already been probed + * since we created the event block successfully. + */ + argument = Arguments[i]; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* The caller is probably malicious. Exit. */ + KphpSsFreeEventBlock(eventBlock); + return; + } + + status = KphpSsCreateArgumentBlock( + &argumentBlockArray[i], + Number, + argument, + i + ); + + if (!NT_SUCCESS(status)) + argumentBlockArray[i] = NULL; + } + + /* Go through the ruleset entry array and write the blocks to each + * client. While we're doing that we can also dereference each + * ruleset entry. + */ + for (i = 0; i < ruleSetEntryCount; i++) + { + /* Begin a sequence. */ + status = KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, StartSequence); + + if (NT_SUCCESS(status)) + { + /* Write the event block. */ + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &eventBlock->Header, InSequence); + + /* Write the argument blocks. */ + for (j = 0; j < NumberOfArguments && j < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; j++) + { + if (argumentBlockArray[j]) + { + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &argumentBlockArray[j]->Header, InSequence); + } + } + + /* End the sequence. */ + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, EndSequence); + } + + KphDereferenceObject(ruleSetEntryArray[i]); } /* Free the event block. */ KphpSsFreeEventBlock(eventBlock); + + /* Free the argument blocks. */ + for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++) + { + if (argumentBlockArray[i]) + KphpSsFreeArgumentBlock(argumentBlockArray[i]); + } } /* KphpSsNewKiFastCallEntry diff --git a/trunk/KProcessHacker/sysservicedata.c b/trunk/KProcessHacker/sysservicedata.c new file mode 100644 index 000000000..55ca9d8c3 --- /dev/null +++ b/trunk/KProcessHacker/sysservicedata.c @@ -0,0 +1,160 @@ +/* + * Process Hacker Driver - + * system service logging (data) + * + * Copyright (C) 2009 wj32 + * + * This file is part of Process Hacker. + * + * Process Hacker is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Process Hacker is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Process Hacker. If not, see . + */ + +#define _SYSSERVICEDATA_PRIVATE +#include "include/sysservicedata.h" + +PVOID KphpSsCallEntryAllocateRoutine( + __in PRTL_GENERIC_TABLE Table, + __in CLONG ByteSize + ); + +RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID FirstStruct, + __in PVOID SecondStruct + ); + +VOID KphpSsCallEntryFreeRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID Buffer + ); + +/* NTSTATUS NtAddAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */ +KPHSS_CALL_ENTRY SsNtAddAtomEntry = { &SsNtAddAtom, "NtAddAtom", 3, { WStringArgument, 0, Int16Argument } }; +/* NTSTATUS NtAlertResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount) */ +KPHSS_CALL_ENTRY SsNtAlertResumeThreadEntry = { &SsNtAlertResumeThread, "NtAlertResumeThread", 2, { HandleArgument, NormalArgument } }; +/* NTSTATUS NtClose(HANDLE Handle) */ +KPHSS_CALL_ENTRY SsNtCloseEntry = { &SsNtClose, "NtClose", 1, { HandleArgument } }; +/* NTSTATUS NtContinue(PCONTEXT Context, BOOLEAN TestAlert) */ +KPHSS_CALL_ENTRY SsNtContinueEntry = { &SsNtContinue, "NtContinue", 2, { ContextArgument, 0 } }; + +KPHSS_CALL_ENTRY SsEntries[] = +{ + /* NTSTATUS NtAddAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */ + { &SsNtAddAtom, "NtAddAtom", 3, { WStringArgument, 0, Int16Argument } }, + /* NTSTATUS NtAlertResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount) */ + { &SsNtAlertResumeThread, "NtAlertResumeThread", 2, { HandleArgument, NormalArgument } }, + /* NTSTATUS NtClose(HANDLE Handle) */ + { &SsNtClose, "NtClose", 1, { HandleArgument } }, + /* NTSTATUS NtContinue(PCONTEXT Context, BOOLEAN TestAlert) */ + { &SsNtContinue, "NtContinue", 2, { ContextArgument, 0 } }, + /* NTSTATUS NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER Interval) */ + { &SsNtDelayExecution, "NtDelayExecution", 2, { 0, Int64Argument } }, + + { NULL, "Dummy", 0 } +}; + +RTL_GENERIC_TABLE KphSsCallTable; + +VOID KphSsDataInit() +{ + ULONG i; + + RtlInitializeGenericTable( + &KphSsCallTable, + KphpSsCallEntryCompareRoutine, + KphpSsCallEntryAllocateRoutine, + KphpSsCallEntryFreeRoutine, + NULL + ); + + for (i = 0; i < sizeof(SsEntries) / sizeof(KPHSS_CALL_ENTRY); i++) + { + /* Ignore the dummy entry. */ + if (SsEntries[i].Number) + { + RtlInsertElementGenericTable( + &KphSsCallTable, + &SsEntries[i], + /* Save some space... */ + FIELD_OFFSET(KPHSS_CALL_ENTRY, Arguments) + + SsEntries[i].NumberOfArguments * sizeof(KPHSS_ARGUMENT_TYPE), + NULL + ); + } + } +} + +VOID KphSsDataDeinit() +{ + PKPHSS_CALL_ENTRY callEntry; + + while (callEntry = (PKPHSS_CALL_ENTRY)RtlGetElementGenericTable(&KphSsCallTable, 0)) + RtlDeleteElementGenericTable(&KphSsCallTable, callEntry); +} + +PKPHSS_CALL_ENTRY KphSsLookupCallEntry( + __in ULONG Number + ) +{ + KPHSS_CALL_ENTRY callEntry; + + callEntry.Number = &Number; + + return (PKPHSS_CALL_ENTRY)RtlLookupElementGenericTable( + &KphSsCallTable, + &callEntry + ); +} + +PVOID KphpSsCallEntryAllocateRoutine( + __in PRTL_GENERIC_TABLE Table, + __in CLONG ByteSize + ) +{ + return ExAllocatePoolWithTag( + PagedPool, + ByteSize, + TAG_CALL_ENTRY + ); +} + +RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID FirstStruct, + __in PVOID SecondStruct + ) +{ + PKPHSS_CALL_ENTRY callEntry1, callEntry2; + + callEntry1 = (PKPHSS_CALL_ENTRY)FirstStruct; + callEntry2 = (PKPHSS_CALL_ENTRY)SecondStruct; + + if (*(callEntry1->Number) < *(callEntry2->Number)) + return GenericLessThan; + else if (*(callEntry1->Number) > *(callEntry2->Number)) + return GenericGreaterThan; + else + return GenericEqual; +} + +VOID KphpSsCallEntryFreeRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID Buffer + ) +{ + ExFreePoolWithTag( + Buffer, + TAG_CALL_ENTRY + ); +} diff --git a/trunk/KProcessHacker/version.c b/trunk/KProcessHacker/version.c index 4ed39913d..e18045657 100644 --- a/trunk/KProcessHacker/version.c +++ b/trunk/KProcessHacker/version.c @@ -180,10 +180,11 @@ NTSTATUS KvInit() OffEpProtectedProcessBit = 0; OffEpRundownProtect = 0x80; OffOhBody = 0x18; + OffOtName = 0x40; OffOtiGenericMapping = 0x60 + 0x8; OffOtiOpenProcedure = 0x60 + 0x30; - SysCallZwContinue = 0x20; + SsNtContinue = 0x20; /* We are scanning for PspTerminateProcess which has the same signature as PsTerminateProcess because @@ -262,26 +263,33 @@ NTSTATUS KvInit() /* SP0 */ if (servicePack == 0) { + OffOtName = 0x40; OffOtiGenericMapping = 0x60 + 0xc; OffOtiOpenProcedure = 0x60 + 0x30; - SysCallZwContinue = 0x36; + SsNtContinue = 0x36; } /* SP1 */ else if (servicePack == 1) { + OffOtName = 0x8; OffOtiGenericMapping = 0x28 + 0xc; /* They got rid of the Mutex (an ERESOURCE) */ OffOtiOpenProcedure = 0x28 + 0x34; - SysCallZwContinue = 0x37; + SsNtContinue = 0x37; } /* SP2 */ else if (servicePack == 2) { + OffOtName = 0x8; OffOtiGenericMapping = 0x28 + 0xc; OffOtiOpenProcedure = 0x28 + 0x34; - SysCallZwContinue = 0x37; + SsNtAddAtom = 0x8; + SsNtAlertResumeThread = 0xd; + SsNtClose = 0x30; + SsNtContinue = 0x37; + SsNtDelayExecution = 0x76; } else { @@ -311,10 +319,11 @@ NTSTATUS KvInit() OffEpProtectedProcessBit = 0xb; OffEpRundownProtect = 0xb0; OffOhBody = 0x18; + OffOtName = 0x8; OffOtiGenericMapping = 0x28 + 0xc; OffOtiOpenProcedure = 0x28 + 0x34; - SysCallZwContinue = 0x3c; + SsNtContinue = 0x3c; INIT_SCAN( PsTerminateProcessScan, diff --git a/trunk/ProcessHacker.Native/KProcessHacker.cs b/trunk/ProcessHacker.Native/KProcessHacker.cs index e814742fe..5cdc6dc16 100644 --- a/trunk/ProcessHacker.Native/KProcessHacker.cs +++ b/trunk/ProcessHacker.Native/KProcessHacker.cs @@ -96,7 +96,9 @@ namespace ProcessHacker.Native SsRef, SsUnref, SsCreateClientEntry, - SsCreateProcessEntry + SsCreateRuleSetEntry, + SsRemoveRule, + SsAddProcessIdRule } [Flags] @@ -848,6 +850,24 @@ namespace ProcessHacker.Native _fileHandle.IoControl(CtlCode(Control.SetProcessToken), inData, 8, null, 0); } + public IntPtr SsAddProcessIdRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + KphSsFilterType filterType, + IntPtr processId + ) + { + byte* inData = stackalloc byte[0xc]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)filterType; + *(int*)(inData + 0x8) = processId.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.SsAddProcessIdRule), inData, 0xc, outData, 4); + + return (*(int*)outData).ToIntPtr(); + } + public KphSsClientEntryHandle SsCreateClientEntry( ProcessHandle processHandle, SemaphoreHandle readSemaphoreHandle, @@ -870,22 +890,35 @@ namespace ProcessHacker.Native return new KphSsClientEntryHandle((*(int*)outData).ToIntPtr()); } - public KphSsProcessEntryHandle SsCreateProcessEntry( + public KphSsRuleSetEntryHandle SsCreateRuleSetEntry( KphSsClientEntryHandle clientEntryHandle, - ProcessHandle targetProcessHandle, - KphSsLogFlags flags + KphSsFilterType defaultFilterType, + KphSsRuleSetAction action ) { byte* inData = stackalloc byte[0xc]; byte* outData = stackalloc byte[4]; *(int*)inData = clientEntryHandle.Handle.ToInt32(); - *(int*)(inData + 0x4) = targetProcessHandle; - *(int*)(inData + 0x8) = (int)flags; + *(int*)(inData + 0x4) = (int)defaultFilterType; + *(int*)(inData + 0x8) = (int)action; - _fileHandle.IoControl(CtlCode(Control.SsCreateProcessEntry), inData, 0xc, outData, 4); + _fileHandle.IoControl(CtlCode(Control.SsCreateRuleSetEntry), inData, 0xc, outData, 4); - return new KphSsProcessEntryHandle((*(int*)outData).ToIntPtr()); + return new KphSsRuleSetEntryHandle((*(int*)outData).ToIntPtr()); + } + + public void SsRemoveRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + IntPtr ruleEntryHandle + ) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 4) = ruleEntryHandle.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.SsRemoveRule), inData, 8, null, 0); } public void SsRef() @@ -940,10 +973,29 @@ namespace ProcessHacker.Native DriverServiceKeyNameInformation } + public enum KphSsArgumentType : int + { + Normal = 0, + Int8, + Int16, + Int32, + Int64, + Handle, + String, + WString, + AnsiString, + UnicodeString, + ObjectAttributes, + ClientId, + Context, + InitialTeb + } + public enum KphSsBlockType : int { Reset, - Event + Event, + Argument } [Flags] @@ -955,13 +1007,24 @@ namespace ProcessHacker.Native UserMode = 0x8 } + public enum KphSsFilterType : int + { + Include, + Exclude + } + [Flags] - public enum KphSsLogFlags : int + public enum KphSsModeFlags : int { UserMode = 0x1, KernelMode = 0x2 } + public enum KphSsRuleSetAction : int + { + Log + } + public class KphHandle : BaseObject { private IntPtr _handle; @@ -989,9 +1052,9 @@ namespace ProcessHacker.Native { } } - public class KphSsProcessEntryHandle : KphHandle + public class KphSsRuleSetEntryHandle : KphHandle { - internal KphSsProcessEntryHandle(IntPtr handle) + internal KphSsRuleSetEntryHandle(IntPtr handle) : base(handle) { } } @@ -1004,6 +1067,30 @@ namespace ProcessHacker.Native public int DriverSize; } + [StructLayout(LayoutKind.Sequential)] + public struct KphSsArgumentBlock + { + [StructLayout(LayoutKind.Explicit)] + public struct KphSsArgumentUnion + { + [FieldOffset(0)] + public int Normal; + [FieldOffset(0)] + public byte Int8; + [FieldOffset(0)] + public short Int16; + [FieldOffset(0)] + public int Int32; + [FieldOffset(0)] + public long Int64; + } + + public KphSsBlockHeader Header; + public int Index; + public KphSsArgumentType Type; + public KphSsArgumentUnion Data; + } + [StructLayout(LayoutKind.Sequential)] public struct KphSsBlockHeader { @@ -1014,7 +1101,7 @@ namespace ProcessHacker.Native [StructLayout(LayoutKind.Sequential)] public struct KphSsEventBlock { - KphSsBlockHeader Header; + public KphSsBlockHeader Header; public int Flags; public long Time; public ClientId ClientId; @@ -1027,6 +1114,20 @@ namespace ProcessHacker.Native public int TraceOffset; } + [StructLayout(LayoutKind.Sequential)] + public struct KphSsHandle + { + public int TypeNameOffset; + public int NameOffset; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsWString + { + public ushort Length; + public byte Buffer; + } + [StructLayout(LayoutKind.Sequential)] public struct ProcessHandleInformation {