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:
wj32
2009-07-26 06:50:37 +00:00
parent 2c22f0e8a4
commit 9da61ad2c8
15 changed files with 1764 additions and 325 deletions
+4 -1
View File
@@ -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.
+14
View File
@@ -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,
+161 -10
View File
@@ -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
+374 -76
View File
@@ -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
+6 -1
View File
@@ -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
+99 -84
View File
@@ -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;
+111
View File
@@ -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.
+1
View File
@@ -15,6 +15,7 @@ SOURCES= \
protect.c \
sync.c \
sysservice.c \
sysservicedata.c \
trace.c \
\
io.c \
+544 -134
View File
@@ -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
+160
View File
@@ -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
);
}
+14 -5
View File
@@ -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,
+114 -13
View File
@@ -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
{