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 b4699c76d..12526a8b3 100644
Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ
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
{