mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
some formatting. Smiley face
This commit is contained in:
parent
a043150844
commit
84c4f5137f
21 changed files with 5680 additions and 6224 deletions
131
.clang-format
Normal file
131
.clang-format
Normal file
|
@ -0,0 +1,131 @@
|
|||
Language: Cpp
|
||||
BasedOnStyle: webkit
|
||||
AccessModifierOffset: -4
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
|
||||
AlignConsecutiveMacros: true
|
||||
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
|
||||
AlignTrailingComments: true
|
||||
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
|
||||
AlwaysBreakTemplateDeclarations: true #false
|
||||
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakStringLiterals: false
|
||||
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^begin_wpp|^end_wpp|^FUNC |^USESUFFIX |^USESUFFIX '
|
||||
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
|
||||
DerivePointerAlignment: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 8
|
||||
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
|
||||
MacroBlockBegin: '^BEGIN_MODULE$|^BEGIN_TEST_CLASS$|^BEGIN_TEST_METHOD$'
|
||||
MacroBlockEnd: '^END_MODULE$|^END_TEST_CLASS$|^END_TEST_METHOD$'
|
||||
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None #All
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
Standard: Cpp11
|
||||
StatementMacros: [
|
||||
'EXTERN_C',
|
||||
'PAGED',
|
||||
'PAGEDX',
|
||||
'NONPAGED',
|
||||
'PNPCODE',
|
||||
'INITCODE',
|
||||
'_At_',
|
||||
'_When_',
|
||||
'_Success_',
|
||||
'_Check_return_',
|
||||
'_Must_inspect_result_',
|
||||
'_IRQL_requires_same_',
|
||||
'_IRQL_requires_',
|
||||
'_IRQL_requires_max_',
|
||||
'_IRQL_requires_min_',
|
||||
'_IRQL_saves_',
|
||||
'_IRQL_restores_',
|
||||
'_IRQL_saves_global_',
|
||||
'_IRQL_restores_global_',
|
||||
'_IRQL_raises_',
|
||||
'_IRQL_lowers_',
|
||||
'_Acquires_lock_',
|
||||
'_Releases_lock_',
|
||||
'_Acquires_exclusive_lock_',
|
||||
'_Releases_exclusive_lock_',
|
||||
'_Acquires_shared_lock_',
|
||||
'_Releases_shared_lock_',
|
||||
'_Requires_lock_held_',
|
||||
'_Use_decl_annotations_',
|
||||
'_Guarded_by_',
|
||||
'__drv_preferredFunction',
|
||||
'__drv_allocatesMem',
|
||||
'__drv_freesMem',
|
||||
]
|
||||
|
||||
TabWidth: '8'
|
||||
UseTab: Never
|
File diff suppressed because it is too large
Load diff
|
@ -10,97 +10,86 @@
|
|||
|
||||
typedef struct _OPEN_HANDLE_FAILURE_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT is_kernel_handle;
|
||||
LONG process_id;
|
||||
LONG thread_id;
|
||||
LONG access;
|
||||
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
|
||||
INT report_code;
|
||||
INT is_kernel_handle;
|
||||
LONG process_id;
|
||||
LONG thread_id;
|
||||
LONG access;
|
||||
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
|
||||
|
||||
}OPEN_HANDLE_FAILURE_REPORT, * POPEN_HANDLE_FAILURE_REPORT;
|
||||
} OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT;
|
||||
|
||||
//handle access masks
|
||||
//https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
||||
#define PROCESS_CREATE_PROCESS 0x0080
|
||||
#define PROCESS_TERMINATE 0x0001
|
||||
#define PROCESS_CREATE_THREAD 0x0002
|
||||
#define PROCESS_DUP_HANDLE 0x0040
|
||||
#define PROCESS_QUERY_INFORMATION 0x0400
|
||||
// handle access masks
|
||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
||||
#define PROCESS_CREATE_PROCESS 0x0080
|
||||
#define PROCESS_TERMINATE 0x0001
|
||||
#define PROCESS_CREATE_THREAD 0x0002
|
||||
#define PROCESS_DUP_HANDLE 0x0040
|
||||
#define PROCESS_QUERY_INFORMATION 0x0400
|
||||
#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
|
||||
#define PROCESS_SET_INFORMATION 0x0200
|
||||
#define PROCESS_SET_QUOTA 0x0100
|
||||
#define PROCESS_SUSPEND_RESUME 0x0800
|
||||
#define PROCESS_VM_OPERATION 0x0008
|
||||
#define PROCESS_VM_READ 0x0010
|
||||
#define PROCESS_VM_WRITE 0x0020
|
||||
#define PROCESS_SET_INFORMATION 0x0200
|
||||
#define PROCESS_SET_QUOTA 0x0100
|
||||
#define PROCESS_SUSPEND_RESUME 0x0800
|
||||
#define PROCESS_VM_OPERATION 0x0008
|
||||
#define PROCESS_VM_READ 0x0010
|
||||
#define PROCESS_VM_WRITE 0x0020
|
||||
|
||||
//https://www.sysnative.com/forums/threads/object-headers-handles-and-types.34987/
|
||||
// https://www.sysnative.com/forums/threads/object-headers-handles-and-types.34987/
|
||||
#define GET_OBJECT_HEADER_FROM_HANDLE(x) ((x << 4) | 0xffff000000000000)
|
||||
|
||||
static const uintptr_t EPROCESS_IMAGE_FILE_NAME_OFFSET = 0x5a8;
|
||||
static const uintptr_t EPROCESS_HANDLE_TABLE_OFFSET = 0x570;
|
||||
static const uintptr_t EPROCESS_PLIST_ENTRY_OFFSET = 0x448;
|
||||
static const uintptr_t EPROCESS_HANDLE_TABLE_OFFSET = 0x570;
|
||||
static const uintptr_t EPROCESS_PLIST_ENTRY_OFFSET = 0x448;
|
||||
|
||||
static UNICODE_STRING OBJECT_TYPE_PROCESS = RTL_CONSTANT_STRING(L"Process");
|
||||
static UNICODE_STRING OBJECT_TYPE_THREAD = RTL_CONSTANT_STRING(L"Thread");
|
||||
static UNICODE_STRING OBJECT_TYPE_THREAD = RTL_CONSTANT_STRING(L"Thread");
|
||||
|
||||
typedef struct _THREAD_LIST_ENTRY
|
||||
{
|
||||
SINGLE_LIST_ENTRY list;
|
||||
PKTHREAD thread;
|
||||
PKPROCESS owning_process;
|
||||
BOOLEAN apc_queued;
|
||||
PKAPC apc;
|
||||
SINGLE_LIST_ENTRY list;
|
||||
PKTHREAD thread;
|
||||
PKPROCESS owning_process;
|
||||
BOOLEAN apc_queued;
|
||||
PKAPC apc;
|
||||
|
||||
}THREAD_LIST_ENTRY, * PTHREAD_LIST_ENTRY;
|
||||
} THREAD_LIST_ENTRY, *PTHREAD_LIST_ENTRY;
|
||||
|
||||
typedef struct _PROCESS_LIST_ENTRY
|
||||
{
|
||||
SINGLE_LIST_ENTRY list;
|
||||
PKPROCESS process;
|
||||
PKPROCESS parent;
|
||||
SINGLE_LIST_ENTRY list;
|
||||
PKPROCESS process;
|
||||
PKPROCESS parent;
|
||||
|
||||
}PROCESS_LIST_ENTRY, *PPROCESS_LIST_ENTRY;
|
||||
} PROCESS_LIST_ENTRY, *PPROCESS_LIST_ENTRY;
|
||||
|
||||
VOID NTAPI
|
||||
ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
ExUnlockHandleTableEntry(
|
||||
IN PHANDLE_TABLE HandleTable,
|
||||
IN PHANDLE_TABLE_ENTRY HandleTableEntry
|
||||
);
|
||||
|
||||
VOID
|
||||
ObPostOpCallbackRoutine(
|
||||
_In_ PVOID RegistrationContext,
|
||||
_In_ POB_POST_OPERATION_INFORMATION OperationInformation
|
||||
);
|
||||
ObPostOpCallbackRoutine(_In_ PVOID RegistrationContext,
|
||||
_In_ POB_POST_OPERATION_INFORMATION OperationInformation);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
OB_PREOP_CALLBACK_STATUS
|
||||
ObPreOpCallbackRoutine(
|
||||
_In_ PVOID RegistrationContext,
|
||||
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
|
||||
);
|
||||
ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
|
||||
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation);
|
||||
|
||||
//VOID ProcessCreateNotifyRoutine(
|
||||
// VOID ProcessCreateNotifyRoutine(
|
||||
// _In_ HANDLE ParentId,
|
||||
// _In_ HANDLE ProcessId,
|
||||
// _In_ BOOLEAN Create
|
||||
//);
|
||||
|
||||
//VOID
|
||||
//EnumerateProcessListWithCallbackFunction(
|
||||
// VOID
|
||||
// EnumerateProcessListWithCallbackFunction(
|
||||
// _In_ PVOID Function,
|
||||
// _In_opt_ PVOID Context
|
||||
//);
|
||||
|
||||
NTSTATUS
|
||||
EnumerateProcessHandles(
|
||||
_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
|
||||
_In_opt_ PVOID Context
|
||||
);
|
||||
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOID Context);
|
||||
|
||||
NTSTATUS
|
||||
InitialiseThreadList();
|
||||
|
@ -109,18 +98,10 @@ NTSTATUS
|
|||
InitialiseProcessList();
|
||||
|
||||
VOID
|
||||
ThreadCreateNotifyRoutine(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ HANDLE ThreadId,
|
||||
_In_ BOOLEAN Create
|
||||
);
|
||||
ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOLEAN Create);
|
||||
|
||||
VOID
|
||||
ProcessCreateNotifyRoutine(
|
||||
_In_ HANDLE ParentId,
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ BOOLEAN Create
|
||||
);
|
||||
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create);
|
||||
|
||||
VOID
|
||||
CleanupThreadListOnDriverUnload();
|
||||
|
@ -129,37 +110,25 @@ _IRQL_requires_max_(APC_LEVEL)
|
|||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
FindThreadListEntryByThreadAddress(
|
||||
_In_ PKTHREAD Thread,
|
||||
_Inout_ PTHREAD_LIST_ENTRY* Entry
|
||||
);
|
||||
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, _Inout_ PTHREAD_LIST_ENTRY* Entry);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
FindProcessListEntryByProcess(
|
||||
_In_ PKPROCESS Process,
|
||||
_Inout_ PPROCESS_LIST_ENTRY* Entry
|
||||
);
|
||||
FindProcessListEntryByProcess(_In_ PKPROCESS Process, _Inout_ PPROCESS_LIST_ENTRY* Entry);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
EnumerateThreadListWithCallbackRoutine(
|
||||
_In_ PVOID CallbackRoutine,
|
||||
_In_opt_ PVOID Context
|
||||
);
|
||||
EnumerateThreadListWithCallbackRoutine(_In_ PVOID CallbackRoutine, _In_opt_ PVOID Context);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
EnumerateProcessListWithCallbackRoutine(
|
||||
_In_ PVOID CallbackRoutine,
|
||||
_In_opt_ PVOID Context
|
||||
);
|
||||
EnumerateProcessListWithCallbackRoutine(_In_ PVOID CallbackRoutine, _In_opt_ PVOID Context);
|
||||
|
||||
VOID
|
||||
CleanupProcessListOnDriverUnload();
|
||||
|
|
2158
driver/common.h
2158
driver/common.h
File diff suppressed because it is too large
Load diff
1530
driver/driver.c
1530
driver/driver.c
File diff suppressed because it is too large
Load diff
165
driver/driver.h
165
driver/driver.h
|
@ -9,8 +9,8 @@
|
|||
#include "queue.h"
|
||||
#include "modules.h"
|
||||
|
||||
#define DRIVER_PATH_MAX_LENGTH 512
|
||||
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
|
||||
#define DRIVER_PATH_MAX_LENGTH 512
|
||||
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
|
||||
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
|
||||
|
||||
#define MAX_REPORTS_PER_IRP 20
|
||||
|
@ -21,106 +21,83 @@
|
|||
|
||||
typedef struct _SYSTEM_INFORMATION
|
||||
{
|
||||
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
|
||||
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
|
||||
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
|
||||
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
|
||||
|
||||
}SYSTEM_INFORMATION, * PSYSTEM_INFORMATION;
|
||||
} SYSTEM_INFORMATION, *PSYSTEM_INFORMATION;
|
||||
|
||||
typedef struct _OB_CALLBACKS_CONFIG
|
||||
{
|
||||
PVOID registration_handle;
|
||||
KGUARDED_MUTEX lock;
|
||||
PVOID registration_handle;
|
||||
KGUARDED_MUTEX lock;
|
||||
|
||||
}OB_CALLBACKS_CONFIG, * POB_CALLBACKS_CONFIG;
|
||||
} OB_CALLBACKS_CONFIG, *POB_CALLBACKS_CONFIG;
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
NTSTATUS
|
||||
ProcLoadInitialiseProcessConfig(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetProtectedProcessEProcess(
|
||||
_Out_ PEPROCESS* Process
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetProtectedProcessId(
|
||||
_Out_ PLONG ProcessId
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ReadProcessInitialisedConfigFlag(
|
||||
_Out_ PBOOLEAN Flag
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID GetDriverPath(
|
||||
_Out_ PUNICODE_STRING DriverPath
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID GetDriverConfigSystemInformation(
|
||||
_Out_ PSYSTEM_INFORMATION* SystemInformation
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetApcContext(
|
||||
_Inout_ PVOID* Context,
|
||||
_In_ LONG ContextIdentifier
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
NTSTATUS
|
||||
InsertApcContext(
|
||||
_In_ PVOID Context
|
||||
);
|
||||
ProcLoadInitialiseProcessConfig(_In_ PIRP Irp);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetApcContextByIndex(
|
||||
_Inout_ PVOID* Context,
|
||||
_In_ INT Index
|
||||
);
|
||||
GetProtectedProcessEProcess(_Out_ PEPROCESS* Process);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
IncrementApcCount(
|
||||
_In_ LONG ContextId
|
||||
);
|
||||
GetProtectedProcessId(_Out_ PLONG ProcessId);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
FreeApcAndDecrementApcCount(
|
||||
_Inout_ PRKAPC Apc,
|
||||
_In_ LONG ContextId
|
||||
);
|
||||
ReadProcessInitialisedConfigFlag(_Out_ PBOOLEAN Flag);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverPath(_Out_ PUNICODE_STRING DriverPath);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverConfigSystemInformation(_Out_ PSYSTEM_INFORMATION* SystemInformation);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetApcContext(_Inout_ PVOID* Context, _In_ LONG ContextIdentifier);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
NTSTATUS
|
||||
InsertApcContext(_In_ PVOID Context);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetApcContextByIndex(_Inout_ PVOID* Context, _In_ INT Index);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
IncrementApcCount(_In_ LONG ContextId);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
FreeApcAndDecrementApcCount(_Inout_ PRKAPC Apc, _In_ LONG ContextId);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
|
@ -153,48 +130,36 @@ _IRQL_requires_max_(APC_LEVEL)
|
|||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetCallbackConfigStructure(
|
||||
_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration
|
||||
);
|
||||
GetCallbackConfigStructure(_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ImageLoadSetProcessId(
|
||||
_In_ HANDLE ProcessId
|
||||
);
|
||||
ImageLoadSetProcessId(_In_ HANDLE ProcessId);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverDeviceName(
|
||||
_Out_ PUNICODE_STRING DeviceName
|
||||
);
|
||||
GetDriverDeviceName(_Out_ PUNICODE_STRING DeviceName);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverRegistryPath(
|
||||
_Out_ PUNICODE_STRING RegistryPath
|
||||
);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverName(
|
||||
_Out_ LPCSTR* DriverName
|
||||
);
|
||||
GetDriverRegistryPath(_Out_ PUNICODE_STRING RegistryPath);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverSymbolicLink(
|
||||
_Out_ PUNICODE_STRING DeviceSymbolicLink
|
||||
);
|
||||
GetDriverName(_Out_ LPCSTR* DriverName);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
GetDriverSymbolicLink(_Out_ PUNICODE_STRING DeviceSymbolicLink);
|
||||
|
||||
#endif
|
156
driver/hv.c
156
driver/hv.c
|
@ -6,110 +6,102 @@
|
|||
#include "ioctl.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, PerformVirtualizationDetection)
|
||||
# pragma alloc_text(PAGE, PerformVirtualizationDetection)
|
||||
#endif
|
||||
|
||||
#define TOTAL_ITERATION_COUNT 20
|
||||
|
||||
/*
|
||||
* TODO: Perform the test in a loop and average the delta out, then compare it
|
||||
* to an instruction such as FYL2XP1 (source: secret.club) which has an average
|
||||
* execution time slightly higher then the CPUID instruction then compare the two.
|
||||
* If the average time for the CPUID instruction is higher then the average time
|
||||
* for the FYL2XP1 instruction it is a dead giveaway we are running on a
|
||||
* virtualized system.
|
||||
*
|
||||
* reference: https://secret.club/2020/01/12/battleye-hypervisor-detection.html
|
||||
*/
|
||||
* TODO: Perform the test in a loop and average the delta out, then compare it
|
||||
* to an instruction such as FYL2XP1 (source: secret.club) which has an average
|
||||
* execution time slightly higher then the CPUID instruction then compare the two.
|
||||
* If the average time for the CPUID instruction is higher then the average time
|
||||
* for the FYL2XP1 instruction it is a dead giveaway we are running on a
|
||||
* virtualized system.
|
||||
*
|
||||
* reference: https://secret.club/2020/01/12/battleye-hypervisor-detection.html
|
||||
*/
|
||||
|
||||
_IRQL_always_function_max_(HIGH_LEVEL)
|
||||
STATIC
|
||||
INT
|
||||
APERFMsrTimingCheck()
|
||||
_IRQL_always_function_max_(HIGH_LEVEL) STATIC INT APERFMsrTimingCheck()
|
||||
{
|
||||
KAFFINITY new_affinity = { 0 };
|
||||
KAFFINITY old_affinity = { 0 };
|
||||
ULONG64 old_irql;
|
||||
INT cpuid_result[4];
|
||||
KAFFINITY new_affinity = {0};
|
||||
KAFFINITY old_affinity = {0};
|
||||
UINT64 old_irql = 0;
|
||||
INT cpuid_result[4];
|
||||
|
||||
/*
|
||||
* First thing we do is we lock the current thread to the logical processor
|
||||
* its executing on.
|
||||
*/
|
||||
new_affinity = (KAFFINITY)(1ull << KeGetCurrentProcessorNumber());
|
||||
old_affinity = KeSetSystemAffinityThreadEx(new_affinity);
|
||||
/*
|
||||
* First thing we do is we lock the current thread to the logical processor
|
||||
* its executing on.
|
||||
*/
|
||||
new_affinity = (KAFFINITY)(1ull << KeGetCurrentProcessorNumber());
|
||||
old_affinity = KeSetSystemAffinityThreadEx(new_affinity);
|
||||
|
||||
/*
|
||||
* Once we've locked our thread to the current core, we save the old irql
|
||||
* and raise to HIGH_LEVEL to ensure the chance our thread is preempted
|
||||
* by a thread with a higher IRQL is extremely low.
|
||||
*/
|
||||
old_irql = __readcr8();
|
||||
__writecr8(HIGH_LEVEL);
|
||||
/*
|
||||
* Once we've locked our thread to the current core, we save the old irql
|
||||
* and raise to HIGH_LEVEL to ensure the chance our thread is preempted
|
||||
* by a thread with a higher IRQL is extremely low.
|
||||
*/
|
||||
old_irql = __readcr8();
|
||||
__writecr8(HIGH_LEVEL);
|
||||
|
||||
/*
|
||||
* Then we also disable interrupts, once again making sure our thread
|
||||
* is not preempted.
|
||||
*/
|
||||
_disable();
|
||||
/*
|
||||
* Then we also disable interrupts, once again making sure our thread
|
||||
* is not preempted.
|
||||
*/
|
||||
_disable();
|
||||
|
||||
/*
|
||||
* Once our thread is ready for the test, we read the APERF from the
|
||||
* MSR register and store it. We then execute a CPUID instruction
|
||||
* which we don't really care about and immediately after read the APERF
|
||||
* counter once again and store it in a seperate variable.
|
||||
*/
|
||||
UINT64 aperf_before = __readmsr(IA32_APERF_MSR) << 32;
|
||||
__cpuid(cpuid_result, 1);
|
||||
UINT64 aperf_after = __readmsr(IA32_APERF_MSR) << 32;
|
||||
/*
|
||||
* Once our thread is ready for the test, we read the APERF from the
|
||||
* MSR register and store it. We then execute a CPUID instruction
|
||||
* which we don't really care about and immediately after read the APERF
|
||||
* counter once again and store it in a seperate variable.
|
||||
*/
|
||||
UINT64 aperf_before = __readmsr(IA32_APERF_MSR) << 32;
|
||||
__cpuid(cpuid_result, 1);
|
||||
UINT64 aperf_after = __readmsr(IA32_APERF_MSR) << 32;
|
||||
|
||||
/*
|
||||
* Once we have performed our test, we want to make sure we are not
|
||||
* hogging the cpu time from other threads, so we reverse the initial
|
||||
* preparation process. i.e we first enable interrupts, lower our irql
|
||||
* to the threads previous irql before it was raised and then restore the
|
||||
* threads affinity back to its original affinity.
|
||||
*/
|
||||
_enable();
|
||||
__writecr8(old_irql);
|
||||
KeRevertToUserAffinityThreadEx(old_affinity);
|
||||
/*
|
||||
* Once we have performed our test, we want to make sure we are not
|
||||
* hogging the cpu time from other threads, so we reverse the initial
|
||||
* preparation process. i.e we first enable interrupts, lower our irql
|
||||
* to the threads previous irql before it was raised and then restore the
|
||||
* threads affinity back to its original affinity.
|
||||
*/
|
||||
_enable();
|
||||
__writecr8(old_irql);
|
||||
KeRevertToUserAffinityThreadEx(old_affinity);
|
||||
|
||||
/*
|
||||
* Now the only thing left to do is calculate the change. Now, on some VMs
|
||||
* such as VMWARE the aperf value will be 0, meaning the change will be 0.
|
||||
* This is a dead giveaway we are executing in a VM.
|
||||
*/
|
||||
UINT64 aperf_delta = aperf_after - aperf_before;
|
||||
/*
|
||||
* Now the only thing left to do is calculate the change. Now, on some VMs
|
||||
* such as VMWARE the aperf value will be 0, meaning the change will be 0.
|
||||
* This is a dead giveaway we are executing in a VM.
|
||||
*/
|
||||
UINT64 aperf_delta = aperf_after - aperf_before;
|
||||
|
||||
return aperf_delta == 0 ? TRUE : FALSE;
|
||||
return aperf_delta == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
PerformVirtualizationDetection(
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
PerformVirtualizationDetection(_Inout_ PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(HYPERVISOR_DETECTION_REPORT));
|
||||
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(HYPERVISOR_DETECTION_REPORT));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
return status;
|
||||
}
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
return status;
|
||||
}
|
||||
|
||||
HYPERVISOR_DETECTION_REPORT report;
|
||||
report.aperf_msr_timing_check = APERFMsrTimingCheck();
|
||||
report.invd_emulation_check = TestINVDEmulation();
|
||||
HYPERVISOR_DETECTION_REPORT report = {0};
|
||||
report.aperf_msr_timing_check = APERFMsrTimingCheck();
|
||||
report.invd_emulation_check = TestINVDEmulation();
|
||||
|
||||
Irp->IoStatus.Information = sizeof(HYPERVISOR_DETECTION_REPORT);
|
||||
Irp->IoStatus.Information = sizeof(HYPERVISOR_DETECTION_REPORT);
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof(HYPERVISOR_DETECTION_REPORT)
|
||||
);
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer, &report, sizeof(HYPERVISOR_DETECTION_REPORT));
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
13
driver/hv.h
13
driver/hv.h
|
@ -6,18 +6,15 @@
|
|||
|
||||
typedef struct _HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
|
||||
}HYPERVISOR_DETECTION_REPORT, * PHYPERVISOR_DETECTION_REPORT;
|
||||
} HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
|
||||
|
||||
NTSTATUS
|
||||
PerformVirtualizationDetection(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
PerformVirtualizationDetection(_Inout_ PIRP Irp);
|
||||
|
||||
extern
|
||||
INT
|
||||
extern INT
|
||||
TestINVDEmulation();
|
||||
|
||||
#endif
|
1584
driver/integrity.c
1584
driver/integrity.c
File diff suppressed because it is too large
Load diff
|
@ -5,50 +5,37 @@
|
|||
#include "common.h"
|
||||
|
||||
NTSTATUS
|
||||
GetDriverImageSize(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
GetDriverImageSize(_Inout_ PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
VerifyInMemoryImageVsDiskImage(
|
||||
//_In_ PIRP Irp
|
||||
//_In_ PIRP Irp
|
||||
);
|
||||
|
||||
NTSTATUS
|
||||
RetrieveInMemoryModuleExecutableSections(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
RetrieveInMemoryModuleExecutableSections(_Inout_ PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
ValidateProcessLoadedModule(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
ValidateProcessLoadedModule(_Inout_ PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
GetHardDiskDriveSerialNumber(
|
||||
_Inout_ PVOID ConfigDrive0Serial,
|
||||
_In_ SIZE_T ConfigDrive0MaxSize
|
||||
);
|
||||
GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T ConfigDrive0MaxSize);
|
||||
|
||||
NTSTATUS
|
||||
ParseSMBIOSTable(
|
||||
_In_ PVOID ConfigMotherboardSerialNumber,
|
||||
_In_ SIZE_T ConfigMotherboardSerialNumberMaxSize
|
||||
);
|
||||
ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
|
||||
_In_ SIZE_T ConfigMotherboardSerialNumberMaxSize);
|
||||
|
||||
NTSTATUS
|
||||
DetectEptHooksInKeyFunctions();
|
||||
|
||||
PVOID
|
||||
ScanForSignature(
|
||||
_In_ PVOID BaseAddress,
|
||||
_In_ SIZE_T MaxLength,
|
||||
_In_ LPCSTR Signature,
|
||||
_In_ SIZE_T SignatureLength
|
||||
);
|
||||
ScanForSignature(_In_ PVOID BaseAddress,
|
||||
_In_ SIZE_T MaxLength,
|
||||
_In_ LPCSTR Signature,
|
||||
_In_ SIZE_T SignatureLength);
|
||||
|
||||
//NTSTATUS
|
||||
//DetermineIfTestSigningIsEnabled(
|
||||
// NTSTATUS
|
||||
// DetermineIfTestSigningIsEnabled(
|
||||
// _Inout_ PBOOLEAN Result
|
||||
//);
|
||||
|
||||
|
|
666
driver/ioctl.c
666
driver/ioctl.c
|
@ -9,502 +9,468 @@
|
|||
#include "queue.h"
|
||||
#include "hv.h"
|
||||
|
||||
STATIC
|
||||
NTSTATUS
|
||||
DispatchApcOperation(
|
||||
_In_ PAPC_OPERATION_ID Operation);
|
||||
STATIC
|
||||
NTSTATUS
|
||||
DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation);
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, DispatchApcOperation)
|
||||
#pragma alloc_text(PAGE, DeviceControl)
|
||||
#pragma alloc_text(PAGE, DeviceClose)
|
||||
#pragma alloc_text(PAGE, DeviceCreate)
|
||||
# pragma alloc_text(PAGE, DispatchApcOperation)
|
||||
# pragma alloc_text(PAGE, DeviceControl)
|
||||
# pragma alloc_text(PAGE, DeviceClose)
|
||||
# pragma alloc_text(PAGE, DeviceCreate)
|
||||
#endif
|
||||
|
||||
#define IOCCTL_RUN_NMI_CALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_ENUMERATE_HANDLE_TABLES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20012, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_INTEGRITY_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_DETECT_ATTACHED_THREADS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_HARDWARE_INFORMATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_INITIATE_APC_OPERATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_CHECK_FOR_EPT_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_LAUNCH_IPI_INTERRUPT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_SYSTEM_MODULES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCCTL_RUN_NMI_CALLBACKS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_DRIVER_OBJECTS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_ENUMERATE_HANDLE_TABLES \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20012, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_INTEGRITY_CHECK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_DETECT_ATTACHED_THREADS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_HARDWARE_INFORMATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_INITIATE_APC_OPERATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_CHECK_FOR_EPT_HOOK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_LAUNCH_IPI_INTERRUPT \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_SYSTEM_MODULES \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define APC_OPERATION_STACKWALK 0x1
|
||||
|
||||
STATIC
|
||||
NTSTATUS
|
||||
DispatchApcOperation(
|
||||
_In_ PAPC_OPERATION_ID Operation
|
||||
)
|
||||
DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation)
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS status;
|
||||
NTSTATUS status;
|
||||
|
||||
switch (Operation->operation_id)
|
||||
{
|
||||
case APC_OPERATION_STACKWALK:
|
||||
switch (Operation->operation_id)
|
||||
{
|
||||
case APC_OPERATION_STACKWALK:
|
||||
|
||||
DEBUG_LOG("Initiating APC stackwalk operation with operation id %i", Operation->operation_id);
|
||||
DEBUG_LOG("Initiating APC stackwalk operation with operation id %i",
|
||||
Operation->operation_id);
|
||||
|
||||
status = ValidateThreadsViaKernelApc();
|
||||
status = ValidateThreadsViaKernelApc();
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateThreadsViaKernelApc failed with status %x", status);
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateThreadsViaKernelApc failed with status %x", status);
|
||||
|
||||
return status;
|
||||
return status;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Invalid operation ID passed");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
default: DEBUG_ERROR("Invalid operation ID passed"); return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obviously, its important we check that the input and output buffer sizes for each IRP is big
|
||||
* enough to hold the incoming and outgoing information.
|
||||
*
|
||||
* Another important thing to note is that the windows IO manager will only zero out the size
|
||||
* of the input buffer. Given that we use METHOD_BUFFERED for all communication, the input
|
||||
* and output buffer are the same, with the size used being that of the greatest buffer passed
|
||||
* to DeviceIoControl. The IO manager will then zero our the buffer to the size of the input
|
||||
* buffer, so if the output buffer is larger then the input buffer there will be uninitialised
|
||||
* memory in the buffer so we must zero out the buffer to the length of the output buffer.
|
||||
*
|
||||
* We then set the IoStatus.Information field to the size of the buffer we are passing back.
|
||||
* If we don't do this and we allocate an output buffer of size 0x1000, yet only use 0x100 bytes,
|
||||
* the user mode apps output buffer will receive 0x100 bytes + 0x900 bytes of uninitialised memory
|
||||
* which is an information leak.
|
||||
*/
|
||||
* Obviously, its important we check that the input and output buffer sizes for each IRP is big
|
||||
* enough to hold the incoming and outgoing information.
|
||||
*
|
||||
* Another important thing to note is that the windows IO manager will only zero out the size
|
||||
* of the input buffer. Given that we use METHOD_BUFFERED for all communication, the input
|
||||
* and output buffer are the same, with the size used being that of the greatest buffer passed
|
||||
* to DeviceIoControl. The IO manager will then zero our the buffer to the size of the input
|
||||
* buffer, so if the output buffer is larger then the input buffer there will be uninitialised
|
||||
* memory in the buffer so we must zero out the buffer to the length of the output buffer.
|
||||
*
|
||||
* We then set the IoStatus.Information field to the size of the buffer we are passing back.
|
||||
* If we don't do this and we allocate an output buffer of size 0x1000, yet only use 0x100 bytes,
|
||||
* the user mode apps output buffer will receive 0x100 bytes + 0x900 bytes of uninitialised memory
|
||||
* which is an information leak.
|
||||
*/
|
||||
NTSTATUS
|
||||
ValidateIrpOutputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
)
|
||||
ValidateIrpOutputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize)
|
||||
{
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
if (io->Parameters.DeviceIoControl.OutputBufferLength < RequiredSize)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
if (io->Parameters.DeviceIoControl.OutputBufferLength < RequiredSize)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
RtlSecureZeroMemory(Irp->AssociatedIrp.SystemBuffer, RequiredSize);
|
||||
RtlSecureZeroMemory(Irp->AssociatedIrp.SystemBuffer, RequiredSize);
|
||||
|
||||
Irp->IoStatus.Information = RequiredSize;
|
||||
Irp->IoStatus.Information = RequiredSize;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we just check that the input buffers size matches the expected size..
|
||||
* It isnt a very secure check but we can work on that later...
|
||||
*/
|
||||
* Here we just check that the input buffers size matches the expected size..
|
||||
* It isnt a very secure check but we can work on that later...
|
||||
*/
|
||||
NTSTATUS
|
||||
ValidateIrpInputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
)
|
||||
ValidateIrpInputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize)
|
||||
{
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (!Irp || !RequiredSize)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
PIO_STACK_LOCATION io = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
if (!io)
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
if (io->Parameters.DeviceIoControl.InputBufferLength != RequiredSize)
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
if (io->Parameters.DeviceIoControl.InputBufferLength != RequiredSize)
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
||||
NTSTATUS
|
||||
DeviceControl(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(DriverObject);
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
|
||||
HANDLE handle = NULL;
|
||||
PKTHREAD thread = NULL;
|
||||
BOOLEAN security_flag = FALSE;
|
||||
|
||||
/*
|
||||
* LMAO
|
||||
*/
|
||||
ReadProcessInitialisedConfigFlag(&security_flag);
|
||||
|
||||
if (security_flag == FALSE &&
|
||||
stack_location->Parameters.DeviceIoControl.IoControlCode != IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH)
|
||||
{
|
||||
status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
}
|
||||
UNREFERENCED_PARAMETER(DriverObject);
|
||||
PAGED_CODE();
|
||||
|
||||
switch (stack_location->Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case IOCCTL_RUN_NMI_CALLBACKS:
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
|
||||
HANDLE handle = NULL;
|
||||
PKTHREAD thread = NULL;
|
||||
BOOLEAN security_flag = FALSE;
|
||||
|
||||
status = HandleNmiIOCTL(Irp);
|
||||
/*
|
||||
* LMAO
|
||||
*/
|
||||
ReadProcessInitialisedConfigFlag(&security_flag);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("RunNmiCallbacks failed with status %lx", status);
|
||||
if (security_flag == FALSE && stack_location->Parameters.DeviceIoControl.IoControlCode !=
|
||||
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH)
|
||||
{
|
||||
status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
break;
|
||||
switch (stack_location->Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case IOCCTL_RUN_NMI_CALLBACKS:
|
||||
|
||||
case IOCTL_VALIDATE_DRIVER_OBJECTS:
|
||||
status = HandleNmiIOCTL(Irp);
|
||||
|
||||
/*
|
||||
* The reason this function is run in a new thread and not the thread
|
||||
* issuing the IOCTL is because ZwOpenDirectoryObject issues a
|
||||
* user mode handle if called on the user mode thread calling DeviceIoControl.
|
||||
* This is a problem because when we pass said handle to ObReferenceObjectByHandle
|
||||
* it will issue a bug check under windows driver verifier.
|
||||
*/
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("RunNmiCallbacks failed with status %lx", status);
|
||||
|
||||
status = PsCreateSystemThread(
|
||||
&handle,
|
||||
PROCESS_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
HandleValidateDriversIOCTL,
|
||||
Irp
|
||||
);
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to start thread to validate system drivers");
|
||||
goto end;
|
||||
}
|
||||
case IOCTL_VALIDATE_DRIVER_OBJECTS:
|
||||
|
||||
/*
|
||||
* Thread objects are a type of dispatcher object, meaning when they are freed
|
||||
* its set to the signal state and any waiters will be signalled. This allows
|
||||
* us to wait til our threads terminated and the IRP buffer has been either filled
|
||||
* or left empty and then from there we can complete the IRP and return.
|
||||
*/
|
||||
status = ObReferenceObjectByHandle(
|
||||
handle,
|
||||
THREAD_ALL_ACCESS,
|
||||
*PsThreadType,
|
||||
KernelMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
|
||||
ZwClose(handle);
|
||||
goto end;
|
||||
}
|
||||
|
||||
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
|
||||
/*
|
||||
* The reason this function is run in a new thread and not the thread
|
||||
* issuing the IOCTL is because ZwOpenDirectoryObject issues a
|
||||
* user mode handle if called on the user mode thread calling DeviceIoControl.
|
||||
* This is a problem because when we pass said handle to ObReferenceObjectByHandle
|
||||
* it will issue a bug check under windows driver verifier.
|
||||
*/
|
||||
|
||||
ZwClose(handle);
|
||||
ObDereferenceObject(thread);
|
||||
status = PsCreateSystemThread(
|
||||
&handle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, HandleValidateDriversIOCTL, Irp);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to start thread to validate system drivers");
|
||||
goto end;
|
||||
}
|
||||
|
||||
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:;
|
||||
/*
|
||||
* Thread objects are a type of dispatcher object, meaning when they are freed
|
||||
* its set to the signal state and any waiters will be signalled. This allows
|
||||
* us to wait til our threads terminated and the IRP buffer has been either filled
|
||||
* or left empty and then from there we can complete the IRP and return.
|
||||
*/
|
||||
status = ObReferenceObjectByHandle(
|
||||
handle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &thread, NULL);
|
||||
|
||||
status = ProcLoadInitialiseProcessConfig(Irp);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
|
||||
ZwClose(handle);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialise driver config on proc launch with status %x", status);
|
||||
goto end;
|
||||
}
|
||||
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
status = ProcLoadEnableObCallbacks();
|
||||
ZwClose(handle);
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("InitiateDriverCallbacks failed with status %x", status);
|
||||
break;
|
||||
|
||||
break;
|
||||
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:;
|
||||
|
||||
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
|
||||
status = ProcLoadInitialiseProcessConfig(Irp);
|
||||
|
||||
status = QueryActiveApcContextsForCompletion();
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR(
|
||||
"Failed to initialise driver config on proc launch with status %x",
|
||||
status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("QueryActiveApcContextsForCompletion filed with status %x", status);
|
||||
status = ProcLoadEnableObCallbacks();
|
||||
|
||||
status = HandlePeriodicGlobalReportQueueQuery(Irp);
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("InitiateDriverCallbacks failed with status %x", status);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to handle period callback report queue");
|
||||
break;
|
||||
|
||||
break;
|
||||
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
|
||||
|
||||
case IOCTL_PERFORM_VIRTUALIZATION_CHECK:
|
||||
status = QueryActiveApcContextsForCompletion();
|
||||
|
||||
status = PerformVirtualizationDetection(Irp);
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("QueryActiveApcContextsForCompletion filed with status %x",
|
||||
status);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("PerformVirtualizationDetection failed with status %x", status);
|
||||
status = HandlePeriodicGlobalReportQueueQuery(Irp);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to handle period callback report queue");
|
||||
|
||||
case IOCTL_ENUMERATE_HANDLE_TABLES:
|
||||
break;
|
||||
|
||||
/* can maybe implement this better so we can extract a status value */
|
||||
EnumerateProcessListWithCallbackRoutine(
|
||||
EnumerateProcessHandles,
|
||||
NULL
|
||||
);
|
||||
case IOCTL_PERFORM_VIRTUALIZATION_CHECK:
|
||||
|
||||
break;
|
||||
status = PerformVirtualizationDetection(Irp);
|
||||
|
||||
case IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS:
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("PerformVirtualizationDetection failed with status %x", status);
|
||||
|
||||
status = PsCreateSystemThread(
|
||||
&handle,
|
||||
PROCESS_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
RetrieveInMemoryModuleExecutableSections,
|
||||
Irp
|
||||
);
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to start system thread to get executable regions");
|
||||
goto end;
|
||||
}
|
||||
case IOCTL_ENUMERATE_HANDLE_TABLES:
|
||||
|
||||
status = ObReferenceObjectByHandle(
|
||||
handle,
|
||||
THREAD_ALL_ACCESS,
|
||||
*PsThreadType,
|
||||
KernelMode,
|
||||
&thread,
|
||||
NULL
|
||||
);
|
||||
/* can maybe implement this better so we can extract a status value */
|
||||
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
|
||||
ZwClose(handle);
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
|
||||
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);;
|
||||
case IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS:
|
||||
|
||||
ZwClose(handle);
|
||||
ObDereferenceObject(thread);
|
||||
status = PsCreateSystemThread(&handle,
|
||||
PROCESS_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
RetrieveInMemoryModuleExecutableSections,
|
||||
Irp);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to retrieve executable regions");
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to start system thread to get executable regions");
|
||||
goto end;
|
||||
}
|
||||
|
||||
break;
|
||||
status = ObReferenceObjectByHandle(
|
||||
handle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &thread, NULL);
|
||||
|
||||
case IOCTL_REQUEST_TOTAL_MODULE_SIZE:
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
|
||||
ZwClose(handle);
|
||||
goto end;
|
||||
}
|
||||
|
||||
status = GetDriverImageSize(Irp);
|
||||
KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
|
||||
;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to retrieve driver image size");
|
||||
ZwClose(handle);
|
||||
ObDereferenceObject(thread);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to retrieve executable regions");
|
||||
|
||||
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION:
|
||||
break;
|
||||
|
||||
ProcCloseClearProcessConfiguration();
|
||||
ProcCloseDisableObCallbacks();
|
||||
case IOCTL_REQUEST_TOTAL_MODULE_SIZE:
|
||||
|
||||
break;
|
||||
status = GetDriverImageSize(Irp);
|
||||
|
||||
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("Failed to retrieve driver image size");
|
||||
|
||||
status = FindUnlinkedProcesses();
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("FindUNlinekdProcesses failed with status %x", status);
|
||||
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION:
|
||||
|
||||
break;
|
||||
ProcCloseClearProcessConfiguration();
|
||||
ProcCloseDisableObCallbacks();
|
||||
|
||||
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD:
|
||||
break;
|
||||
|
||||
ValidateKPCRBThreads();
|
||||
case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
|
||||
|
||||
break;
|
||||
status = FindUnlinkedProcesses();
|
||||
|
||||
case IOCTL_PERFORM_INTEGRITY_CHECK:
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("FindUNlinekdProcesses failed with status %x", status);
|
||||
|
||||
status = VerifyInMemoryImageVsDiskImage();
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("VerifyInMemoryImageVsDisk failed with status %x", status);
|
||||
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD: ValidateKPCRBThreads(); break;
|
||||
|
||||
break;
|
||||
case IOCTL_PERFORM_INTEGRITY_CHECK:
|
||||
|
||||
case IOCTL_DETECT_ATTACHED_THREADS:
|
||||
status = VerifyInMemoryImageVsDiskImage();
|
||||
|
||||
DetectThreadsAttachedToProtectedProcess();
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("VerifyInMemoryImageVsDisk failed with status %x", status);
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case IOCTL_VALIDATE_PROCESS_LOADED_MODULE:
|
||||
case IOCTL_DETECT_ATTACHED_THREADS: DetectThreadsAttachedToProtectedProcess(); break;
|
||||
|
||||
status = ValidateProcessLoadedModule(Irp);
|
||||
case IOCTL_VALIDATE_PROCESS_LOADED_MODULE:
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateProcessLoadedModule failed with status %x", status);
|
||||
status = ValidateProcessLoadedModule(Irp);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateProcessLoadedModule failed with status %x", status);
|
||||
|
||||
case IOCTL_REQUEST_HARDWARE_INFORMATION:;
|
||||
break;
|
||||
|
||||
PSYSTEM_INFORMATION system_information = NULL;
|
||||
GetDriverConfigSystemInformation(&system_information);
|
||||
case IOCTL_REQUEST_HARDWARE_INFORMATION:;
|
||||
|
||||
if (system_information == NULL)
|
||||
{
|
||||
DEBUG_ERROR("GetDriverConfigSystemInformation failed");
|
||||
goto end;
|
||||
}
|
||||
PSYSTEM_INFORMATION system_information = NULL;
|
||||
GetDriverConfigSystemInformation(&system_information);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(SYSTEM_INFORMATION));
|
||||
if (system_information == NULL)
|
||||
{
|
||||
DEBUG_ERROR("GetDriverConfigSystemInformation failed");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(SYSTEM_INFORMATION));
|
||||
|
||||
Irp->IoStatus.Information = sizeof(SYSTEM_INFORMATION);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
system_information,
|
||||
sizeof(SYSTEM_INFORMATION)
|
||||
);
|
||||
Irp->IoStatus.Information = sizeof(SYSTEM_INFORMATION);
|
||||
|
||||
break;
|
||||
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
||||
system_information,
|
||||
sizeof(SYSTEM_INFORMATION));
|
||||
|
||||
case IOCTL_INITIATE_APC_OPERATION:;
|
||||
break;
|
||||
|
||||
PAPC_OPERATION_ID operation = (PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
|
||||
case IOCTL_INITIATE_APC_OPERATION:;
|
||||
|
||||
status = DispatchApcOperation(operation);
|
||||
PAPC_OPERATION_ID operation = (PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("DispatchApcOperation failed with status %x", status);
|
||||
status = DispatchApcOperation(operation);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("DispatchApcOperation failed with status %x", status);
|
||||
|
||||
case IOCTL_CHECK_FOR_EPT_HOOK:
|
||||
break;
|
||||
|
||||
status = DetectEptHooksInKeyFunctions();
|
||||
case IOCTL_CHECK_FOR_EPT_HOOK:
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("DetectEpthooksInKeyFunctions failed with status %x", status);
|
||||
status = DetectEptHooksInKeyFunctions();
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("DetectEpthooksInKeyFunctions failed with status %x", status);
|
||||
|
||||
case IOCTL_LAUNCH_IPI_INTERRUPT:
|
||||
break;
|
||||
|
||||
status = LaunchInterProcessInterrupt(Irp);
|
||||
case IOCTL_LAUNCH_IPI_INTERRUPT:
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("LaunchInterProcessInterrupt failed with status %x", status);
|
||||
status = LaunchInterProcessInterrupt(Irp);
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("LaunchInterProcessInterrupt failed with status %x", status);
|
||||
|
||||
case IOCTL_VALIDATE_SYSTEM_MODULES:
|
||||
break;
|
||||
|
||||
/*
|
||||
* Currently the validation is buggy, once the validation is better will
|
||||
* probably bugcheck the system.
|
||||
*/
|
||||
status = ValidateSystemModules();
|
||||
case IOCTL_VALIDATE_SYSTEM_MODULES:
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateSystemModules failed with status %x", status);
|
||||
/*
|
||||
* Currently the validation is buggy, once the validation is better will
|
||||
* probably bugcheck the system.
|
||||
*/
|
||||
status = ValidateSystemModules();
|
||||
|
||||
break;
|
||||
if (!NT_SUCCESS(status))
|
||||
DEBUG_ERROR("ValidateSystemModules failed with status %x", status);
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Invalid IOCTL passed to driver: %lx", stack_location->Parameters.DeviceIoControl.IoControlCode);
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Invalid IOCTL passed to driver: %lx",
|
||||
stack_location->Parameters.DeviceIoControl.IoControlCode);
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
Irp->IoStatus.Status = status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return status;
|
||||
Irp->IoStatus.Status = status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return status;
|
||||
}
|
||||
|
||||
_Dispatch_type_(IRP_MJ_CLOSE)
|
||||
NTSTATUS
|
||||
DeviceClose(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
_Dispatch_type_(IRP_MJ_CLOSE) NTSTATUS
|
||||
DeviceClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
UNREFERENCED_PARAMETER(DeviceObject);
|
||||
|
||||
DEBUG_LOG("Handle closed to DonnaAC");
|
||||
DEBUG_LOG("Handle closed to DonnaAC");
|
||||
|
||||
/*
|
||||
* For now its fine, but this will need to be moved to our process load callbacks
|
||||
* since right now anyone can open a handle to our driver and then close it lol
|
||||
*/
|
||||
/*
|
||||
* For now its fine, but this will need to be moved to our process load callbacks
|
||||
* since right now anyone can open a handle to our driver and then close it lol
|
||||
*/
|
||||
|
||||
/* we also lose reports here, so sohuld pass em into the irp before freeing */
|
||||
FreeGlobalReportQueueObjects();
|
||||
ProcCloseClearProcessConfiguration();
|
||||
ProcCloseDisableObCallbacks();
|
||||
/* we also lose reports here, so sohuld pass em into the irp before freeing */
|
||||
FreeGlobalReportQueueObjects();
|
||||
ProcCloseClearProcessConfiguration();
|
||||
ProcCloseDisableObCallbacks();
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Irp->IoStatus.Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
_Dispatch_type_(IRP_MJ_CREATE)
|
||||
NTSTATUS
|
||||
DeviceCreate(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
_Dispatch_type_(IRP_MJ_CREATE) NTSTATUS
|
||||
DeviceCreate(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
DEBUG_LOG("Handle opened to DonnaAC");
|
||||
DEBUG_LOG("Handle opened to DonnaAC");
|
||||
|
||||
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Irp->IoStatus.Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Irp->IoStatus.Status;
|
||||
}
|
|
@ -8,41 +8,24 @@
|
|||
|
||||
typedef struct _DRIVER_INITIATION_INFORMATION
|
||||
{
|
||||
ULONG protected_process_id;
|
||||
ULONG protected_process_id;
|
||||
|
||||
} DRIVER_INITIATION_INFORMATION, * PDRIVER_INITIATION_INFORMATION;
|
||||
} DRIVER_INITIATION_INFORMATION, *PDRIVER_INITIATION_INFORMATION;
|
||||
|
||||
//_Dispatch_type_(IRP_MJ_SYSTEM_CONTROL)
|
||||
NTSTATUS
|
||||
DeviceControl(
|
||||
_In_ PDRIVER_OBJECT DriverObject,
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
DeviceControl(_In_ PDRIVER_OBJECT DriverObject, _Inout_ PIRP Irp);
|
||||
|
||||
_Dispatch_type_(IRP_MJ_CLOSE)
|
||||
NTSTATUS
|
||||
DeviceClose(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
_Dispatch_type_(IRP_MJ_CLOSE) NTSTATUS
|
||||
DeviceClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp);
|
||||
|
||||
_Dispatch_type_(IRP_MJ_CREATE)
|
||||
NTSTATUS
|
||||
DeviceCreate(
|
||||
_In_ PDEVICE_OBJECT DeviceObject,
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
_Dispatch_type_(IRP_MJ_CREATE) NTSTATUS
|
||||
DeviceCreate(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp);
|
||||
|
||||
NTSTATUS
|
||||
ValidateIrpOutputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
);
|
||||
ValidateIrpOutputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
|
||||
|
||||
NTSTATUS
|
||||
ValidateIrpInputBuffer(
|
||||
_In_ PIRP Irp,
|
||||
_In_ ULONG RequiredSize
|
||||
);
|
||||
ValidateIrpInputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
|
||||
|
||||
#endif
|
2236
driver/modules.c
2236
driver/modules.c
File diff suppressed because it is too large
Load diff
|
@ -9,117 +9,96 @@
|
|||
|
||||
typedef struct NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
|
||||
}NMI_CALLBACK_FAILURE, * PNMI_CALLBACK_FAILURE;
|
||||
} NMI_CALLBACK_FAILURE, *PNMI_CALLBACK_FAILURE;
|
||||
|
||||
typedef struct _MODULE_VALIDATION_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT report_type;
|
||||
UINT64 driver_base_address;
|
||||
UINT64 driver_size;
|
||||
CHAR driver_name[128];
|
||||
INT report_code;
|
||||
INT report_type;
|
||||
UINT64 driver_base_address;
|
||||
UINT64 driver_size;
|
||||
CHAR driver_name[128];
|
||||
|
||||
}MODULE_VALIDATION_FAILURE, * PMODULE_VALIDATION_FAILURE;
|
||||
} MODULE_VALIDATION_FAILURE, *PMODULE_VALIDATION_FAILURE;
|
||||
|
||||
#define APC_STACKWALK_BUFFER_SIZE 4096
|
||||
|
||||
typedef struct _APC_STACKWALK_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
INT report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
|
||||
}APC_STACKWALK_REPORT, * PAPC_STACKWALK_REPORT;
|
||||
} APC_STACKWALK_REPORT, *PAPC_STACKWALK_REPORT;
|
||||
|
||||
typedef struct _APC_OPERATION_ID
|
||||
{
|
||||
int operation_id;
|
||||
int operation_id;
|
||||
|
||||
}APC_OPERATION_ID, * PAPC_OPERATION_ID;
|
||||
} APC_OPERATION_ID, *PAPC_OPERATION_ID;
|
||||
|
||||
/* system modules information */
|
||||
|
||||
typedef struct _SYSTEM_MODULES
|
||||
{
|
||||
PVOID address;
|
||||
INT module_count;
|
||||
PVOID address;
|
||||
INT module_count;
|
||||
|
||||
}SYSTEM_MODULES, * PSYSTEM_MODULES;
|
||||
} SYSTEM_MODULES, *PSYSTEM_MODULES;
|
||||
|
||||
#define APC_CONTEXT_ID_STACKWALK 0x1
|
||||
|
||||
typedef struct _APC_CONTEXT_HEADER
|
||||
{
|
||||
LONG context_id;
|
||||
volatile INT count;
|
||||
volatile INT allocation_in_progress;
|
||||
LONG context_id;
|
||||
volatile INT count;
|
||||
volatile INT allocation_in_progress;
|
||||
|
||||
}APC_CONTEXT_HEADER, * PAPC_CONTEXT_HEADER;
|
||||
} APC_CONTEXT_HEADER, *PAPC_CONTEXT_HEADER;
|
||||
|
||||
typedef struct _APC_STACKWALK_CONTEXT
|
||||
{
|
||||
APC_CONTEXT_HEADER header;
|
||||
PSYSTEM_MODULES modules;
|
||||
APC_CONTEXT_HEADER header;
|
||||
PSYSTEM_MODULES modules;
|
||||
|
||||
}APC_STACKWALK_CONTEXT, * PAPC_STACKWALK_CONTEXT;
|
||||
} APC_STACKWALK_CONTEXT, *PAPC_STACKWALK_CONTEXT;
|
||||
|
||||
NTSTATUS
|
||||
GetSystemModuleInformation(
|
||||
_Out_ PSYSTEM_MODULES ModuleInformation
|
||||
);
|
||||
GetSystemModuleInformation(_Out_ PSYSTEM_MODULES ModuleInformation);
|
||||
|
||||
NTSTATUS
|
||||
HandleValidateDriversIOCTL(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
HandleValidateDriversIOCTL(_Inout_ PIRP Irp);
|
||||
|
||||
PRTL_MODULE_EXTENDED_INFO
|
||||
FindSystemModuleByName(
|
||||
_In_ LPCSTR ModuleName,
|
||||
_In_ PSYSTEM_MODULES SystemModules
|
||||
);
|
||||
FindSystemModuleByName(_In_ LPCSTR ModuleName, _In_ PSYSTEM_MODULES SystemModules);
|
||||
|
||||
NTSTATUS
|
||||
HandleNmiIOCTL(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
HandleNmiIOCTL(_Inout_ PIRP Irp);
|
||||
|
||||
BOOLEAN
|
||||
FreeApcContextStructure(
|
||||
_Inout_ PAPC_CONTEXT_HEADER Context
|
||||
);
|
||||
FreeApcContextStructure(_Inout_ PAPC_CONTEXT_HEADER Context);
|
||||
|
||||
NTSTATUS
|
||||
ValidateThreadsViaKernelApc();
|
||||
|
||||
VOID
|
||||
FreeApcStackwalkApcContextInformation(
|
||||
_Inout_ PAPC_STACKWALK_CONTEXT Context
|
||||
);
|
||||
FreeApcStackwalkApcContextInformation(_Inout_ PAPC_STACKWALK_CONTEXT Context);
|
||||
|
||||
NTSTATUS
|
||||
IsInstructionPointerInInvalidRegion(
|
||||
_In_ UINT64 RIP,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_Out_ PBOOLEAN Result
|
||||
);
|
||||
IsInstructionPointerInInvalidRegion(_In_ UINT64 RIP,
|
||||
_In_ PSYSTEM_MODULES SystemModules,
|
||||
_Out_ PBOOLEAN Result);
|
||||
|
||||
BOOLEAN
|
||||
FlipKThreadMiscFlagsFlag(
|
||||
_In_ PKTHREAD Thread,
|
||||
_In_ ULONG FlagIndex,
|
||||
_In_ BOOLEAN NewValue
|
||||
);
|
||||
FlipKThreadMiscFlagsFlag(_In_ PKTHREAD Thread, _In_ ULONG FlagIndex, _In_ BOOLEAN NewValue);
|
||||
|
||||
NTSTATUS
|
||||
LaunchInterProcessInterrupt(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
LaunchInterProcessInterrupt(_In_ PIRP Irp);
|
||||
|
||||
#endif
|
||||
|
|
1118
driver/pool.c
1118
driver/pool.c
File diff suppressed because it is too large
Load diff
|
@ -8,18 +8,16 @@
|
|||
|
||||
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
|
||||
INT report_code;
|
||||
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
|
||||
|
||||
}INVALID_PROCESS_ALLOCATION_REPORT, * PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
} INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
|
||||
NTSTATUS
|
||||
FindUnlinkedProcesses();
|
||||
|
||||
VOID
|
||||
GetPsActiveProcessHead(
|
||||
_Out_ PUINT64 Address
|
||||
);
|
||||
GetPsActiveProcessHead(_Out_ PUINT64 Address);
|
||||
|
||||
PKDDEBUGGER_DATA64
|
||||
GetGlobalDebuggerData();
|
||||
|
|
515
driver/queue.c
515
driver/queue.c
|
@ -11,42 +11,41 @@
|
|||
#include "common.h"
|
||||
|
||||
/*
|
||||
* This mutex is to prevent a new item being pushed to the queue
|
||||
* while the HandlePeriodicCallbackReportQueue is iterating through
|
||||
* the objects. This can be an issue because the spinlock is released
|
||||
* after each report is placed in the IRP buffer which means a new report
|
||||
* can be pushed into the queue before the next iteration can take ownership
|
||||
* of the spinlock.
|
||||
*/
|
||||
* This mutex is to prevent a new item being pushed to the queue
|
||||
* while the HandlePeriodicCallbackReportQueue is iterating through
|
||||
* the objects. This can be an issue because the spinlock is released
|
||||
* after each report is placed in the IRP buffer which means a new report
|
||||
* can be pushed into the queue before the next iteration can take ownership
|
||||
* of the spinlock.
|
||||
*/
|
||||
typedef struct _REPORT_QUEUE_CONFIGURATION
|
||||
{
|
||||
QUEUE_HEAD head;
|
||||
volatile BOOLEAN is_driver_unloading;
|
||||
KGUARDED_MUTEX lock;
|
||||
QUEUE_HEAD head;
|
||||
volatile BOOLEAN is_driver_unloading;
|
||||
KGUARDED_MUTEX lock;
|
||||
|
||||
}REPORT_QUEUE_CONFIGURATION, * PREPORT_QUEUE_CONFIGURATION;
|
||||
} REPORT_QUEUE_CONFIGURATION, *PREPORT_QUEUE_CONFIGURATION;
|
||||
|
||||
REPORT_QUEUE_CONFIGURATION report_queue_config = { 0 };
|
||||
REPORT_QUEUE_CONFIGURATION report_queue_config = {0};
|
||||
|
||||
VOID
|
||||
InitialiseGlobalReportQueue(
|
||||
_Out_ PBOOLEAN Status
|
||||
)
|
||||
InitialiseGlobalReportQueue(_Out_ PBOOLEAN Status)
|
||||
{
|
||||
report_queue_config.head.start = NULL;
|
||||
report_queue_config.head.end = NULL;
|
||||
report_queue_config.head.entries = 0;
|
||||
report_queue_config.is_driver_unloading = FALSE;
|
||||
report_queue_config.head.start = NULL;
|
||||
report_queue_config.head.end = NULL;
|
||||
report_queue_config.head.entries = 0;
|
||||
report_queue_config.is_driver_unloading = FALSE;
|
||||
|
||||
KeInitializeGuardedMutex(&report_queue_config.head.lock);
|
||||
KeInitializeGuardedMutex(&report_queue_config.lock);
|
||||
KeInitializeGuardedMutex(&report_queue_config.head.lock);
|
||||
KeInitializeGuardedMutex(&report_queue_config.lock);
|
||||
|
||||
*Status = TRUE;
|
||||
*Status = TRUE;
|
||||
}
|
||||
|
||||
//PQUEUE_HEAD QueueCreate()
|
||||
// PQUEUE_HEAD QueueCreate()
|
||||
//{
|
||||
// PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_HEAD ), QUEUE_POOL_TAG );
|
||||
// PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_HEAD ),
|
||||
//QUEUE_POOL_TAG );
|
||||
//
|
||||
// if ( !head )
|
||||
// return NULL;
|
||||
|
@ -58,85 +57,79 @@ InitialiseGlobalReportQueue(
|
|||
// KeInitializeSpinLock( &head->lock );
|
||||
//
|
||||
// return head;
|
||||
//}
|
||||
// }
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
QueuePush(
|
||||
_Inout_ PQUEUE_HEAD Head,
|
||||
_In_ PVOID Data
|
||||
)
|
||||
QueuePush(_Inout_ PQUEUE_HEAD Head, _In_ PVOID Data)
|
||||
{
|
||||
KeAcquireGuardedMutex(&Head->lock);
|
||||
KeAcquireGuardedMutex(&Head->lock);
|
||||
|
||||
PQUEUE_NODE temp = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(QUEUE_NODE), QUEUE_POOL_TAG);
|
||||
PQUEUE_NODE temp = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(QUEUE_NODE), QUEUE_POOL_TAG);
|
||||
|
||||
if (!temp)
|
||||
goto end;
|
||||
if (!temp)
|
||||
goto end;
|
||||
|
||||
Head->entries += 1;
|
||||
Head->entries += 1;
|
||||
|
||||
temp->data = Data;
|
||||
temp->data = Data;
|
||||
|
||||
if (Head->end != NULL)
|
||||
Head->end->next = temp;
|
||||
if (Head->end != NULL)
|
||||
Head->end->next = temp;
|
||||
|
||||
Head->end = temp;
|
||||
Head->end = temp;
|
||||
|
||||
if (Head->start == NULL)
|
||||
Head->start = temp;
|
||||
if (Head->start == NULL)
|
||||
Head->start = temp;
|
||||
|
||||
end:
|
||||
KeReleaseGuardedMutex(&Head->lock);
|
||||
KeReleaseGuardedMutex(&Head->lock);
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
PVOID
|
||||
QueuePop(
|
||||
_Inout_ PQUEUE_HEAD Head
|
||||
)
|
||||
QueuePop(_Inout_ PQUEUE_HEAD Head)
|
||||
{
|
||||
KeAcquireGuardedMutex(&Head->lock);
|
||||
KeAcquireGuardedMutex(&Head->lock);
|
||||
|
||||
PVOID data = NULL;
|
||||
PQUEUE_NODE temp = Head->start;
|
||||
PVOID data = NULL;
|
||||
PQUEUE_NODE temp = Head->start;
|
||||
|
||||
if (temp == NULL)
|
||||
goto end;
|
||||
if (temp == NULL)
|
||||
goto end;
|
||||
|
||||
Head->entries = Head->entries - 1;
|
||||
Head->entries = Head->entries - 1;
|
||||
|
||||
data = temp->data;
|
||||
Head->start = temp->next;
|
||||
data = temp->data;
|
||||
Head->start = temp->next;
|
||||
|
||||
if (Head->end == temp)
|
||||
Head->end = NULL;
|
||||
if (Head->end == temp)
|
||||
Head->end = NULL;
|
||||
|
||||
ExFreePoolWithTag(temp, QUEUE_POOL_TAG);
|
||||
ExFreePoolWithTag(temp, QUEUE_POOL_TAG);
|
||||
|
||||
end:
|
||||
KeReleaseGuardedMutex(&Head->lock);
|
||||
return data;
|
||||
KeReleaseGuardedMutex(&Head->lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
InsertReportToQueue(
|
||||
_In_ PVOID Report
|
||||
)
|
||||
InsertReportToQueue(_In_ PVOID Report)
|
||||
{
|
||||
if (InterlockedExchange(&report_queue_config.is_driver_unloading, report_queue_config.is_driver_unloading))
|
||||
return;
|
||||
if (InterlockedExchange(&report_queue_config.is_driver_unloading,
|
||||
report_queue_config.is_driver_unloading))
|
||||
return;
|
||||
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
QueuePush(&report_queue_config.head, Report);
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
QueuePush(&report_queue_config.head, Report);
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
|
@ -145,297 +138,277 @@ _Releases_lock_(_Lock_kind_mutex_)
|
|||
VOID
|
||||
FreeGlobalReportQueueObjects()
|
||||
{
|
||||
InterlockedExchange(&report_queue_config.is_driver_unloading, TRUE);
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
InterlockedExchange(&report_queue_config.is_driver_unloading, TRUE);
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
|
||||
PVOID report = QueuePop(&report_queue_config.head);
|
||||
PVOID report = QueuePop(&report_queue_config.head);
|
||||
|
||||
while (report != NULL)
|
||||
{
|
||||
ExFreePoolWithTag(report, REPORT_POOL_TAG);
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
DEBUG_LOG("Queu Unload Remaining Entries: %i", report_queue_config.head.entries);
|
||||
}
|
||||
while (report != NULL)
|
||||
{
|
||||
ExFreePoolWithTag(report, REPORT_POOL_TAG);
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
DEBUG_LOG("Queu Unload Remaining Entries: %i", report_queue_config.head.entries);
|
||||
}
|
||||
|
||||
end:
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles sending all the pending reports in the global report
|
||||
* queue to the usermode application. This function is called periodically by the
|
||||
* usermode application. The reason I have implemented this is because as this application
|
||||
* expanded, it became apparent that some of the driver functions will generate multiple
|
||||
* reports as a result of a single usermode request and hence it makes dealing with
|
||||
* reports generated from ObRegisterCallbacks for example much easier.
|
||||
*/
|
||||
* This function handles sending all the pending reports in the global report
|
||||
* queue to the usermode application. This function is called periodically by the
|
||||
* usermode application. The reason I have implemented this is because as this application
|
||||
* expanded, it became apparent that some of the driver functions will generate multiple
|
||||
* reports as a result of a single usermode request and hence it makes dealing with
|
||||
* reports generated from ObRegisterCallbacks for example much easier.
|
||||
*/
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
NTSTATUS
|
||||
HandlePeriodicGlobalReportQueueQuery(
|
||||
_Inout_ PIRP Irp
|
||||
)
|
||||
HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp)
|
||||
{
|
||||
INT count = 0;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PVOID report = NULL;
|
||||
SIZE_T total_size = 0;
|
||||
PVOID report_buffer = NULL;
|
||||
ULONG report_buffer_size = 0;
|
||||
PREPORT_HEADER report_header = NULL;
|
||||
GLOBAL_REPORT_QUEUE_HEADER header = { 0 };
|
||||
INT count = 0;
|
||||
NTSTATUS status = STATUS_ABANDONED;
|
||||
PVOID report = NULL;
|
||||
SIZE_T total_size = 0;
|
||||
PVOID report_buffer = NULL;
|
||||
ULONG report_buffer_size = 0;
|
||||
PREPORT_HEADER report_header = NULL;
|
||||
GLOBAL_REPORT_QUEUE_HEADER header = {0};
|
||||
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
KeAcquireGuardedMutex(&report_queue_config.lock);
|
||||
|
||||
report_buffer_size = sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP + sizeof(GLOBAL_REPORT_QUEUE_HEADER);
|
||||
report_buffer_size = sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP +
|
||||
sizeof(GLOBAL_REPORT_QUEUE_HEADER);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, report_buffer_size);
|
||||
status = ValidateIrpOutputBuffer(Irp, report_buffer_size);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate Irp output buffer");
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
return status;
|
||||
}
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate Irp output buffer");
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
report_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, report_buffer_size, REPORT_QUEUE_TEMP_BUFFER_TAG);
|
||||
report_buffer =
|
||||
ExAllocatePool2(POOL_FLAG_NON_PAGED, report_buffer_size, REPORT_QUEUE_TEMP_BUFFER_TAG);
|
||||
|
||||
if (!report_buffer)
|
||||
{
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
return STATUS_MEMORY_NOT_ALLOCATED;
|
||||
}
|
||||
if (!report_buffer)
|
||||
{
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
return STATUS_MEMORY_NOT_ALLOCATED;
|
||||
}
|
||||
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
|
||||
if (report == NULL)
|
||||
{
|
||||
DEBUG_LOG("callback report queue is empty, returning");
|
||||
goto end;
|
||||
}
|
||||
if (report == NULL)
|
||||
{
|
||||
DEBUG_LOG("callback report queue is empty, returning");
|
||||
goto end;
|
||||
}
|
||||
|
||||
while (report != NULL)
|
||||
{
|
||||
if (count >= MAX_REPORTS_PER_IRP)
|
||||
goto end;
|
||||
while (report != NULL)
|
||||
{
|
||||
if (count >= MAX_REPORTS_PER_IRP)
|
||||
goto end;
|
||||
|
||||
report_header = (PREPORT_HEADER)report;
|
||||
report_header = (PREPORT_HEADER)report;
|
||||
|
||||
switch (report_header->report_id)
|
||||
{
|
||||
case REPORT_ILLEGAL_HANDLE_OPERATION:
|
||||
switch (report_header->report_id)
|
||||
{
|
||||
case REPORT_ILLEGAL_HANDLE_OPERATION:
|
||||
|
||||
RtlCopyMemory(
|
||||
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
|
||||
report,
|
||||
sizeof(OPEN_HANDLE_FAILURE_REPORT)
|
||||
);
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(OPEN_HANDLE_FAILURE_REPORT));
|
||||
|
||||
total_size += sizeof(OPEN_HANDLE_FAILURE_REPORT);
|
||||
break;
|
||||
total_size += sizeof(OPEN_HANDLE_FAILURE_REPORT);
|
||||
break;
|
||||
|
||||
case REPORT_ILLEGAL_ATTACH_PROCESS:
|
||||
case REPORT_ILLEGAL_ATTACH_PROCESS:
|
||||
|
||||
RtlCopyMemory(
|
||||
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
|
||||
report,
|
||||
sizeof(ATTACH_PROCESS_REPORT)
|
||||
);
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(ATTACH_PROCESS_REPORT));
|
||||
|
||||
total_size += sizeof(ATTACH_PROCESS_REPORT);
|
||||
break;
|
||||
total_size += sizeof(ATTACH_PROCESS_REPORT);
|
||||
break;
|
||||
|
||||
case REPORT_INVALID_PROCESS_ALLOCATION:
|
||||
case REPORT_INVALID_PROCESS_ALLOCATION:
|
||||
|
||||
RtlCopyMemory(
|
||||
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
|
||||
report,
|
||||
sizeof(INVALID_PROCESS_ALLOCATION_REPORT)
|
||||
);
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(INVALID_PROCESS_ALLOCATION_REPORT));
|
||||
|
||||
total_size += sizeof(INVALID_PROCESS_ALLOCATION_REPORT);
|
||||
break;
|
||||
total_size += sizeof(INVALID_PROCESS_ALLOCATION_REPORT);
|
||||
break;
|
||||
|
||||
case REPORT_APC_STACKWALK:
|
||||
case REPORT_APC_STACKWALK:
|
||||
|
||||
RtlCopyMemory(
|
||||
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
|
||||
report,
|
||||
sizeof(APC_STACKWALK_REPORT)
|
||||
);
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(APC_STACKWALK_REPORT));
|
||||
|
||||
total_size += sizeof(APC_STACKWALK_REPORT);
|
||||
break;
|
||||
total_size += sizeof(APC_STACKWALK_REPORT);
|
||||
break;
|
||||
|
||||
case REPORT_HIDDEN_SYSTEM_THREAD:
|
||||
case REPORT_HIDDEN_SYSTEM_THREAD:
|
||||
|
||||
RtlCopyMemory(
|
||||
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
|
||||
report,
|
||||
sizeof(HIDDEN_SYSTEM_THREAD_REPORT)
|
||||
);
|
||||
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
|
||||
total_size,
|
||||
report,
|
||||
sizeof(HIDDEN_SYSTEM_THREAD_REPORT));
|
||||
|
||||
total_size += sizeof(HIDDEN_SYSTEM_THREAD_REPORT);
|
||||
break;
|
||||
total_size += sizeof(HIDDEN_SYSTEM_THREAD_REPORT);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
/* QueuePop frees the node, but we still need to free the returned data */
|
||||
ExFreePoolWithTag(report, REPORT_POOL_TAG);
|
||||
|
||||
/* QueuePop frees the node, but we still need to free the returned data */
|
||||
ExFreePoolWithTag(report, REPORT_POOL_TAG);
|
||||
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
count += 1;
|
||||
}
|
||||
report = QueuePop(&report_queue_config.head);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
KeReleaseGuardedMutex(&report_queue_config.lock);
|
||||
|
||||
Irp->IoStatus.Information = sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size;
|
||||
Irp->IoStatus.Information = sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size;
|
||||
|
||||
header.count = count;
|
||||
header.count = count;
|
||||
|
||||
RtlCopyMemory(
|
||||
report_buffer,
|
||||
&header,
|
||||
sizeof(GLOBAL_REPORT_QUEUE_HEADER));
|
||||
RtlCopyMemory(report_buffer, &header, sizeof(GLOBAL_REPORT_QUEUE_HEADER));
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
report_buffer,
|
||||
sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size
|
||||
);
|
||||
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
||||
report_buffer,
|
||||
sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size);
|
||||
|
||||
if (report_buffer)
|
||||
ExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
|
||||
if (report_buffer)
|
||||
ExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
|
||||
|
||||
DEBUG_LOG("Moved all reports into the IRP, sending !");
|
||||
return STATUS_SUCCESS;
|
||||
DEBUG_LOG("Moved all reports into the IRP, sending !");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple thread safe linked list implementation. All structures should begin
|
||||
* with a SINGLE_LIST_ENTRY structure provided by the windows API. for example:
|
||||
*
|
||||
* typedef struct _LIST_ENTRY_STRUCTURE
|
||||
* {
|
||||
* SINGLE_LIST_ENTRY list;
|
||||
* PVOID address;
|
||||
* UINT32 data;
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* This common structure layout allows us to pass in a callback routine when freeing
|
||||
* allowing immense flexibility to ensure we can free and/or deference any objects
|
||||
* that are referenced in said object.
|
||||
*
|
||||
* I've opted to use a mutex rather then a spinlock since there are many times we
|
||||
* enumerate the list for extended periods aswell as queue up many insertions at
|
||||
* once.
|
||||
*/
|
||||
* Simple thread safe linked list implementation. All structures should begin
|
||||
* with a SINGLE_LIST_ENTRY structure provided by the windows API. for example:
|
||||
*
|
||||
* typedef struct _LIST_ENTRY_STRUCTURE
|
||||
* {
|
||||
* SINGLE_LIST_ENTRY list;
|
||||
* PVOID address;
|
||||
* UINT32 data;
|
||||
* ...
|
||||
* };
|
||||
*
|
||||
* This common structure layout allows us to pass in a callback routine when freeing
|
||||
* allowing immense flexibility to ensure we can free and/or deference any objects
|
||||
* that are referenced in said object.
|
||||
*
|
||||
* I've opted to use a mutex rather then a spinlock since there are many times we
|
||||
* enumerate the list for extended periods aswell as queue up many insertions at
|
||||
* once.
|
||||
*/
|
||||
VOID
|
||||
ListInit(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PKGUARDED_MUTEX Lock
|
||||
)
|
||||
ListInit(_Inout_ PSINGLE_LIST_ENTRY Head, _Inout_ PKGUARDED_MUTEX Lock)
|
||||
{
|
||||
KeInitializeGuardedMutex(Lock);
|
||||
Head->Next = NULL;
|
||||
KeInitializeGuardedMutex(Lock);
|
||||
Head->Next = NULL;
|
||||
}
|
||||
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ListInsert(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY NewEntry,
|
||||
_In_ PKGUARDED_MUTEX Lock
|
||||
)
|
||||
ListInsert(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY NewEntry,
|
||||
_In_ PKGUARDED_MUTEX Lock)
|
||||
{
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
|
||||
PSINGLE_LIST_ENTRY old_entry = Head->Next;
|
||||
PSINGLE_LIST_ENTRY old_entry = Head->Next;
|
||||
|
||||
Head->Next = NewEntry;
|
||||
NewEntry->Next = old_entry;
|
||||
Head->Next = NewEntry;
|
||||
NewEntry->Next = old_entry;
|
||||
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assuming the SINGLE_LIST_ENTRY is the first item in the structure, we
|
||||
* can pass a callback routine to be called before the free occurs. This
|
||||
* allows us to dereference/free structure specific items whilst still allowing
|
||||
* the list to remain flexible.
|
||||
*/
|
||||
* Assuming the SINGLE_LIST_ENTRY is the first item in the structure, we
|
||||
* can pass a callback routine to be called before the free occurs. This
|
||||
* allows us to dereference/free structure specific items whilst still allowing
|
||||
* the list to remain flexible.
|
||||
*/
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
BOOLEAN
|
||||
ListFreeFirstEntry(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_In_ PKGUARDED_MUTEX Lock,
|
||||
_In_opt_ PVOID CallbackRoutine
|
||||
)
|
||||
ListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_In_ PKGUARDED_MUTEX Lock,
|
||||
_In_opt_ PVOID CallbackRoutine)
|
||||
{
|
||||
BOOLEAN result = FALSE;
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
BOOLEAN result = FALSE;
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
|
||||
if (Head->Next)
|
||||
{
|
||||
PSINGLE_LIST_ENTRY entry = Head->Next;
|
||||
if (Head->Next)
|
||||
{
|
||||
PSINGLE_LIST_ENTRY entry = Head->Next;
|
||||
|
||||
VOID(*callback_function_ptr)(PVOID) = CallbackRoutine;
|
||||
(*callback_function_ptr)(entry);
|
||||
VOID (*callback_function_ptr)(PVOID) = CallbackRoutine;
|
||||
(*callback_function_ptr)(entry);
|
||||
|
||||
Head->Next = Head->Next->Next;
|
||||
ExFreePoolWithTag(entry, POOL_TAG_THREAD_LIST);
|
||||
result = TRUE;
|
||||
}
|
||||
Head->Next = Head->Next->Next;
|
||||
ExFreePoolWithTag(entry, POOL_TAG_THREAD_LIST);
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
return result;
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are removing a specific entry, its assumed we have freed and/or dereferenced
|
||||
* any fields in the structure.
|
||||
*/
|
||||
* If we are removing a specific entry, its assumed we have freed and/or dereferenced
|
||||
* any fields in the structure.
|
||||
*/
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ListRemoveEntry(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY Entry,
|
||||
_In_ PKGUARDED_MUTEX Lock
|
||||
)
|
||||
ListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY Entry,
|
||||
_In_ PKGUARDED_MUTEX Lock)
|
||||
{
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
KeAcquireGuardedMutex(Lock);
|
||||
|
||||
PSINGLE_LIST_ENTRY entry = Head->Next;
|
||||
PSINGLE_LIST_ENTRY entry = Head->Next;
|
||||
|
||||
if (!entry)
|
||||
goto unlock;
|
||||
if (!entry)
|
||||
goto unlock;
|
||||
|
||||
if (entry == Entry)
|
||||
{
|
||||
Head->Next = entry->Next;
|
||||
ExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
|
||||
goto unlock;
|
||||
}
|
||||
if (entry == Entry)
|
||||
{
|
||||
Head->Next = entry->Next;
|
||||
ExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
while (entry->Next)
|
||||
{
|
||||
if (entry->Next == Entry)
|
||||
{
|
||||
entry->Next = Entry->Next;
|
||||
ExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
|
||||
goto unlock;
|
||||
}
|
||||
while (entry->Next)
|
||||
{
|
||||
if (entry->Next == Entry)
|
||||
{
|
||||
entry->Next = Entry->Next;
|
||||
ExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
entry = entry->Next;
|
||||
}
|
||||
entry = entry->Next;
|
||||
}
|
||||
|
||||
unlock:
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
KeReleaseGuardedMutex(Lock);
|
||||
}
|
||||
|
|
|
@ -8,31 +8,31 @@
|
|||
|
||||
typedef struct _QUEUE_NODE
|
||||
{
|
||||
struct _QUEUE_NODE* next;
|
||||
PVOID data;
|
||||
struct _QUEUE_NODE* next;
|
||||
PVOID data;
|
||||
|
||||
}QUEUE_NODE, * PQUEUE_NODE;
|
||||
} QUEUE_NODE, *PQUEUE_NODE;
|
||||
|
||||
typedef struct QUEUE_HEAD
|
||||
{
|
||||
struct _QUEUE_NODE* start;
|
||||
struct _QUEUE_NODE* end;
|
||||
KGUARDED_MUTEX lock;
|
||||
INT entries;
|
||||
struct _QUEUE_NODE* start;
|
||||
struct _QUEUE_NODE* end;
|
||||
KGUARDED_MUTEX lock;
|
||||
INT entries;
|
||||
|
||||
}QUEUE_HEAD, * PQUEUE_HEAD;
|
||||
} QUEUE_HEAD, *PQUEUE_HEAD;
|
||||
|
||||
typedef struct _GLOBAL_REPORT_QUEUE_HEADER
|
||||
{
|
||||
INT count;
|
||||
INT count;
|
||||
|
||||
}GLOBAL_REPORT_QUEUE_HEADER, * PGLOBAL_REPORT_QUEUE_HEADER;
|
||||
} GLOBAL_REPORT_QUEUE_HEADER, *PGLOBAL_REPORT_QUEUE_HEADER;
|
||||
|
||||
typedef struct _REPORT_HEADER
|
||||
{
|
||||
INT report_id;
|
||||
INT report_id;
|
||||
|
||||
}REPORT_HEADER, * PREPORT_HEADER;
|
||||
} REPORT_HEADER, *PREPORT_HEADER;
|
||||
|
||||
#define LIST_POOL_TAG 'list'
|
||||
|
||||
|
@ -40,39 +40,28 @@ _IRQL_requires_max_(APC_LEVEL)
|
|||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
QueuePush(
|
||||
_Inout_ PQUEUE_HEAD Head,
|
||||
_In_ PVOID Data
|
||||
);
|
||||
QueuePush(_Inout_ PQUEUE_HEAD Head, _In_ PVOID Data);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
PVOID
|
||||
QueuePop(
|
||||
_Inout_ PQUEUE_HEAD Head
|
||||
);
|
||||
QueuePop(_Inout_ PQUEUE_HEAD Head);
|
||||
|
||||
VOID
|
||||
InitialiseGlobalReportQueue(
|
||||
_Out_ PBOOLEAN Status
|
||||
);
|
||||
InitialiseGlobalReportQueue(_Out_ PBOOLEAN Status);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
InsertReportToQueue(
|
||||
_In_ PVOID Report
|
||||
);
|
||||
InsertReportToQueue(_In_ PVOID Report);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
NTSTATUS
|
||||
HandlePeriodicGlobalReportQueueQuery(
|
||||
_Inout_ PIRP Irp
|
||||
);
|
||||
HandlePeriodicGlobalReportQueueQuery(_Inout_ PIRP Irp);
|
||||
|
||||
_IRQL_requires_max_(APC_LEVEL)
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
|
@ -81,36 +70,27 @@ VOID
|
|||
FreeGlobalReportQueueObjects();
|
||||
|
||||
VOID
|
||||
ListInit(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PKGUARDED_MUTEX Lock
|
||||
);
|
||||
ListInit(_Inout_ PSINGLE_LIST_ENTRY Head, _Inout_ PKGUARDED_MUTEX Lock);
|
||||
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ListInsert(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY NewEntry,
|
||||
_In_ PKGUARDED_MUTEX Lock
|
||||
);
|
||||
ListInsert(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY NewEntry,
|
||||
_In_ PKGUARDED_MUTEX Lock);
|
||||
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
BOOLEAN
|
||||
ListFreeFirstEntry(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_In_ PKGUARDED_MUTEX Lock,
|
||||
_In_opt_ PVOID CallbackRoutine
|
||||
);
|
||||
ListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_In_ PKGUARDED_MUTEX Lock,
|
||||
_In_opt_ PVOID CallbackRoutine);
|
||||
|
||||
_Acquires_lock_(_Lock_kind_mutex_)
|
||||
_Releases_lock_(_Lock_kind_mutex_)
|
||||
VOID
|
||||
ListRemoveEntry(
|
||||
_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY Entry,
|
||||
_In_ PKGUARDED_MUTEX Lock
|
||||
);
|
||||
ListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
|
||||
_Inout_ PSINGLE_LIST_ENTRY Entry,
|
||||
_In_ PKGUARDED_MUTEX Lock);
|
||||
|
||||
#endif
|
266
driver/thread.c
266
driver/thread.c
|
@ -8,190 +8,184 @@
|
|||
#include "queue.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, ValidateKPCRBThreads)
|
||||
#pragma alloc_text(PAGE, DetectThreadsAttachedToProtectedProcess)
|
||||
# pragma alloc_text(PAGE, ValidateKPCRBThreads)
|
||||
# pragma alloc_text(PAGE, DetectThreadsAttachedToProtectedProcess)
|
||||
#endif
|
||||
|
||||
typedef struct _KPRCB_THREAD_VALIDATION_CTX
|
||||
{
|
||||
UINT64 current_kpcrb_thread;
|
||||
UINT8 thread_found_in_pspcidtable;
|
||||
UINT8 thread_found_in_kthreadlist;
|
||||
BOOLEAN finished;
|
||||
UINT64 current_kpcrb_thread;
|
||||
UINT8 thread_found_in_pspcidtable;
|
||||
UINT8 thread_found_in_kthreadlist;
|
||||
BOOLEAN finished;
|
||||
|
||||
}KPRCB_THREAD_VALIDATION_CTX, * PKPRCB_THREAD_VALIDATION_CTX;
|
||||
} KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
|
||||
|
||||
_IRQL_always_function_min_(DISPATCH_LEVEL)
|
||||
STATIC
|
||||
VOID
|
||||
KPRCBThreadValidationProcessCallback(
|
||||
_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
||||
_Inout_opt_ PVOID Context
|
||||
)
|
||||
_IRQL_always_function_min_(DISPATCH_LEVEL) STATIC VOID
|
||||
KPRCBThreadValidationProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
||||
_Inout_opt_ PVOID Context)
|
||||
{
|
||||
UINT32 thread_id;
|
||||
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
|
||||
UINT32 thread_id = 0;
|
||||
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
|
||||
|
||||
if (!Context || context->finished == TRUE)
|
||||
return;
|
||||
if (!Context || context->finished == TRUE)
|
||||
return;
|
||||
|
||||
if (ThreadListEntry->thread == context->current_kpcrb_thread)
|
||||
{
|
||||
context->thread_found_in_kthreadlist = TRUE;
|
||||
if (ThreadListEntry->thread == context->current_kpcrb_thread)
|
||||
{
|
||||
context->thread_found_in_kthreadlist = TRUE;
|
||||
|
||||
thread_id = PsGetThreadId(ThreadListEntry->thread);
|
||||
thread_id = PsGetThreadId(ThreadListEntry->thread);
|
||||
|
||||
if (thread_id != NULL)
|
||||
{
|
||||
context->thread_found_in_pspcidtable = TRUE;
|
||||
context->finished = TRUE;
|
||||
}
|
||||
}
|
||||
if (thread_id != NULL)
|
||||
{
|
||||
context->thread_found_in_pspcidtable = TRUE;
|
||||
context->finished = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* How this will work:
|
||||
*
|
||||
* 1. The KPCRB (processor control block) contains 3 pointers to 3 threads:
|
||||
*
|
||||
* +0x008 CurrentThread : Ptr64 _KTHREAD
|
||||
* +0x010 NextThread : Ptr64 _KTHREAD
|
||||
* +0x018 IdleThread : Ptr64 _KTHREAD
|
||||
*
|
||||
* 2. These threads are stored in a list that is seperate to the KTHREADs linked list.
|
||||
* We know this because if you unlink a process, the threads are still scheduled by
|
||||
* the OS, meaning the OS has a seperate list that it uses to schedule these threads.
|
||||
*
|
||||
* 3. From here we can firstly check if the KTHREAD is within the KTHREAD linked list,
|
||||
* if it is we can then use this to check if its in the PspCidTable by passing it
|
||||
* to PsGetThreadId which returns the thread id by enumerating the PspCidTable and
|
||||
* finding the corresponding object pointer. If the thread id is not found, we know
|
||||
* that it's been removed from the PspCidTable, and if the thread is not in any
|
||||
* process' thread list , we know it's been removed from the KTHREAD linked list.
|
||||
*
|
||||
*/
|
||||
* How this will work:
|
||||
*
|
||||
* 1. The KPCRB (processor control block) contains 3 pointers to 3 threads:
|
||||
*
|
||||
* +0x008 CurrentThread : Ptr64 _KTHREAD
|
||||
* +0x010 NextThread : Ptr64 _KTHREAD
|
||||
* +0x018 IdleThread : Ptr64 _KTHREAD
|
||||
*
|
||||
* 2. These threads are stored in a list that is seperate to the KTHREADs linked list.
|
||||
* We know this because if you unlink a process, the threads are still scheduled by
|
||||
* the OS, meaning the OS has a seperate list that it uses to schedule these threads.
|
||||
*
|
||||
* 3. From here we can firstly check if the KTHREAD is within the KTHREAD linked list,
|
||||
* if it is we can then use this to check if its in the PspCidTable by passing it
|
||||
* to PsGetThreadId which returns the thread id by enumerating the PspCidTable and
|
||||
* finding the corresponding object pointer. If the thread id is not found, we know
|
||||
* that it's been removed from the PspCidTable, and if the thread is not in any
|
||||
* process' thread list , we know it's been removed from the KTHREAD linked list.
|
||||
*
|
||||
*/
|
||||
VOID
|
||||
ValidateKPCRBThreads()
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
UINT64 kpcr;
|
||||
UINT64 kprcb;
|
||||
KAFFINITY old_affinity = { 0 };
|
||||
KPRCB_THREAD_VALIDATION_CTX context = { 0 };
|
||||
UINT64 kpcr = 0;
|
||||
UINT64 kprcb = 0;
|
||||
KAFFINITY old_affinity = {0};
|
||||
KPRCB_THREAD_VALIDATION_CTX context = {0};
|
||||
|
||||
for (LONG processor_index = 0; processor_index < KeQueryActiveProcessorCount(0); processor_index++)
|
||||
{
|
||||
old_affinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1ull << processor_index));
|
||||
for (LONG processor_index = 0; processor_index < KeQueryActiveProcessorCount(0);
|
||||
processor_index++)
|
||||
{
|
||||
old_affinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1ull << processor_index));
|
||||
|
||||
while (KeGetCurrentProcessorNumber() != processor_index)
|
||||
YieldProcessor();
|
||||
while (KeGetCurrentProcessorNumber() != processor_index)
|
||||
YieldProcessor();
|
||||
|
||||
kpcr = __readmsr(IA32_GS_BASE);
|
||||
kprcb = kpcr + KPRCB_OFFSET_FROM_GS_BASE;
|
||||
kpcr = __readmsr(IA32_GS_BASE);
|
||||
kprcb = kpcr + KPRCB_OFFSET_FROM_GS_BASE;
|
||||
|
||||
/* sanity check */
|
||||
if (!MmIsAddressValid(kprcb + KPCRB_CURRENT_THREAD))
|
||||
continue;
|
||||
/* sanity check */
|
||||
if (!MmIsAddressValid(kprcb + KPCRB_CURRENT_THREAD))
|
||||
continue;
|
||||
|
||||
context.current_kpcrb_thread = *(UINT64*)(kprcb + KPCRB_CURRENT_THREAD);
|
||||
context.current_kpcrb_thread = *(UINT64*)(kprcb + KPCRB_CURRENT_THREAD);
|
||||
|
||||
DEBUG_LOG("Proc number: %lx, Current thread: %llx", processor_index, context.current_kpcrb_thread);
|
||||
DEBUG_LOG("Proc number: %lx, Current thread: %llx",
|
||||
processor_index,
|
||||
context.current_kpcrb_thread);
|
||||
|
||||
if (!context.current_kpcrb_thread)
|
||||
continue;
|
||||
if (!context.current_kpcrb_thread)
|
||||
continue;
|
||||
|
||||
EnumerateThreadListWithCallbackRoutine(
|
||||
KPRCBThreadValidationProcessCallback,
|
||||
&context
|
||||
);
|
||||
EnumerateThreadListWithCallbackRoutine(KPRCBThreadValidationProcessCallback,
|
||||
&context);
|
||||
|
||||
DEBUG_LOG("Found in kthread: %lx, found in pspcid: %lx", (UINT32)context.thread_found_in_kthreadlist, (UINT32)context.thread_found_in_pspcidtable);
|
||||
DEBUG_LOG("Found in kthread: %lx, found in pspcid: %lx",
|
||||
(UINT32)context.thread_found_in_kthreadlist,
|
||||
(UINT32)context.thread_found_in_pspcidtable);
|
||||
|
||||
if (context.current_kpcrb_thread == FALSE || context.thread_found_in_pspcidtable == FALSE)
|
||||
{
|
||||
PHIDDEN_SYSTEM_THREAD_REPORT report =
|
||||
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(HIDDEN_SYSTEM_THREAD_REPORT), REPORT_POOL_TAG);
|
||||
if (context.current_kpcrb_thread == FALSE ||
|
||||
context.thread_found_in_pspcidtable == FALSE)
|
||||
{
|
||||
PHIDDEN_SYSTEM_THREAD_REPORT report =
|
||||
ExAllocatePool2(POOL_FLAG_NON_PAGED,
|
||||
sizeof(HIDDEN_SYSTEM_THREAD_REPORT),
|
||||
REPORT_POOL_TAG);
|
||||
|
||||
if (!report)
|
||||
goto increment;
|
||||
if (!report)
|
||||
goto increment;
|
||||
|
||||
report->report_code = REPORT_HIDDEN_SYSTEM_THREAD;
|
||||
report->found_in_kthreadlist = context.thread_found_in_kthreadlist;
|
||||
report->found_in_pspcidtable = context.thread_found_in_pspcidtable;
|
||||
report->thread_id = PsGetThreadId(context.current_kpcrb_thread);
|
||||
report->thread_address = context.current_kpcrb_thread;
|
||||
report->report_code = REPORT_HIDDEN_SYSTEM_THREAD;
|
||||
report->found_in_kthreadlist = context.thread_found_in_kthreadlist;
|
||||
report->found_in_pspcidtable = context.thread_found_in_pspcidtable;
|
||||
report->thread_id = PsGetThreadId(context.current_kpcrb_thread);
|
||||
report->thread_address = context.current_kpcrb_thread;
|
||||
|
||||
RtlCopyMemory(
|
||||
report->thread,
|
||||
context.current_kpcrb_thread,
|
||||
sizeof(report->thread));
|
||||
RtlCopyMemory(
|
||||
report->thread, context.current_kpcrb_thread, sizeof(report->thread));
|
||||
|
||||
InsertReportToQueue(report);
|
||||
}
|
||||
InsertReportToQueue(report);
|
||||
}
|
||||
|
||||
increment:
|
||||
KeRevertToUserAffinityThreadEx(old_affinity);
|
||||
}
|
||||
increment:
|
||||
KeRevertToUserAffinityThreadEx(old_affinity);
|
||||
}
|
||||
}
|
||||
|
||||
_IRQL_always_function_min_(DISPATCH_LEVEL)
|
||||
STATIC
|
||||
VOID
|
||||
DetectAttachedThreadsProcessCallback(
|
||||
_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
||||
_Inout_opt_ PVOID Context
|
||||
)
|
||||
_IRQL_always_function_min_(DISPATCH_LEVEL) STATIC VOID
|
||||
DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
||||
_Inout_opt_ PVOID Context)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Context);
|
||||
UNREFERENCED_PARAMETER(Context);
|
||||
|
||||
PKAPC_STATE apc_state;
|
||||
PEPROCESS protected_process = NULL;
|
||||
PKAPC_STATE apc_state = NULL;
|
||||
PEPROCESS protected_process = NULL;
|
||||
|
||||
GetProtectedProcessEProcess(&protected_process);
|
||||
GetProtectedProcessEProcess(&protected_process);
|
||||
|
||||
if (protected_process == NULL)
|
||||
return;
|
||||
if (protected_process == NULL)
|
||||
return;
|
||||
|
||||
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread + KTHREAD_APC_STATE_OFFSET);
|
||||
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread + KTHREAD_APC_STATE_OFFSET);
|
||||
|
||||
if (apc_state->Process == protected_process)
|
||||
{
|
||||
DEBUG_LOG("Program attached to notepad: %llx", (UINT64)ThreadListEntry->thread);
|
||||
if (apc_state->Process == protected_process)
|
||||
{
|
||||
DEBUG_LOG("Program attached to notepad: %llx", (UINT64)ThreadListEntry->thread);
|
||||
|
||||
PATTACH_PROCESS_REPORT report =
|
||||
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);
|
||||
PATTACH_PROCESS_REPORT report = ExAllocatePool2(
|
||||
POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);
|
||||
|
||||
if (!report)
|
||||
return;
|
||||
if (!report)
|
||||
return;
|
||||
|
||||
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
|
||||
report->thread_id = PsGetThreadId(ThreadListEntry->thread);
|
||||
report->thread_address = ThreadListEntry->thread;
|
||||
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
|
||||
report->thread_id = PsGetThreadId(ThreadListEntry->thread);
|
||||
report->thread_address = ThreadListEntry->thread;
|
||||
|
||||
InsertReportToQueue(report);
|
||||
}
|
||||
InsertReportToQueue(report);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* I did not reverse this myself and previously had no idea how you would go about
|
||||
* detecting KiAttachProcess so credits to KANKOSHEV for the explanation:
|
||||
*
|
||||
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
|
||||
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
|
||||
*
|
||||
* To expand on his writeup a little, the offset that he provides is equivalent to PKAPC_STATE->Process.
|
||||
* This is where KiAttachProcess writes the process that thread is attaching to when it's called.
|
||||
* The APC_STATE structure holds relevant information about the thread's APC state and is quite
|
||||
* important during context switch scenarios as it's how the thread determines if it has any APC's
|
||||
* queued.
|
||||
*/
|
||||
VOID DetectThreadsAttachedToProtectedProcess()
|
||||
* I did not reverse this myself and previously had no idea how you would go about
|
||||
* detecting KiAttachProcess so credits to KANKOSHEV for the explanation:
|
||||
*
|
||||
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
|
||||
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
|
||||
*
|
||||
* To expand on his writeup a little, the offset that he provides is equivalent to
|
||||
* PKAPC_STATE->Process. This is where KiAttachProcess writes the process that thread is attaching
|
||||
* to when it's called. The APC_STATE structure holds relevant information about the thread's APC
|
||||
* state and is quite important during context switch scenarios as it's how the thread determines if
|
||||
* it has any APC's queued.
|
||||
*/
|
||||
VOID
|
||||
DetectThreadsAttachedToProtectedProcess()
|
||||
{
|
||||
PAGED_CODE();
|
||||
PAGED_CODE();
|
||||
|
||||
EnumerateThreadListWithCallbackRoutine(
|
||||
DetectAttachedThreadsProcessCallback,
|
||||
NULL
|
||||
);
|
||||
EnumerateThreadListWithCallbackRoutine(DetectAttachedThreadsProcessCallback, NULL);
|
||||
}
|
||||
|
|
|
@ -3,26 +3,26 @@
|
|||
|
||||
#include <ntifs.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[4096];
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[4096];
|
||||
|
||||
}HIDDEN_SYSTEM_THREAD_REPORT, * PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
} HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
|
||||
typedef struct _ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT32 thread_id;
|
||||
UINT64 thread_address;
|
||||
INT report_code;
|
||||
UINT32 thread_id;
|
||||
UINT64 thread_address;
|
||||
|
||||
}ATTACH_PROCESS_REPORT, * PATTACH_PROCESS_REPORT;
|
||||
} ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
|
||||
|
||||
VOID
|
||||
ValidateKPCRBThreads();
|
||||
|
|
|
@ -3,33 +3,32 @@
|
|||
|
||||
#include <ntddk.h>
|
||||
|
||||
extern UINT32 KTHREAD_STACK_BASE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_STACK_LIMIT_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_THREADLIST_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_APC_STATE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_START_ADDRESS_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_MISC_FLAGS_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_WAIT_IRQL_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_PREVIOUS_MODE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_STATE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_STACK_BASE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_STACK_LIMIT_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_THREADLIST_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_APC_STATE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_START_ADDRESS_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_MISC_FLAGS_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_WAIT_IRQL_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_PREVIOUS_MODE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_STATE_OFFSET = 0;
|
||||
extern UINT32 KTHREAD_MISC_FLAGS_APC_QUEUEABLE = 0;
|
||||
extern UINT32 KTHREAD_MISC_FLAGS_ALERTABLE = 0;
|
||||
extern UINT32 KTHREAD_MISC_FLAGS_ALERTABLE = 0;
|
||||
|
||||
extern UINT32 EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_VAD_ROOT_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_OBJECT_TABLE_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_IMAGE_NAME_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_PEB_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_VAD_ROOT_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_OBJECT_TABLE_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_IMAGE_NAME_OFFSET = 0;
|
||||
extern UINT32 EPROCESS_PEB_OFFSET = 0;
|
||||
|
||||
extern UINT32 KPROCESS_THREADLIST_OFFSET = 0;
|
||||
extern UINT32 KPROCESS_THREADLIST_OFFSET = 0;
|
||||
extern UINT32 KPROCESS_DIRECTORY_TABLE_BASE_OFFSET = 0;
|
||||
|
||||
extern UINT32 OBJECT_HEADER_TYPE_INDEX_OFFSET = 0;
|
||||
|
||||
extern UINT32 POOL_HEADER_BLOCK_SIZE_OFFSET = 0;
|
||||
extern UINT32 POOL_HEADER_TAG_OFFSET = 0;
|
||||
extern UINT32 POOL_HEADER_TAG_OFFSET = 0;
|
||||
|
||||
extern UINT32 KPCRB_CURRENT_THREAD_OFFSET = 0;
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue