some formatting. Smiley face

This commit is contained in:
lhodges1 2023-12-13 15:06:27 +11:00
parent a043150844
commit 84c4f5137f
21 changed files with 5680 additions and 6224 deletions

131
.clang-format Normal file
View 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

View file

@ -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();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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;
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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
//);

View file

@ -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;
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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();

View file

@ -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