mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
many improvements to KphSs
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1633 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -15,6 +15,7 @@ SOURCES= \
|
||||
protect.c \
|
||||
sync.c \
|
||||
sysservice.c \
|
||||
sysservicedata.c \
|
||||
trace.c \
|
||||
\
|
||||
io.c \
|
||||
|
||||
+544
-134
@@ -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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user