80 line limit - need to refactor lots of code but ceebs atm

This commit is contained in:
donnaskiez 2024-04-13 14:40:51 +10:00
parent 4037283f59
commit c3e0dc65b0
23 changed files with 2961 additions and 2493 deletions

View file

@ -1,5 +1,4 @@
Language: Cpp
BasedOnStyle: webkit
BasedOnStyle: webkit
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
@ -14,7 +13,6 @@ AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
@ -29,10 +27,9 @@ AlwaysBreakTemplateDeclarations: true #false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: false
AllowAllParametersOfDeclarationOnNextLine: true
BreakBeforeBraces: Custom
BreakBeforeBraces: Stroustrup
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
@ -51,7 +48,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakStringLiterals: false
ColumnLimit: 100
ColumnLimit: 80
CommentPragmas: '^begin_wpp|^end_wpp|^FUNC |^USESUFFIX |^USESUFFIX '
ConstructorInitializerAllOnOneLineOrOnePerLine: true
@ -81,7 +78,6 @@ SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
@ -127,5 +123,5 @@ StatementMacros: [
'__drv_freesMem',
]
TabWidth: '8'
TabWidth: '4'
UseTab: Never

View file

@ -16,8 +16,7 @@ GetApcContext(_Out_ PVOID* Context, _In_ LONG ContextIdentifier)
{
AcquireDriverConfigLock();
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++) {
PAPC_CONTEXT_HEADER header = GetApcContextArray()[index];
if (!header)
@ -44,8 +43,7 @@ FreeApcContextStructure(_Out_ PAPC_CONTEXT_HEADER Context)
{
DEBUG_VERBOSE("All APCs executed, freeing context structure");
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++) {
PUINT64 entry = GetApcContextArray();
if (entry[index] != Context)
@ -95,32 +93,35 @@ FreeApcAndDecrementApcCount(_Inout_ PRKAPC Apc, _In_ LONG ContextId)
/*
* The reason we use a query model rather then checking the count of queued APCs
* after each APC free and decrement is that the lock will be recursively acquired by
* freeing threads (i.e executing APCs) rather then APC allocation threads. The reason for this
* being that freeing threads are executing at a higher IRQL then the APC allocation
* thread, hence they are granted higher priority by the scheduler when determining
* which thread will accquire the lock next:
* after each APC free and decrement is that the lock will be recursively
* acquired by freeing threads (i.e executing APCs) rather then APC allocation
* threads. The reason for this being that freeing threads are executing at a
* higher IRQL then the APC allocation thread, hence they are granted higher
* priority by the scheduler when determining which thread will accquire the
* lock next:
*
* [+] Freeing thread -> ApcKernelRoutine IRQL: 1 (APC_LEVEL)
* [+] Allocation thread -> ValidateThreadViaKernelApcCallback IRQL: 0 (PASSIVE_LEVEL)
* [+] Allocation thread -> ValidateThreadViaKernelApcCallback IRQL: 0
* (PASSIVE_LEVEL)
*
* As a result, once an APC is executed and reaches the freeing stage, it will acquire the
* lock and decrement it. Then, if atleast 1 APC execution thread is waiting on the lock,
* it will be prioritised due to its higher IRQL and the cycle will continue. Eventually,
* the count will reach 0 due to recursive acquisition by the executing APC threads and then
* the function will free the APC context structure. This will then cause a bug check the next
* time a thread accesses the context structure and hence not good :c.
* As a result, once an APC is executed and reaches the freeing stage, it will
* acquire the lock and decrement it. Then, if atleast 1 APC execution thread is
* waiting on the lock, it will be prioritised due to its higher IRQL and the
* cycle will continue. Eventually, the count will reach 0 due to recursive
* acquisition by the executing APC threads and then the function will free the
* APC context structure. This will then cause a bug check the next time a
* thread accesses the context structure and hence not good :c.
*
* So to combat this, we add in a flag specifying whether or not an allocation of APCs is
* in progress, and even if the count is 0 we will not free the context structure until
* the count is 0 and allocation_in_progress is 0. We can then call this function alongside
* other query callbacks via IOCTL to constantly monitor the status of open APC contexts.
* So to combat this, we add in a flag specifying whether or not an allocation
* of APCs is in progress, and even if the count is 0 we will not free the
* context structure until the count is 0 and allocation_in_progress is 0. We
* can then call this function alongside other query callbacks via IOCTL to
* constantly monitor the status of open APC contexts.
*/
NTSTATUS
QueryActiveApcContextsForCompletion()
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++) {
PAPC_CONTEXT_HEADER entry = NULL;
GetApcContextByIndex(&entry, index);
AcquireDriverConfigLock();
@ -131,8 +132,7 @@ QueryActiveApcContextsForCompletion()
if (entry->count > 0 || entry->allocation_in_progress == TRUE)
goto increment;
switch (entry->context_id)
{
switch (entry->context_id) {
case APC_CONTEXT_ID_STACKWALK:
FreeApcStackwalkApcContextInformation(entry);
FreeApcContextStructure(entry);
@ -154,12 +154,10 @@ InsertApcContext(_In_ PVOID Context)
AcquireDriverConfigLock();
PAPC_CONTEXT_HEADER header = Context;
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++) {
PUINT64 entry = GetApcContextArray();
if (entry[index] == NULL)
{
if (entry[index] == NULL) {
entry[index] = Context;
goto end;
}
@ -169,36 +167,38 @@ end:
}
/*
* The driver config structure holds an array of pointers to APC context structures. These
* APC context structures are unique to each APC operation that this driver will perform. For
* example, a single context will manage all APCs that are used to stackwalk, whilst another
* context will be used to manage all APCs used to query a threads memory for example.
* The driver config structure holds an array of pointers to APC context
* structures. These APC context structures are unique to each APC operation
* that this driver will perform. For example, a single context will manage all
* APCs that are used to stackwalk, whilst another context will be used to
* manage all APCs used to query a threads memory for example.
*
* Due to the nature of APCs, its important to keep a total or count of the number of APCs we
* have allocated and queued to threads. This information is stored in the APC_CONTEXT_HEADER which
* all APC context structures will contain as the first entry in their structure. It holds the
* ContextId which is a unique identifier for the type of APC operation it is managing aswell as the
* number of currently queued APCs.
* Due to the nature of APCs, its important to keep a total or count of the
* number of APCs we have allocated and queued to threads. This information is
* stored in the APC_CONTEXT_HEADER which all APC context structures will
* contain as the first entry in their structure. It holds the ContextId which
* is a unique identifier for the type of APC operation it is managing aswell as
* the number of currently queued APCs.
*
* When an APC is allocated a queued, we increment this count. When an APC is completed and freed,
* we decrement this counter and free the APC itself. If all APCs have been freed and the counter is
* 0,the following objects will be freed:
* When an APC is allocated a queued, we increment this count. When an APC is
* completed and freed, we decrement this counter and free the APC itself. If
* all APCs have been freed and the counter is 0,the following objects will be
* freed:
*
* 1. Any additional allocations used by the APC stored in the context structure
* 2. The APC context structure for the given APC operation
* 3. The APC context entry in g_DriverConfig->>apc_contexts will be zero'd.
*
* It's important to remember that the driver can unload when pending APC's have not been freed due
* to the limitations windows places on APCs, however I am in the process of finding a solution for
* this.
* It's important to remember that the driver can unload when pending APC's have
* not been freed due to the limitations windows places on APCs, however I am in
* the process of finding a solution for this.
*/
BOOLEAN
DrvUnloadFreeAllApcContextStructures()
{
AcquireDriverConfigLock();
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++)
{
for (INT index = 0; index < MAXIMUM_APC_CONTEXTS; index++) {
PUINT64 entry = GetApcContextArray();
if (entry[index] == NULL)
@ -206,8 +206,7 @@ DrvUnloadFreeAllApcContextStructures()
PAPC_CONTEXT_HEADER context = entry[index];
if (context->count > 0)
{
if (context->count > 0) {
ReleaseDriverConfigLock();
return FALSE;
}

View file

@ -27,8 +27,8 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
#endif
/*
* Its important on unload we dereference any objects to ensure the kernels reference
* count remains correct.
* Its important on unload we dereference any objects to ensure the kernels
* reference count remains correct.
*/
VOID
CleanupProcessListFreeCallback(_In_ PPROCESS_LIST_ENTRY ProcessListEntry)
@ -69,19 +69,19 @@ UnregisterThreadCreateNotifyRoutine()
}
/*
* While ExDeleteLookasideListEx already frees each item, we wanna allow ourselves to reduce the
* reference count to any objects we are referencing.
* While ExDeleteLookasideListEx already frees each item, we wanna allow
* ourselves to reduce the reference count to any objects we are referencing.
*/
VOID
CleanupProcessListOnDriverUnload()
{
PPROCESS_LIST_HEAD list = GetProcessList();
DEBUG_VERBOSE("Freeing process list");
for (;;)
{
for (;;) {
if (!LookasideListFreeFirstEntry(
&list->start, &list->lock, CleanupProcessListFreeCallback))
{
&list->start,
&list->lock,
CleanupProcessListFreeCallback)) {
ExDeleteLookasideListEx(&list->lookaside_list);
return;
}
@ -93,11 +93,11 @@ CleanupThreadListOnDriverUnload()
{
PTHREAD_LIST_HEAD list = GetThreadList();
DEBUG_VERBOSE("Freeing thread list!");
for (;;)
{
for (;;) {
if (!LookasideListFreeFirstEntry(
&list->start, &list->lock, CleanupThreadListFreeCallback))
{
&list->start,
&list->lock,
CleanupThreadListFreeCallback)) {
ExDeleteLookasideListEx(&list->lookaside_list);
return;
}
@ -108,16 +108,15 @@ VOID
CleanupDriverListOnDriverUnload()
{
PDRIVER_LIST_HEAD list = GetDriverList();
for (;;)
{
for (;;) {
if (!ListFreeFirstEntry(&list->start, &list->lock, NULL))
return;
}
}
VOID
EnumerateThreadListWithCallbackRoutine(_In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context)
EnumerateThreadListWithCallbackRoutine(
_In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
{
PTHREAD_LIST_HEAD list = GetThreadList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -127,8 +126,7 @@ EnumerateThreadListWithCallbackRoutine(_In_ THREADLIST_CALLBACK_ROUTINE Callback
PTHREAD_LIST_ENTRY entry = list->start.Next;
while (entry)
{
while (entry) {
CallbackRoutine(entry, Context);
entry = entry->list.Next;
}
@ -138,8 +136,8 @@ unlock:
}
VOID
EnumerateProcessListWithCallbackRoutine(_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context)
EnumerateProcessListWithCallbackRoutine(
_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
{
PPROCESS_LIST_HEAD list = GetProcessList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -149,8 +147,7 @@ EnumerateProcessListWithCallbackRoutine(_In_ PROCESSLIST_CALLBACK_ROUTINE Callba
PPROCESS_LIST_ENTRY entry = list->start.Next;
while (entry)
{
while (entry) {
CallbackRoutine(entry, Context);
entry = entry->list.Next;
}
@ -160,8 +157,8 @@ unlock:
}
VOID
EnumerateDriverListWithCallbackRoutine(_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context)
EnumerateDriverListWithCallbackRoutine(
_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
{
PDRIVER_LIST_HEAD list = GetDriverList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -171,8 +168,7 @@ EnumerateDriverListWithCallbackRoutine(_In_ DRIVERLIST_CALLBACK_ROUTINE Callback
PDRIVER_LIST_ENTRY entry = list->start.Next;
while (entry)
{
while (entry) {
CallbackRoutine(entry, Context);
entry = entry->list.Next;
}
@ -187,7 +183,9 @@ DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry,
{
Extended->ImageBase = Entry->ImageBase;
Extended->ImageSize = Entry->ImageSize;
RtlCopyMemory(Extended->FullPathName, Entry->path, sizeof(Extended->FullPathName));
RtlCopyMemory(Extended->FullPathName,
Entry->path,
sizeof(Extended->FullPathName));
}
NTSTATUS
@ -213,41 +211,44 @@ InitialiseDriverList()
status = GetSystemModuleInformation(&modules);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("GetSystemModuleInformation failed with status %x",
status);
return status;
}
/* skip hal.dll and ntoskrnl.exe */
for (INT index = 2; index < modules.module_count; index++)
{
entry = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(DRIVER_LIST_ENTRY), POOL_TAG_DRIVER_LIST);
for (INT index = 2; index < modules.module_count; index++) {
entry = ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(DRIVER_LIST_ENTRY),
POOL_TAG_DRIVER_LIST);
if (!entry)
continue;
module_entry = &((PRTL_MODULE_EXTENDED_INFO)modules.address)[index];
module_entry =
&((PRTL_MODULE_EXTENDED_INFO)modules.address)[index];
entry->hashed = TRUE;
entry->ImageBase = module_entry->ImageBase;
entry->ImageSize = module_entry->ImageSize;
RtlCopyMemory(
entry->path, module_entry->FullPathName, sizeof(module_entry->FullPathName));
RtlCopyMemory(entry->path,
module_entry->FullPathName,
sizeof(module_entry->FullPathName));
status = HashModule(module_entry, entry->text_hash);
if (status == STATUS_INVALID_IMAGE_WIN_32)
{
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
if (status == STATUS_INVALID_IMAGE_WIN_32) {
DEBUG_ERROR(
"32 bit module not hashed, will hash later. %x",
status);
entry->hashed = FALSE;
entry->x86 = TRUE;
InsertHeadList(&list->deferred_list, &entry->deferred_entry);
InsertHeadList(&list->deferred_list,
&entry->deferred_entry);
}
else if (!NT_SUCCESS(status))
{
else if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashModule failed with status %x", status);
entry->hashed = FALSE;
}
@ -265,11 +266,13 @@ end:
}
/*
* I actually think a spinlock here for the driver list is what we want rather then a mutex, but
* implementing a spinlock has its challenges... todo: have a think!
* I actually think a spinlock here for the driver list is what we want rather
* then a mutex, but implementing a spinlock has its challenges... todo: have a
* think!
*/
VOID
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Entry)
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase,
_Out_ PDRIVER_LIST_ENTRY* Entry)
{
PDRIVER_LIST_HEAD list = GetDriverList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -277,10 +280,8 @@ FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Ent
PDRIVER_LIST_ENTRY entry = (PDRIVER_LIST_ENTRY)list->start.Next;
while (entry)
{
if (entry->ImageBase == ImageBase)
{
while (entry) {
if (entry->ImageBase == ImageBase) {
*Entry = entry;
goto unlock;
}
@ -314,8 +315,9 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
if (entry)
return;
entry =
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DRIVER_LIST_ENTRY), POOL_TAG_DRIVER_LIST);
entry = ExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(DRIVER_LIST_ENTRY),
POOL_TAG_DRIVER_LIST);
if (!entry)
return;
@ -328,23 +330,24 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
module.ImageBase = ImageInfo->ImageBase;
module.ImageSize = ImageInfo->ImageSize;
if (FullImageName)
{
status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE);
if (FullImageName) {
status = RtlUnicodeStringToAnsiString(
&ansi_path, FullImageName, TRUE);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"RtlUnicodeStringToAnsiString failed with status %x",
status);
goto hash;
}
if (ansi_path.Length > sizeof(module.FullPathName))
{
if (ansi_path.Length > sizeof(module.FullPathName)) {
RtlFreeAnsiString(&ansi_path);
goto hash;
}
RtlCopyMemory(module.FullPathName, ansi_path.Buffer, ansi_path.Length);
RtlCopyMemory(
module.FullPathName, ansi_path.Buffer, ansi_path.Length);
RtlCopyMemory(entry->path, ansi_path.Buffer, ansi_path.Length);
RtlFreeAnsiString(&ansi_path);
@ -355,14 +358,13 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
hash:
status = HashModule(&module, &entry->text_hash);
if (status == STATUS_INVALID_IMAGE_WIN_32)
{
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
if (status == STATUS_INVALID_IMAGE_WIN_32) {
DEBUG_ERROR("32 bit module not hashed, will hash later. %x",
status);
entry->x86 = TRUE;
entry->hashed = FALSE;
}
else if (!NT_SUCCESS(status))
{
else if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashModule failed with status %x", status);
entry->hashed = FALSE;
}
@ -385,9 +387,9 @@ InitialiseProcessList()
POOL_TAG_PROCESS_LIST,
0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ExInitializeLookasideListEx failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ExInitializeLookasideListEx failed with status %x",
status);
return status;
}
@ -411,9 +413,9 @@ InitialiseThreadList()
POOL_TAG_PROCESS_LIST,
0);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ExInitializeLookasideListEx failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ExInitializeLookasideListEx failed with status %x",
status);
return status;
}
@ -423,7 +425,8 @@ InitialiseThreadList()
}
VOID
FindProcessListEntryByProcess(_In_ PKPROCESS Process, _Out_ PPROCESS_LIST_ENTRY* Entry)
FindProcessListEntryByProcess(_In_ PKPROCESS Process,
_Out_ PPROCESS_LIST_ENTRY* Entry)
{
PPROCESS_LIST_HEAD list = GetProcessList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -431,10 +434,8 @@ FindProcessListEntryByProcess(_In_ PKPROCESS Process, _Out_ PPROCESS_LIST_ENTRY*
PPROCESS_LIST_ENTRY entry = (PPROCESS_LIST_ENTRY)list->start.Next;
while (entry)
{
if (entry->process == Process)
{
while (entry) {
if (entry->process == Process) {
*Entry = entry;
goto unlock;
}
@ -446,7 +447,8 @@ unlock:
}
VOID
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, _Out_ PTHREAD_LIST_ENTRY* Entry)
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread,
_Out_ PTHREAD_LIST_ENTRY* Entry)
{
PTHREAD_LIST_HEAD list = GetThreadList();
ImpKeAcquireGuardedMutex(&list->lock);
@ -454,10 +456,8 @@ FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, _Out_ PTHREAD_LIST_ENTR
PTHREAD_LIST_ENTRY entry = (PTHREAD_LIST_ENTRY)list->start.Next;
while (entry)
{
if (entry->thread == Thread)
{
while (entry) {
if (entry->thread == Thread) {
*Entry = entry;
goto unlock;
}
@ -469,7 +469,9 @@ unlock:
}
VOID
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create)
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId,
_In_ HANDLE ProcessId,
_In_ BOOLEAN Create)
{
PPROCESS_LIST_ENTRY entry = NULL;
PKPROCESS parent = NULL;
@ -489,8 +491,7 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
process_name = ImpPsGetProcessImageFileName(process);
if (Create)
{
if (Create) {
entry = ExAllocateFromLookasideListEx(&list->lookaside_list);
if (!entry)
@ -505,11 +506,10 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
ListInsert(&list->start, entry, &list->lock);
/*
* Notify to our driver that we can hash x86 modules, and hash any x86 modules that
* werent hashed.
* Notify to our driver that we can hash x86 modules, and hash
* any x86 modules that werent hashed.
*/
if (!strcmp(process_name, "winlogon.exe"))
{
if (!strcmp(process_name, "winlogon.exe")) {
DEBUG_VERBOSE("Winlogon process has started");
driver_list->can_hash_x86 = TRUE;
IoQueueWorkItem(driver_list->deferred_work_item,
@ -518,8 +518,7 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
NULL);
}
}
else
{
else {
FindProcessListEntryByProcess(process, &entry);
if (!entry)
@ -533,7 +532,9 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
}
VOID
ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOLEAN Create)
ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId,
_In_ HANDLE ThreadId,
_In_ BOOLEAN Create)
{
PTHREAD_LIST_ENTRY entry = NULL;
PKTHREAD thread = NULL;
@ -550,8 +551,7 @@ ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOL
if (!thread || !process)
return;
if (Create)
{
if (Create) {
entry = ExAllocateFromLookasideListEx(&list->lookaside_list);
if (!entry)
@ -567,8 +567,7 @@ ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOL
ListInsert(&list->start, &entry->list, &list->lock);
}
else
{
else {
FindThreadListEntryByThreadAddress(thread, &entry);
if (!entry)
@ -582,8 +581,9 @@ ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOL
}
VOID
ObPostOpCallbackRoutine(_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation)
ObPostOpCallbackRoutine(_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION
OperationInformation)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistrationContext);
@ -608,20 +608,21 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
* This callback routine is executed in the context of the thread that
* is requesting to open said handle
*/
PEPROCESS process_creator = PsGetCurrentProcess();
PEPROCESS protected_process = NULL;
PEPROCESS target_process = (PEPROCESS)OperationInformation->Object;
HANDLE process_creator_id = ImpPsGetProcessId(process_creator);
LONG protected_process_id = 0;
LPCSTR process_creator_name = NULL;
LPCSTR target_process_name = NULL;
LPCSTR protected_process_name = NULL;
POB_CALLBACKS_CONFIG configuration = NULL;
PEPROCESS process_creator = PsGetCurrentProcess();
PEPROCESS protected_process = NULL;
PEPROCESS target_process = (PEPROCESS)OperationInformation->Object;
HANDLE process_creator_id = ImpPsGetProcessId(process_creator);
LONG protected_process_id = 0;
LPCSTR process_creator_name = NULL;
LPCSTR target_process_name = NULL;
LPCSTR protected_process_name = NULL;
POB_CALLBACKS_CONFIG configuration = NULL;
/*
* This is to prevent the condition where the thread executing this function is scheduled
* whilst we are cleaning up the callbacks on driver unload. We must hold the driver config
* lock to ensure the pool containing the callback configuration lock is not freed
* This is to prevent the condition where the thread executing this
* function is scheduled whilst we are cleaning up the callbacks on
* driver unload. We must hold the driver config lock to ensure the pool
* containing the callback configuration lock is not freed
*/
SessionGetCallbackConfiguration(&configuration);
@ -635,48 +636,49 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
if (!protected_process_id || !protected_process)
goto end;
process_creator_name = ImpPsGetProcessImageFileName(process_creator);
target_process_name = ImpPsGetProcessImageFileName(target_process);
protected_process_name = ImpPsGetProcessImageFileName(protected_process);
process_creator_name = ImpPsGetProcessImageFileName(process_creator);
target_process_name = ImpPsGetProcessImageFileName(target_process);
protected_process_name =
ImpPsGetProcessImageFileName(protected_process);
if (!protected_process_name || !target_process_name)
goto end;
if (!strcmp(protected_process_name, target_process_name))
{
if (!strcmp(protected_process_name, target_process_name)) {
/*
* WerFault is some windows 11 application that cries when it cant get a handle,
* so well allow it for now... todo; learn more about it
* WerFault is some windows 11 application that cries when it
* cant get a handle, so well allow it for now... todo; learn
* more about it
*
* todo: perform stricter checks rather then the image name. perhapds check some
* certificate or something.
* todo: perform stricter checks rather then the image name.
* perhapds check some certificate or something.
*/
if (!strcmp(process_creator_name, "lsass.exe") ||
!strcmp(process_creator_name, "csrss.exe") ||
!strcmp(process_creator_name, "WerFault.exe") ||
!strcmp(process_creator_name, "MsMpEng.exe") ||
!strcmp(process_creator_name, target_process_name))
{
!strcmp(process_creator_name, target_process_name)) {
/* We will downgrade these handles later */
// DEBUG_LOG("Handles created by CSRSS, LSASS and WerFault are allowed for
// now...");
// DEBUG_LOG("Handles created by CSRSS, LSASS and
// WerFault are allowed for now...");
}
else if (target_process == process_creator)
{
else if (target_process == process_creator) {
// DEBUG_LOG("handles made by NOTEPAD r okay :)");
/* handles created by the game (notepad) are okay */
}
else
{
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess =
else {
OperationInformation->Parameters
->CreateHandleInformation.DesiredAccess =
deny_access;
OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess =
OperationInformation->Parameters
->DuplicateHandleInformation.DesiredAccess =
deny_access;
/*
* These processes will constantly open handles to any open process for
* various reasons, so we will still strip them but we won't report them..
* for now atleast.
* These processes will constantly open handles to any
* open process for various reasons, so we will still
* strip them but we won't report them.. for now
* atleast.
*/
if (!strcmp(process_creator_name, "Discord.exe") ||
@ -692,8 +694,10 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
// if (!report)
// goto end;
// report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
// report->is_kernel_handle = OperationInformation->KernelHandle;
// report->report_code =
// REPORT_ILLEGAL_HANDLE_OPERATION;
// report->is_kernel_handle =
// OperationInformation->KernelHandle;
// report->process_id = process_creator_id;
// report->thread_id = ImpPsGetCurrentThreadId();
// report->access =
@ -704,10 +708,11 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
// HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
// if (!NT_SUCCESS(
// IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
// IrpQueueCompleteIrp(report,
// sizeof(OPEN_HANDLE_FAILURE_REPORT))))
//{
// DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
// goto end;
// DEBUG_ERROR("IrpQueueCompleteIrp failed with
// no status."); goto end;
// }
}
}
@ -720,13 +725,15 @@ end:
/* stolen from ReactOS xD */
VOID NTAPI
ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry)
ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable,
IN PHANDLE_TABLE_ENTRY HandleTableEntry)
{
INT64 old_value;
PAGED_CODE();
/* Set the lock bit and make sure it wasn't earlier */
old_value = InterlockedOr((PLONG)&HandleTableEntry->VolatileLowValue, 1);
old_value =
InterlockedOr((PLONG)&HandleTableEntry->VolatileLowValue, 1);
/* Unblock any waiters */
ImpExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
@ -761,117 +768,113 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
object_type = ImpObGetObjectType(object);
/* TODO: check for threads aswell */
if (!ImpRtlCompareUnicodeString(&object_type->Name, &OBJECT_TYPE_PROCESS, TRUE))
{
if (!ImpRtlCompareUnicodeString(
&object_type->Name, &OBJECT_TYPE_PROCESS, TRUE)) {
process = (PEPROCESS)object;
process_name = ImpPsGetProcessImageFileName(process);
SessionGetProcess(&protected_process);
protected_process_name = ImpPsGetProcessImageFileName(protected_process);
protected_process_name =
ImpPsGetProcessImageFileName(protected_process);
if (strcmp(process_name, protected_process_name))
goto end;
DEBUG_VERBOSE("Handle references our protected process with access mask: %lx",
(ACCESS_MASK)Entry->GrantedAccessBits);
DEBUG_VERBOSE(
"Handle references our protected process with access mask: %lx",
(ACCESS_MASK)Entry->GrantedAccessBits);
handle_access_mask = (ACCESS_MASK)Entry->GrantedAccessBits;
/* These permissions can be stripped from every process including CSRSS and LSASS */
if (handle_access_mask & PROCESS_CREATE_PROCESS)
{
/* These permissions can be stripped from every process
* including CSRSS and LSASS */
if (handle_access_mask & PROCESS_CREATE_PROCESS) {
Entry->GrantedAccessBits &= ~PROCESS_CREATE_PROCESS;
DEBUG_VERBOSE("Stripped PROCESS_CREATE_PROCESS");
}
if (handle_access_mask & PROCESS_CREATE_THREAD)
{
if (handle_access_mask & PROCESS_CREATE_THREAD) {
Entry->GrantedAccessBits &= ~PROCESS_CREATE_THREAD;
DEBUG_VERBOSE("Stripped PROCESS_CREATE_THREAD");
}
if (handle_access_mask & PROCESS_DUP_HANDLE)
{
if (handle_access_mask & PROCESS_DUP_HANDLE) {
Entry->GrantedAccessBits &= ~PROCESS_DUP_HANDLE;
DEBUG_VERBOSE("Stripped PROCESS_DUP_HANDLE");
}
if (handle_access_mask & PROCESS_QUERY_INFORMATION)
{
if (handle_access_mask & PROCESS_QUERY_INFORMATION) {
Entry->GrantedAccessBits &= ~PROCESS_QUERY_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_QUERY_INFORMATION");
}
if (handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION)
{
Entry->GrantedAccessBits &= ~PROCESS_QUERY_LIMITED_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_QUERY_LIMITED_INFORMATION");
if (handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION) {
Entry->GrantedAccessBits &=
~PROCESS_QUERY_LIMITED_INFORMATION;
DEBUG_VERBOSE(
"Stripped PROCESS_QUERY_LIMITED_INFORMATION");
}
if (handle_access_mask & PROCESS_VM_READ)
{
if (handle_access_mask & PROCESS_VM_READ) {
Entry->GrantedAccessBits &= ~PROCESS_VM_READ;
DEBUG_VERBOSE("Stripped PROCESS_VM_READ");
}
if (!strcmp(process_name, "csrss.exe") || !strcmp(process_name, "lsass.exe"))
{
if (!strcmp(process_name, "csrss.exe") ||
!strcmp(process_name, "lsass.exe")) {
DEBUG_VERBOSE(
"Required system process allowed, only stripping some permissions");
goto end;
}
/* Permissions beyond here can only be stripped from non critical processes */
if (handle_access_mask & PROCESS_SET_INFORMATION)
{
/* Permissions beyond here can only be stripped from non
* critical processes */
if (handle_access_mask & PROCESS_SET_INFORMATION) {
Entry->GrantedAccessBits &= ~PROCESS_SET_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_SET_INFORMATION");
}
if (handle_access_mask & PROCESS_SET_QUOTA)
{
if (handle_access_mask & PROCESS_SET_QUOTA) {
Entry->GrantedAccessBits &= ~PROCESS_SET_QUOTA;
DEBUG_VERBOSE("Stripped PROCESS_SET_QUOTA");
}
if (handle_access_mask & PROCESS_SUSPEND_RESUME)
{
if (handle_access_mask & PROCESS_SUSPEND_RESUME) {
Entry->GrantedAccessBits &= ~PROCESS_SUSPEND_RESUME;
DEBUG_VERBOSE("Stripped PROCESS_SUSPEND_RESUME ");
}
if (handle_access_mask & PROCESS_TERMINATE)
{
if (handle_access_mask & PROCESS_TERMINATE) {
Entry->GrantedAccessBits &= ~PROCESS_TERMINATE;
DEBUG_VERBOSE("Stripped PROCESS_TERMINATE");
}
if (handle_access_mask & PROCESS_VM_OPERATION)
{
if (handle_access_mask & PROCESS_VM_OPERATION) {
Entry->GrantedAccessBits &= ~PROCESS_VM_OPERATION;
DEBUG_VERBOSE("Stripped PROCESS_VM_OPERATION");
}
if (handle_access_mask & PROCESS_VM_WRITE)
{
if (handle_access_mask & PROCESS_VM_WRITE) {
Entry->GrantedAccessBits &= ~PROCESS_VM_WRITE;
DEBUG_VERBOSE("Stripped PROCESS_VM_WRITE");
}
POPEN_HANDLE_FAILURE_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(OPEN_HANDLE_FAILURE_REPORT), REPORT_POOL_TAG);
POPEN_HANDLE_FAILURE_REPORT report =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(OPEN_HANDLE_FAILURE_REPORT),
REPORT_POOL_TAG);
if (!report)
goto end;
/*
* Using the same report structure as the ObRegisterCallbacks report
* since both of these reports are closely related by the fact they are
* triggered by a process either opening a handle to our protected process
* or have a valid open handle to it. I also don't think its worth creating
* another queue specifically for open handle reports since they will be
* rare.
* Using the same report structure as the ObRegisterCallbacks
* report since both of these reports are closely related by the
* fact they are triggered by a process either opening a handle
* to our protected process or have a valid open handle to it. I
* also don't think its worth creating another queue
* specifically for open handle reports since they will be rare.
*/
report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
report->is_kernel_handle = 0;
@ -879,12 +882,14 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
report->thread_id = 0;
report->access = handle_access_mask;
RtlCopyMemory(
&report->process_name, process_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
RtlCopyMemory(&report->process_name,
process_name,
HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
if (!NT_SUCCESS(IrpQueueCompleteIrp(
report, sizeof(OPEN_HANDLE_FAILURE_REPORT)))) {
DEBUG_ERROR(
"IrpQueueCompleteIrp failed with no status.");
goto end;
}
}
@ -895,7 +900,8 @@ end:
}
NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOID Context)
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_In_opt_ PVOID Context)
{
/* Handles are stored in pageable memory */
PAGED_CODE();
@ -909,7 +915,8 @@ EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOI
return STATUS_SUCCESS;
PHANDLE_TABLE handle_table =
*(PHANDLE_TABLE*)((uintptr_t)ProcessListEntry->process + EPROCESS_HANDLE_TABLE_OFFSET);
*(PHANDLE_TABLE*)((uintptr_t)ProcessListEntry->process +
EPROCESS_HANDLE_TABLE_OFFSET);
if (!handle_table)
return STATUS_INVALID_ADDRESS;
@ -920,7 +927,8 @@ EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOI
#pragma warning(push)
#pragma warning(suppress : 6387)
BOOLEAN result = ImpExEnumHandleTable(handle_table, EnumHandleCallback, NULL, NULL);
BOOLEAN result =
ImpExEnumHandleTable(handle_table, EnumHandleCallback, NULL, NULL);
#pragma warning(pop)
@ -932,7 +940,8 @@ EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOI
ULONG value = 10;
VOID
TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PTIMER_OBJECT timer = (PTIMER_OBJECT)Context;
@ -943,15 +952,15 @@ TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Cont
DEBUG_VERBOSE("Integrity check timer callback invoked.");
if (!ValidateOurDriversDispatchRoutines())
{
if (!ValidateOurDriversDispatchRoutines()) {
DEBUG_VERBOSE("l");
}
status = ValidateOurDriverImage();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateOurDriverImage failed with status %x", status);
DEBUG_ERROR("ValidateOurDriverImage failed with status %x",
status);
end:
InterlockedExchange(&timer->state, FALSE);
@ -975,10 +984,13 @@ TimerObjectCallbackRoutine(_In_ PKDPC Dpc,
if (timer->state)
return;
/* we queue a work item because DPCs run at IRQL = DISPATCH_LEVEL and we need certain
* routines which cannot be run at an IRQL this high.*/
/* we queue a work item because DPCs run at IRQL = DISPATCH_LEVEL and we
* need certain routines which cannot be run at an IRQL this high.*/
InterlockedExchange(&timer->state, TRUE);
IoQueueWorkItem(timer->work_item, TimerObjectWorkItemRoutine, BackgroundWorkQueue, timer);
IoQueueWorkItem(timer->work_item,
TimerObjectWorkItemRoutine,
BackgroundWorkQueue,
timer);
}
NTSTATUS
@ -1005,7 +1017,8 @@ InitialiseTimerObject(_Out_ PTIMER_OBJECT Timer)
VOID
CleanupDriverTimerObjects(_Out_ PTIMER_OBJECT Timer)
{
/* this routine blocks until all queued DPCs on all processors have executed. */
/* this routine blocks until all queued DPCs on all processors have
* executed. */
KeFlushQueuedDpcs();
/* wait for our work item to complete */
@ -1026,9 +1039,9 @@ UnregisterProcessObCallbacks()
PACTIVE_SESSION config = GetActiveSession();
AcquireDriverConfigLock();
if (config->callback_configuration.registration_handle)
{
ImpObUnRegisterCallbacks(config->callback_configuration.registration_handle);
if (config->callback_configuration.registration_handle) {
ImpObUnRegisterCallbacks(
config->callback_configuration.registration_handle);
config->callback_configuration.registration_handle = NULL;
}
@ -1056,16 +1069,18 @@ RegisterProcessObCallbacks()
operation_registration.PreOperation = ObPreOpCallbackRoutine;
operation_registration.PostOperation = ObPostOpCallbackRoutine;
callback_registration.Version = OB_FLT_REGISTRATION_VERSION;
callback_registration.OperationRegistration = &operation_registration;
callback_registration.Version = OB_FLT_REGISTRATION_VERSION;
callback_registration.OperationRegistration = &operation_registration;
callback_registration.OperationRegistrationCount = 1;
callback_registration.RegistrationContext = NULL;
status = ImpObRegisterCallbacks(&callback_registration,
&config->callback_configuration.registration_handle);
status = ImpObRegisterCallbacks(
&callback_registration,
&config->callback_configuration.registration_handle);
if (!NT_SUCCESS(status))
DEBUG_ERROR("ObRegisterCallbacks failed with status %x", status);
DEBUG_ERROR("ObRegisterCallbacks failed with status %x",
status);
ReleaseDriverConfigLock();
return status;
@ -1074,5 +1089,6 @@ RegisterProcessObCallbacks()
VOID
InitialiseObCallbacksConfiguration(_Out_ PACTIVE_SESSION ProcessConfig)
{
ImpKeInitializeGuardedMutex(&ProcessConfig->callback_configuration.lock);
ImpKeInitializeGuardedMutex(
&ProcessConfig->callback_configuration.lock);
}

View file

@ -6,17 +6,16 @@
#include <wdf.h>
typedef void (*THREADLIST_CALLBACK_ROUTINE)(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
_In_opt_ PVOID Context);
typedef void (*THREADLIST_CALLBACK_ROUTINE)(
_In_ PTHREAD_LIST_ENTRY ThreadListEntry, _In_opt_ PVOID Context);
typedef void (*PROCESSLIST_CALLBACK_ROUTINE)(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_In_opt_ PVOID Context);
typedef void (*PROCESSLIST_CALLBACK_ROUTINE)(
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOID Context);
#define DRIVER_PATH_LENGTH 0x100
#define SHA_256_HASH_LENGTH 32
typedef struct _DRIVER_LIST_ENTRY
{
typedef struct _DRIVER_LIST_ENTRY {
SINGLE_LIST_ENTRY list;
PVOID ImageBase;
ULONG ImageSize;
@ -26,32 +25,36 @@ typedef struct _DRIVER_LIST_ENTRY
CHAR text_hash[SHA_256_HASH_LENGTH];
/*
* This LIST_ENTRY is to be used for modules where the hashing needs to be deferred.
* For example, when x86 modules can't be hashed on driver load.
* This LIST_ENTRY is to be used for modules where the hashing needs to
* be deferred. For example, when x86 modules can't be hashed on driver
* load.
*/
LIST_ENTRY deferred_entry;
} DRIVER_LIST_ENTRY, *PDRIVER_LIST_ENTRY;
typedef void (*DRIVERLIST_CALLBACK_ROUTINE)(_In_ PDRIVER_LIST_ENTRY DriverListEntry,
_In_opt_ PVOID Context);
typedef void (*DRIVERLIST_CALLBACK_ROUTINE)(
_In_ PDRIVER_LIST_ENTRY DriverListEntry, _In_opt_ PVOID Context);
NTSTATUS
InitialiseDriverList();
VOID NTAPI
ExUnlockHandleTableEntry(IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry);
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);
OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation);
NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOID Context);
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_In_opt_ PVOID Context);
NTSTATUS
InitialiseThreadList();
@ -60,30 +63,37 @@ 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();
VOID
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, _Inout_ PTHREAD_LIST_ENTRY* Entry);
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread,
_Inout_ PTHREAD_LIST_ENTRY* Entry);
VOID
FindProcessListEntryByProcess(_In_ PKPROCESS Process, _Inout_ PPROCESS_LIST_ENTRY* Entry);
FindProcessListEntryByProcess(_In_ PKPROCESS Process,
_Inout_ PPROCESS_LIST_ENTRY* Entry);
VOID
EnumerateThreadListWithCallbackRoutine(_In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context);
EnumerateThreadListWithCallbackRoutine(
_In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context);
VOID
EnumerateProcessListWithCallbackRoutine(_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context);
EnumerateProcessListWithCallbackRoutine(
_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context);
VOID
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Entry);
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase,
_Out_ PDRIVER_LIST_ENTRY* Entry);
VOID
CleanupProcessListOnDriverUnload();
@ -121,8 +131,8 @@ VOID
InitialiseObCallbacksConfiguration(_Out_ PACTIVE_SESSION ProcessConfig);
VOID
EnumerateDriverListWithCallbackRoutine(_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context);
EnumerateDriverListWithCallbackRoutine(
_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context);
VOID
DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry,

View file

@ -10,8 +10,8 @@
/*
* For numbers < 32, these are equivalent to 0ul < x.
*
* For an item to be printed, its bitwise AND'd with the set filter. If the result is non zero the
* log will be printed.
* For an item to be printed, its bitwise AND'd with the set filter. If the
* result is non zero the log will be printed.
*/
#define LOG_ERROR_LEVEL 1
#define LOG_WARNING_LEVEL 2
@ -20,9 +20,11 @@
#define DPFLTR_MASK 0x80000000
#define DEBUG_ERROR(fmt, ...) \
DbgPrintEx( \
DPFLTR_DEFAULT_ID, LOG_ERROR_LEVEL, "donna-ac : [ERROR] ::: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_ERROR(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
LOG_ERROR_LEVEL, \
"donna-ac : [ERROR] ::: " fmt "\n", \
##__VA_ARGS__)
#define DEBUG_WARNING(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
@ -30,9 +32,11 @@
"donna-ac : [WARNING] : " fmt "\n", \
##__VA_ARGS__)
#define DEBUG_INFO(fmt, ...) \
DbgPrintEx( \
DPFLTR_DEFAULT_ID, LOG_INFO_LEVEL, "donna-ac : [INFO] :::: " fmt "\n", ##__VA_ARGS__)
#define DEBUG_INFO(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
LOG_INFO_LEVEL, \
"donna-ac : [INFO] :::: " fmt "\n", \
##__VA_ARGS__)
#define DEBUG_VERBOSE(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
@ -46,12 +50,11 @@
#define MAX_MODULE_PATH 256
/*
* Interlocked intrinsics are only atomic with respect to other InterlockedXxx functions,
* so all reads and writes to the THREAD_LIST->active flag must be with Interlocked instrinsics
* to ensure atomicity.
* Interlocked intrinsics are only atomic with respect to other InterlockedXxx
* functions, so all reads and writes to the THREAD_LIST->active flag must be
* with Interlocked instrinsics to ensure atomicity.
*/
typedef struct _THREAD_LIST_HEAD
{
typedef struct _THREAD_LIST_HEAD {
SINGLE_LIST_ENTRY start;
volatile BOOLEAN active;
KGUARDED_MUTEX lock;
@ -59,8 +62,7 @@ typedef struct _THREAD_LIST_HEAD
} THREAD_LIST_HEAD, *PTHREAD_LIST_HEAD;
typedef struct _PROCESS_LIST_HEAD
{
typedef struct _PROCESS_LIST_HEAD {
SINGLE_LIST_ENTRY start;
volatile BOOLEAN active;
KGUARDED_MUTEX lock;
@ -68,8 +70,7 @@ typedef struct _PROCESS_LIST_HEAD
} PROCESS_LIST_HEAD, *PPROCESS_LIST_HEAD;
typedef struct _DRIVER_LIST_HEAD
{
typedef struct _DRIVER_LIST_HEAD {
SINGLE_LIST_ENTRY start;
volatile ULONG count;
volatile BOOLEAN active;
@ -82,8 +83,7 @@ typedef struct _DRIVER_LIST_HEAD
} DRIVER_LIST_HEAD, *PDRIVER_LIST_HEAD;
typedef struct _THREAD_LIST_ENTRY
{
typedef struct _THREAD_LIST_ENTRY {
SINGLE_LIST_ENTRY list;
PKTHREAD thread;
PKPROCESS owning_process;
@ -92,8 +92,7 @@ typedef struct _THREAD_LIST_ENTRY
} THREAD_LIST_ENTRY, *PTHREAD_LIST_ENTRY;
typedef struct _PROCESS_LIST_ENTRY
{
typedef struct _PROCESS_LIST_ENTRY {
SINGLE_LIST_ENTRY list;
PKPROCESS process;
PKPROCESS parent;
@ -102,13 +101,11 @@ typedef struct _PROCESS_LIST_ENTRY
/*
* ioctl_flag consists of the first 16 bits of the Function part of the CTL code
* cookie_value consists of a static 16 bit value generated by the user mode app on startup
* which is then passed to the driver and stored.
* cookie_value consists of a static 16 bit value generated by the user mode app
* on startup which is then passed to the driver and stored.
*/
typedef union _SECURITY_COOKIE
{
struct
{
typedef union _SECURITY_COOKIE {
struct {
UINT32 ioctl_flag : 16;
UINT32 cookie_value : 16;
} bits;
@ -117,8 +114,7 @@ typedef union _SECURITY_COOKIE
} SECURITY_COOKIE, *PSECURITY_COOKIE;
typedef struct _TIMER_OBJECT
{
typedef struct _TIMER_OBJECT {
/*
* state = 1: callback in progress
* state = 0: no callback in progress (i.e safe to free and unregister)
@ -131,16 +127,14 @@ typedef struct _TIMER_OBJECT
} TIMER_OBJECT, *PTIMER_OBJECT;
typedef enum _ENVIRONMENT_TYPE
{
typedef enum _ENVIRONMENT_TYPE {
NativeWindows = 0,
Vmware,
VirtualBox
} ENVIRONMENT_TYPE;
typedef enum _PROCESSOR_TYPE
{
typedef enum _PROCESSOR_TYPE {
Unknown = 0,
GenuineIntel,
AuthenticAmd
@ -161,8 +155,7 @@ typedef enum _PROCESSOR_TYPE
#define MAXIMUM_APC_CONTEXTS 10
typedef struct _SYSTEM_INFORMATION
{
typedef struct _SYSTEM_INFORMATION {
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
CHAR vendor[VENDOR_STRING_MAX_LENGTH];
@ -173,31 +166,27 @@ typedef struct _SYSTEM_INFORMATION
} SYSTEM_INFORMATION, *PSYSTEM_INFORMATION;
typedef struct _OB_CALLBACKS_CONFIG
{
typedef struct _OB_CALLBACKS_CONFIG {
PVOID registration_handle;
KGUARDED_MUTEX lock;
} OB_CALLBACKS_CONFIG, *POB_CALLBACKS_CONFIG;
typedef struct _DEFERRED_REPORT
{
typedef struct _DEFERRED_REPORT {
LIST_ENTRY list_entry;
PVOID buffer;
UINT32 buffer_size;
} DEFERRED_REPORT, *PDEFERRED_REPORT;
typedef struct _DEFERRED_REPORTS_LIST
{
typedef struct _DEFERRED_REPORTS_LIST {
LIST_ENTRY head;
UINT32 count;
KSPIN_LOCK lock;
} DEFERRED_REPORTS_LIST, *PDEFERRED_REPORTS_LIST;
typedef struct _IRP_QUEUE_HEAD
{
typedef struct _IRP_QUEUE_HEAD {
LIST_ENTRY queue;
volatile UINT32 count;
IO_CSQ csq;
@ -206,8 +195,7 @@ typedef struct _IRP_QUEUE_HEAD
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;
typedef struct _IRP_QUEUE_ENTRY
{
typedef struct _IRP_QUEUE_ENTRY {
SINGLE_LIST_ENTRY entry;
PIRP irp;
@ -220,8 +208,7 @@ typedef struct _IRP_QUEUE_ENTRY
#define AES_128_KEY_SIZE 16
typedef struct _ACTIVE_SESSION
{
typedef struct _ACTIVE_SESSION {
BOOLEAN is_session_active;
PVOID um_handle;
PVOID km_handle;
@ -231,8 +218,7 @@ typedef struct _ACTIVE_SESSION
UINT32 session_cookie;
CHAR session_aes_key[AES_128_KEY_SIZE];
struct SESSION_STATISTICS
{
struct SESSION_STATISTICS {
UINT32 irps_processed;
UINT32 report_count;
UINT32 heartbeat_count;
@ -363,8 +349,7 @@ typedef struct _ACTIVE_SESSION
#define PAGE_4KB_SHIFT 12
#define PAGE_4KB_OFFSET(x) (x & (~(MAXUINT64 << PAGE_4KB_SHIFT)))
typedef struct _KAFFINITY_EX
{
typedef struct _KAFFINITY_EX {
USHORT Count;
USHORT Size;
ULONG Reserved;
@ -372,16 +357,14 @@ typedef struct _KAFFINITY_EX
} KAFFINITY_EX, *PKAFFINITY_EX;
typedef struct _OBJECT_DIRECTORY_ENTRY
{
typedef struct _OBJECT_DIRECTORY_ENTRY {
struct _OBJECT_DIRECTORY_ENTRY* ChainLink;
PVOID Object;
ULONG HashValue;
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
typedef struct _OBJECT_DIRECTORY
{
typedef struct _OBJECT_DIRECTORY {
POBJECT_DIRECTORY_ENTRY HashBuckets[NUMBER_HASH_BUCKETS];
EX_PUSH_LOCK Lock;
struct _DEVICE_MAP* DeviceMap;
@ -391,8 +374,7 @@ typedef struct _OBJECT_DIRECTORY
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
typedef struct _DEVICE_MAP
{
typedef struct _DEVICE_MAP {
struct _OBJECT_DIRECTORY* DosDevicesDirectory;
struct _OBJECT_DIRECTORY* GlobalDosDevicesDirectory;
ULONG ReferenceCount;
@ -401,8 +383,7 @@ typedef struct _DEVICE_MAP
} DEVICE_MAP, *PDEVICE_MAP;
typedef struct _RTL_MODULE_EXTENDED_INFO
{
typedef struct _RTL_MODULE_EXTENDED_INFO {
PVOID ImageBase;
ULONG ImageSize;
USHORT FileNameOffset;
@ -433,8 +414,7 @@ Thread Information Block: (GS register)
...
*/
typedef struct _OBJECT_TYPE
{
typedef struct _OBJECT_TYPE {
LIST_ENTRY TypeList;
UNICODE_STRING Name;
PVOID DefaultObject;
@ -450,15 +430,13 @@ typedef struct _OBJECT_TYPE
} OBJECT_TYPE, *POBJECT_TYPE;
typedef struct _PEB_LDR_DATA
{
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY
{
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
@ -469,8 +447,7 @@ typedef struct _LDR_DATA_TABLE_ENTRY
PVOID Reserved5[3];
#pragma warning(push)
#pragma warning(disable : 4201) // we'll always use the Microsoft compiler
union
{
union {
ULONG CheckSum;
PVOID Reserved6;
} DUMMYUNIONNAME;
@ -478,8 +455,7 @@ typedef struct _LDR_DATA_TABLE_ENTRY
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB
{
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
@ -501,8 +477,7 @@ typedef struct _PEB
ULONG SessionId;
} PEB, *PPEB;
typedef struct _PEB32
{
typedef struct _PEB32 {
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
@ -523,8 +498,7 @@ typedef struct _PEB32
ULONG ApiSetMap;
} PEB32, *PPEB32;
typedef struct _PEB_LDR_DATA32
{
typedef struct _PEB_LDR_DATA32 {
ULONG Length;
UCHAR Initialized;
ULONG SsHandle;
@ -533,8 +507,7 @@ typedef struct _PEB_LDR_DATA32
LIST_ENTRY32 InInitializationOrderModuleList;
} PEB_LDR_DATA32, *PPEB_LDR_DATA32;
typedef struct _LDR_DATA_TABLE_ENTRY32
{
typedef struct _LDR_DATA_TABLE_ENTRY32 {
LIST_ENTRY32 InLoadOrderLinks;
LIST_ENTRY32 InMemoryOrderLinks;
LIST_ENTRY32 InInitializationOrderLinks;
@ -550,17 +523,14 @@ typedef struct _LDR_DATA_TABLE_ENTRY32
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
typedef struct _HANDLE_TABLE_ENTRY_INFO
{
typedef struct _HANDLE_TABLE_ENTRY_INFO {
ULONG AuditMask;
ULONG MaxRelativeAccessMask;
} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO;
typedef union _EXHANDLE
{
struct
{
typedef union _EXHANDLE {
struct {
int TagBits : 2;
int Index : 30;
} u;
@ -573,25 +543,27 @@ typedef union _EXHANDLE
#pragma pack(push, 1)
typedef struct _POOL_HEADER // Size=16
{
union
{
struct
{
unsigned long PreviousSize : 8; // Size=4 Offset=0 BitOffset=0 BitCount=8
unsigned long PoolIndex : 8; // Size=4 Offset=0 BitOffset=8 BitCount=8
unsigned long BlockSize : 8; // Size=4 Offset=0 BitOffset=16 BitCount=8
unsigned long PoolType : 8; // Size=4 Offset=0 BitOffset=24 BitCount=8
union {
struct {
unsigned long
PreviousSize : 8; // Size=4 Offset=0 BitOffset=0
// BitCount=8
unsigned long PoolIndex : 8; // Size=4 Offset=0
// BitOffset=8 BitCount=8
unsigned long BlockSize : 8; // Size=4 Offset=0
// BitOffset=16 BitCount=8
unsigned long PoolType : 8; // Size=4 Offset=0
// BitOffset=24 BitCount=8
};
unsigned long Ulong1; // Size=4 Offset=0
};
unsigned long PoolTag; // Size=4 Offset=4
union
{
union {
struct _EPROCESS* ProcessBilled; // Size=8 Offset=8
struct
{
unsigned short AllocatorBackTraceIndex; // Size=2 Offset=8
unsigned short PoolTagHash; // Size=2 Offset=10
struct {
unsigned short
AllocatorBackTraceIndex; // Size=2 Offset=8
unsigned short PoolTagHash; // Size=2 Offset=10
};
};
} POOL_HEADER, *PPOOL_HEADER;
@ -599,37 +571,40 @@ typedef struct _POOL_HEADER // Size=16
typedef struct _HANDLE_TABLE_ENTRY // Size=16
{
union
{
ULONG_PTR VolatileLowValue; // Size=8 Offset=0
ULONG_PTR LowValue; // Size=8 Offset=0
struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; // Size=8 Offset=0
struct
{
ULONG_PTR Unlocked : 1; // Size=8 Offset=0 BitOffset=0 BitCount=1
ULONG_PTR RefCnt : 16; // Size=8 Offset=0 BitOffset=1 BitCount=16
ULONG_PTR Attributes : 3; // Size=8 Offset=0 BitOffset=17 BitCount=3
union {
ULONG_PTR VolatileLowValue; // Size=8 Offset=0
ULONG_PTR LowValue; // Size=8 Offset=0
struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; // Size=8 Offset=0
struct {
ULONG_PTR Unlocked : 1; // Size=8 Offset=0 BitOffset=0
// BitCount=1
ULONG_PTR RefCnt : 16; // Size=8 Offset=0 BitOffset=1
// BitCount=16
ULONG_PTR Attributes : 3; // Size=8 Offset=0
// BitOffset=17 BitCount=3
ULONG_PTR
ObjectPointerBits : 44; // Size=8 Offset=0 BitOffset=20 BitCount=44
ObjectPointerBits : 44; // Size=8 Offset=0 BitOffset=20
// BitCount=44
};
};
union
{
ULONG_PTR HighValue; // Size=8 Offset=8
struct _HANDLE_TABLE_ENTRY* NextFreeHandleEntry; // Size=8 Offset=8
union _EXHANDLE LeafHandleValue; // Size=8 Offset=8
struct
{
ULONG GrantedAccessBits : 25; // Size=4 Offset=8 BitOffset=0 BitCount=25
ULONG NoRightsUpgrade : 1; // Size=4 Offset=8 BitOffset=25 BitCount=1
ULONG Spare : 6; // Size=4 Offset=8 BitOffset=26 BitCount=6
union {
ULONG_PTR HighValue; // Size=8 Offset=8
struct _HANDLE_TABLE_ENTRY*
NextFreeHandleEntry; // Size=8 Offset=8
union _EXHANDLE LeafHandleValue; // Size=8 Offset=8
struct {
ULONG GrantedAccessBits : 25; // Size=4 Offset=8
// BitOffset=0 BitCount=25
ULONG NoRightsUpgrade : 1; // Size=4 Offset=8
// BitOffset=25 BitCount=1
ULONG Spare : 6; // Size=4 Offset=8 BitOffset=26
// BitCount=6
};
};
ULONG TypeInfo; // Size=4 Offset=12
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
typedef struct _HANDLE_TABLE_FREE_LIST
{
typedef struct _HANDLE_TABLE_FREE_LIST {
EX_PUSH_LOCK FreeListLock;
PHANDLE_TABLE_ENTRY FirstFreeHandleEntry;
PHANDLE_TABLE_ENTRY LastFreeHandleEntry;
@ -637,8 +612,7 @@ typedef struct _HANDLE_TABLE_FREE_LIST
ULONG HighWaterMark;
} HANDLE_TABLE_FREE_LIST, *PHANDLE_TABLE_FREE_LIST;
typedef struct _HANDLE_TRACE_DB_ENTRY
{
typedef struct _HANDLE_TRACE_DB_ENTRY {
CLIENT_ID ClientId;
PVOID Handle;
ULONG Type;
@ -646,8 +620,7 @@ typedef struct _HANDLE_TRACE_DB_ENTRY
} HANDLE_TRACE_DB_ENTRY, *PHANDLE_TRACE_DB_ENTRY;
typedef struct _HANDLE_TRACE_DEBUG_INFO
{
typedef struct _HANDLE_TRACE_DEBUG_INFO {
LONG RefCount;
ULONG TableSize;
ULONG BitMaskFlags;
@ -657,19 +630,16 @@ typedef struct _HANDLE_TRACE_DEBUG_INFO
} HANDLE_TRACE_DEBUG_INFO, *PHANDLE_TRACE_DEBUG_INFO;
typedef struct _HANDLE_TABLE
{
typedef struct _HANDLE_TABLE {
ULONG NextHandleNeedingPool;
LONG ExtraInfoPages;
ULONGLONG TableCode;
PEPROCESS QuotaProcess;
LIST_ENTRY HandleTableList;
ULONG UniqueProcessId;
union
{
union {
ULONG Flags;
struct
{
struct {
UCHAR StrictFIFO : 1;
UCHAR EnableHandleExceptions : 1;
UCHAR Rundown : 1;
@ -679,8 +649,7 @@ typedef struct _HANDLE_TABLE
};
EX_PUSH_LOCK HandleContentionEvent;
EX_PUSH_LOCK HandleTableLock;
union
{
union {
HANDLE_TABLE_FREE_LIST FreeLists[1];
UCHAR ActualEntry[32];
};
@ -689,12 +658,12 @@ typedef struct _HANDLE_TABLE
} HANDLE_TABLE, *PHANDLE_TABLE;
typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter);
typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(IN PHANDLE_TABLE_ENTRY
HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter);
typedef struct _OBJECT_CREATE_INFORMATION
{
typedef struct _OBJECT_CREATE_INFORMATION {
ULONG Attributes;
PVOID RootDirectory;
CHAR ProbeMode;
@ -707,31 +676,25 @@ typedef struct _OBJECT_CREATE_INFORMATION
} OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;
typedef struct _OBJECT_HEADER
{
typedef struct _OBJECT_HEADER {
LONGLONG PointerCount;
union
{
union {
LONGLONG HandleCount;
PVOID NextToFree;
};
EX_PUSH_LOCK Lock;
UCHAR TypeIndex;
union
{
union {
UCHAR TraceFlags;
struct
{
struct {
UCHAR DbgRefTrace : 1;
UCHAR DbgTracePermanent : 1;
};
};
UCHAR InfoMask;
union
{
union {
UCHAR Flags;
struct
{
struct {
UCHAR NewObject : 1;
UCHAR KernelObject : 1;
UCHAR KernelOnlyAccess : 1;
@ -743,8 +706,7 @@ typedef struct _OBJECT_HEADER
};
};
ULONG Reserved;
union
{
union {
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
PVOID QuotaBlockCharged;
};
@ -758,11 +720,9 @@ typedef struct _OBJECT_HEADER
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER
{
typedef struct _IMAGE_SECTION_HEADER {
unsigned char Name[IMAGE_SIZEOF_SHORT_NAME];
union
{
union {
unsigned long PhysicalAddress;
unsigned long VirtualSize;
} Misc;
@ -776,8 +736,7 @@ typedef struct _IMAGE_SECTION_HEADER
unsigned long Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _IMAGE_FILE_HEADER
{
typedef struct _IMAGE_FILE_HEADER {
unsigned short Machine;
unsigned short NumberOfSections;
unsigned long TimeDateStamp;
@ -787,16 +746,14 @@ typedef struct _IMAGE_FILE_HEADER
unsigned short Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY
{
typedef struct _IMAGE_DATA_DIRECTORY {
unsigned long VirtualAddress;
unsigned long Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER64
{
typedef struct _IMAGE_OPTIONAL_HEADER64 {
unsigned short Magic;
unsigned char MajorLinkerVersion;
unsigned char MinorLinkerVersion;
@ -832,8 +789,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER64
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef struct _IMAGE_OPTIONAL_HEADER32
{
typedef struct _IMAGE_OPTIONAL_HEADER32 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
@ -867,8 +823,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER32
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_DOS_HEADER
{ // DOS .EXE header
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
unsigned short e_magic; // Magic number
unsigned short e_cblp; // Bytes on last page of file
unsigned short e_cp; // Pages in file
@ -890,8 +845,7 @@ typedef struct _IMAGE_DOS_HEADER
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _KLDR_DATA_TABLE_ENTRY
{
typedef struct _KLDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
PVOID ExceptionTable;
ULONG ExceptionTableSize;
@ -913,8 +867,7 @@ typedef struct _KLDR_DATA_TABLE_ENTRY
PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
typedef struct _IMAGE_EXPORT_DIRECTORY
{
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
@ -928,57 +881,53 @@ typedef struct _IMAGE_EXPORT_DIRECTORY
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
typedef struct _LOCAL_NT_HEADER
{
typedef struct _LOCAL_NT_HEADER {
unsigned long Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} LOCAL_NT_HEADER, *PLOCAL_NT_HEADER;
#define IMAGE_FIRST_SECTION(ntheader) \
((PIMAGE_SECTION_HEADER)((ULONG_PTR)(ntheader) + \
FIELD_OFFSET(LOCAL_NT_HEADER, OptionalHeader) + \
((ntheader))->FileHeader.SizeOfOptionalHeader))
#define IMAGE_FIRST_SECTION(ntheader) \
((PIMAGE_SECTION_HEADER)((ULONG_PTR)(ntheader) + \
FIELD_OFFSET(LOCAL_NT_HEADER, \
OptionalHeader) + \
((ntheader)) \
->FileHeader.SizeOfOptionalHeader))
/* creds: https://www.unknowncheats.me/forum/2602838-post2.html */
typedef struct _DBGKD_DEBUG_DATA_HEADER64
{
typedef struct _DBGKD_DEBUG_DATA_HEADER64 {
LIST_ENTRY64 List;
ULONG OwnerTag;
ULONG Size;
} DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64;
typedef NTSTATUS(__stdcall* ZwQuerySystemInformation)(_In_ UINT32 SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength);
typedef NTSTATUS(__stdcall* ZwQuerySystemInformation)(
_In_ UINT32 SystemInformationClass,
_Inout_ PVOID SystemInformation,
_In_ ULONG SystemInformationLength,
_Out_opt_ PULONG ReturnLength);
#define SYSTEM_BIGPOOL_INFORMATION_ID 0x42
typedef struct _SYSTEM_BIGPOOL_ENTRY
{
union
{
typedef struct _SYSTEM_BIGPOOL_ENTRY {
union {
PVOID VirtualAddress;
ULONG_PTR NonPaged : 1;
};
SIZE_T SizeInBytes;
union
{
union {
UCHAR Tag[4];
ULONG TagUlong;
};
} SYSTEM_BIGPOOL_ENTRY, *PSYSTEM_BIGPOOL_ENTRY;
typedef struct _SYSTEM_BIGPOOL_INFORMATION
{
typedef struct _SYSTEM_BIGPOOL_INFORMATION {
ULONG Count;
_Field_size_(Count) SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];
} SYSTEM_BIGPOOL_INFORMATION, *PSYSTEM_BIGPOOL_INFORMATION;
typedef struct _KDDEBUGGER_DATA64
{
typedef struct _KDDEBUGGER_DATA64 {
DBGKD_DEBUG_DATA_HEADER64 Header;
ULONG64 KernBase;
ULONG64 BreakpointWithStatus;
@ -1111,8 +1060,7 @@ typedef struct _KDDEBUGGER_DATA64
ULONG64 IopTriageDumpDataBlocks;
} KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64;
typedef struct _KDDEBUGGER_DATA_ADDITION64
{
typedef struct _KDDEBUGGER_DATA_ADDITION64 {
ULONG64 VfCrashDataBlock;
ULONG64 MmBadPagesDetected;
ULONG64 MmZeroedPageSingleBitErrorsDetected;
@ -1139,8 +1087,7 @@ typedef struct _KDDEBUGGER_DATA_ADDITION64
ULONG RetpolineStubSize;
} KDDEBUGGER_DATA_ADDITION64, *PKDDEBUGGER_DATA_ADDITION64;
typedef struct _DUMP_HEADER
{
typedef struct _DUMP_HEADER {
ULONG Signature;
ULONG ValidDump;
ULONG MajorVersion;
@ -1160,10 +1107,8 @@ typedef struct _DUMP_HEADER
struct _KDDEBUGGER_DATA64* KdDebuggerDataBlock;
} DUMP_HEADER, *PDUMP_HEADER;
typedef union _VIRTUAL_MEMORY_ADDRESS
{
struct
{
typedef union _VIRTUAL_MEMORY_ADDRESS {
struct {
UINT64 PageIndex : 12; /* 0:11 */
UINT64 PtIndex : 9; /* 12:20 */
UINT64 PdIndex : 9; /* 21:29 */
@ -1177,10 +1122,8 @@ typedef union _VIRTUAL_MEMORY_ADDRESS
} VIRTUAL_ADDRESS, *PVIRTUAL_ADDRESS;
typedef union _PML4_ENTRY
{
struct
{
typedef union _PML4_ENTRY {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1197,10 +1140,8 @@ typedef union _PML4_ENTRY
UINT64 BitAddress;
} PML4E;
typedef union _PDPT_ENTRY
{
struct
{
typedef union _PDPT_ENTRY {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1217,10 +1158,8 @@ typedef union _PDPT_ENTRY
UINT64 BitAddress;
} PDPTE;
typedef union _PD_ENTRY
{
struct
{
typedef union _PD_ENTRY {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1238,10 +1177,8 @@ typedef union _PD_ENTRY
UINT64 BitAddress;
} PDE;
typedef union _PT_ENTRY
{
struct
{
typedef union _PT_ENTRY {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1261,10 +1198,8 @@ typedef union _PT_ENTRY
UINT64 BitAddress;
} PTE;
typedef union _PDPT_ENTRY_LARGE
{
struct
{
typedef union _PDPT_ENTRY_LARGE {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1285,10 +1220,8 @@ typedef union _PDPT_ENTRY_LARGE
UINT64 BitAddress;
} PDPTE_LARGE;
typedef union _PD_ENTRY_LARGE
{
struct
{
typedef union _PD_ENTRY_LARGE {
struct {
UINT64 Present : 1; /* 0 */
UINT64 ReadWrite : 1; /* 1 */
UINT64 UserSupervisor : 1; /* 2 */
@ -1334,8 +1267,7 @@ typedef union _PD_ENTRY_LARGE
// };
// } KAPC_STATE, * PKAPC_STATE, * PRKAPC_STATE;
typedef struct _RAW_SMBIOS_DATA
{
typedef struct _RAW_SMBIOS_DATA {
BYTE Used20CallingMethod;
BYTE SMBIOSMajorVersion;
BYTE SMBIOSMinorVersion;
@ -1344,8 +1276,7 @@ typedef struct _RAW_SMBIOS_DATA
BYTE SMBIOSTableData[1];
} RAW_SMBIOS_DATA, *PRAW_SMBIOS_DATA;
typedef struct _SMBIOS_TABLE_HEADER
{
typedef struct _SMBIOS_TABLE_HEADER {
UCHAR Type;
UCHAR Length;
USHORT Handle;
@ -1353,8 +1284,7 @@ typedef struct _SMBIOS_TABLE_HEADER
} SMBIOS_TABLE_HEADER, *PSMBIOS_TABLE_HEADER;
typedef struct _RAW_SMBIOS_TABLE_01
{
typedef struct _RAW_SMBIOS_TABLE_01 {
UCHAR Type;
UCHAR Length;
USHORT Handle;
@ -1369,8 +1299,7 @@ typedef struct _RAW_SMBIOS_TABLE_01
} RAW_SMBIOS_TABLE_01, *PRAW_SMBIOS_TABLE_01;
typedef struct _RAW_SMBIOS_TABLE_02
{
typedef struct _RAW_SMBIOS_TABLE_02 {
UCHAR Type;
UCHAR Length;
USHORT Handle;
@ -1388,21 +1317,18 @@ typedef struct _RAW_SMBIOS_TABLE_02
} RAW_SMBIOS_TABLE_02, *PRAW_SMBIOS_TABLE_02;
typedef struct _RTL_RELATIVE_NAME
{
typedef struct _RTL_RELATIVE_NAME {
UNICODE_STRING RelativeName;
HANDLE ContainingDirectory;
void* CurDirRef;
} RTL_RELATIVE_NAME, *PRTL_RELATIVE_NAME;
typedef struct _STORAGE_DESCRIPTOR_HEADER
{
typedef struct _STORAGE_DESCRIPTOR_HEADER {
ULONG Version;
ULONG Size;
} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER;
typedef enum _STORAGE_BUS_TYPE
{
typedef enum _STORAGE_BUS_TYPE {
BusTypeUnknown = 0x00,
BusTypeScsi,
BusTypeAtapi,
@ -1416,11 +1342,10 @@ typedef enum _STORAGE_BUS_TYPE
} STORAGE_BUS_TYPE,
*PSTORAGE_BUS_TYPE;
typedef enum _STORAGE_SET_TYPE
{
typedef enum _STORAGE_SET_TYPE {
PropertyStandardSet = 0, // Sets the descriptor
PropertyExistsSet, // Used to test whether the descriptor is supported
PropertySetMaxDefined // use to validate the value
PropertyExistsSet, // Used to test whether the descriptor is supported
PropertySetMaxDefined // use to validate the value
} STORAGE_SET_TYPE,
*PSTORAGE_SET_TYPE;
@ -1428,17 +1353,16 @@ typedef enum _STORAGE_SET_TYPE
// define some initial property id's
//
typedef enum _STORAGE_QUERY_TYPE
{
typedef enum _STORAGE_QUERY_TYPE {
PropertyStandardQuery = 0, // Retrieves the descriptor
PropertyExistsQuery, // Used to test whether the descriptor is supported
PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor
PropertyQueryMaxDefined // use to validate the value
PropertyExistsQuery, // Used to test whether the descriptor is supported
PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the
// descriptor
PropertyQueryMaxDefined // use to validate the value
} STORAGE_QUERY_TYPE,
*PSTORAGE_QUERY_TYPE;
typedef enum _STORAGE_PROPERTY_ID
{
typedef enum _STORAGE_PROPERTY_ID {
StorageDeviceProperty = 0,
StorageAdapterProperty,
StorageDeviceIdProperty,
@ -1478,15 +1402,13 @@ typedef enum _STORAGE_PROPERTY_ID
} STORAGE_PROPERTY_ID,
*PSTORAGE_PROPERTY_ID;
typedef struct _STORAGE_PROPERTY_QUERY
{
typedef struct _STORAGE_PROPERTY_QUERY {
STORAGE_PROPERTY_ID PropertyId;
STORAGE_QUERY_TYPE QueryType;
UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
typedef struct _STORAGE_DEVICE_DESCRIPTOR
{
typedef struct _STORAGE_DEVICE_DESCRIPTOR {
ULONG Version;
ULONG Size;
UCHAR DeviceType;
@ -1518,7 +1440,8 @@ typedef struct _EX_PUSH_LOCK_WAIT_BLOCK* PEX_PUSH_LOCK_WAIT_BLOCK;
NTKERNELAPI
VOID FASTCALL
ExfUnblockPushLock(_Inout_ PEX_PUSH_LOCK PushLock, _Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock);
ExfUnblockPushLock(_Inout_ PEX_PUSH_LOCK PushLock,
_Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock);
LPCSTR
NTSYSAPI
@ -1538,7 +1461,9 @@ VOID
HalSendNMI(PKAFFINITY_EX affinity);
NTSTATUS
RtlQueryModuleInformation(ULONG* InformationLength, ULONG SizePerModule, PVOID InformationBuffer);
RtlQueryModuleInformation(ULONG* InformationLength,
ULONG SizePerModule,
PVOID InformationBuffer);
NTSTATUS
NTAPI
@ -1586,11 +1511,10 @@ VOID NTAPI
_Inout_ _Deref_pre_maybenull_ PKNORMAL_ROUTINE* NormalRoutine,
_Inout_ _Deref_pre_maybenull_ PVOID* NormalContext,
_Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument1,
_Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2);
_Inout_ _Deref_pre_maybenull_ PVOID* SystemArgument2);
typedef KKERNEL_ROUTINE* PKKERNEL_ROUTINE;
typedef enum _KAPC_ENVIRONMENT
{
typedef enum _KAPC_ENVIRONMENT {
OriginalApcEnvironment,
AttachedApcEnvironment,
CurrentApcEnvironment,
@ -1661,8 +1585,7 @@ C_ASSERT(FIELD_OFFSET(DUMP_HEADER, KdDebuggerDataBlock) == 0x80);
#define TSS_IST_OFFSET 0x01c
#define WINDOWS_USERMODE_MAX_ADDRESS 0x00007FFFFFFFFFFF
typedef struct _MACHINE_FRAME
{
typedef struct _MACHINE_FRAME {
UINT64 rip;
UINT64 cs;
UINT64 eflags;

View file

@ -24,21 +24,26 @@ CryptEncryptImportsArray(_In_ PUINT64 Array, _In_ UINT32 Entries)
UINT32 block_count = Entries / block_size;
/*
* Here we break down the import array into blocks of 32 bytes. Each block is loaded into an
* SSE register, xored with the key, and then copied back into the array.
* Here we break down the import array into blocks of 32 bytes. Each
* block is loaded into an SSE register, xored with the key, and then
* copied back into the array.
*/
for (UINT32 block_index = 0; block_index < block_count; block_index++)
{
for (UINT32 block_index = 0; block_index < block_count; block_index++) {
__m256i current_block = {0};
__m256i load_block = {0};
__m256i xored_block = {0};
RtlCopyMemory(&current_block, &Array[block_index * block_size], sizeof(__m256i));
RtlCopyMemory(&current_block,
&Array[block_index * block_size],
sizeof(__m256i));
load_block = _mm256_loadu_si256(&current_block);
xored_block = _mm256_xor_si256(load_block, CryptGenerateSseXorKey());
load_block = _mm256_loadu_si256(&current_block);
xored_block =
_mm256_xor_si256(load_block, CryptGenerateSseXorKey());
RtlCopyMemory(&Array[block_index * block_size], &xored_block, sizeof(__m256i));
RtlCopyMemory(&Array[block_index * block_size],
&xored_block,
sizeof(__m256i));
}
}
@ -50,7 +55,8 @@ CryptDecryptImportBlock(_In_ PUINT64 Array, _In_ UINT32 BlockIndex)
__m256i load_block = {0};
UINT32 block_size = sizeof(__m256i) / sizeof(UINT64);
RtlCopyMemory(&load_block, &Array[BlockIndex * block_size], sizeof(__m256i));
RtlCopyMemory(
&load_block, &Array[BlockIndex * block_size], sizeof(__m256i));
return _mm256_xor_si256(load_block, CryptGenerateSseXorKey());
}
@ -66,22 +72,19 @@ CryptFindContainingBlockForArrayIndex(_In_ UINT32 EntryIndex,
UINT32 containing_block = EntryIndex;
UINT32 block_index = 0;
if (EntryIndex < BlockSize)
{
if (EntryIndex < BlockSize) {
*ContainingBlockIndex = 0;
*BlockSubIndex = EntryIndex;
return;
}
if (EntryIndex == BlockSize)
{
if (EntryIndex == BlockSize) {
*ContainingBlockIndex = 1;
*BlockSubIndex = 0;
return;
}
while (containing_block % BlockSize != 0)
{
while (containing_block % BlockSize != 0) {
containing_block--;
block_index++;
}
@ -91,7 +94,9 @@ CryptFindContainingBlockForArrayIndex(_In_ UINT32 EntryIndex,
}
UINT64
CryptDecryptImportsArrayEntry(_In_ PUINT64 Array, _In_ UINT32 Entries, _In_ UINT32 EntryIndex)
CryptDecryptImportsArrayEntry(_In_ PUINT64 Array,
_In_ UINT32 Entries,
_In_ UINT32 EntryIndex)
{
__m256i original_block = {0};
__m128i original_half = {0};
@ -105,8 +110,7 @@ CryptDecryptImportsArrayEntry(_In_ PUINT64 Array, _In_ UINT32 Entries, _In_ UINT
original_block = CryptDecryptImportBlock(Array, containing_block_index);
if (block_sub_index < 2)
{
if (block_sub_index < 2) {
original_half = _mm256_extracti128_si256(original_block, 0);
if (block_sub_index < 1)
@ -114,8 +118,7 @@ CryptDecryptImportsArrayEntry(_In_ PUINT64 Array, _In_ UINT32 Entries, _In_ UINT
else
pointer = _mm_extract_epi64(original_half, 1);
}
else
{
else {
original_half = _mm256_extracti128_si256(original_block, 1);
if (block_sub_index == 2)
@ -128,16 +131,16 @@ CryptDecryptImportsArrayEntry(_In_ PUINT64 Array, _In_ UINT32 Entries, _In_ UINT
}
/*
* simple for now.. just to get it working
*/
* simple for now.. just to get it working
*/
VOID
CryptDecryptBufferWithCookie(_In_ PVOID Buffer, _In_ UINT32 BufferSize, _In_ UINT32 Cookie)
CryptDecryptBufferWithCookie(_In_ PVOID Buffer,
_In_ UINT32 BufferSize,
_In_ UINT32 Cookie)
{
PCHAR buffer = (PCHAR)Buffer;
for (UINT32 index = 0; index < BufferSize; index++)
{
for (UINT32 index = 0; index < BufferSize; index++) {
buffer[index] ^= Cookie;
}
}

View file

@ -21,7 +21,8 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject);
_Function_class_(DRIVER_INITIALIZE) _IRQL_requires_same_
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath);
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath);
STATIC
NTSTATUS
@ -54,7 +55,8 @@ DrvLoadEnableNotifyRoutines();
STATIC
NTSTATUS
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath);
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath);
#ifdef ALLOC_PRAGMA
# pragma alloc_text(INIT, DriverEntry)
@ -73,8 +75,7 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
# pragma alloc_text(PAGE, DrvLoadInitialiseDriverConfig)
#endif
typedef struct _DRIVER_CONFIG
{
typedef struct _DRIVER_CONFIG {
volatile LONG nmi_status;
UNICODE_STRING unicode_driver_name;
ANSI_STRING ansi_driver_name;
@ -104,10 +105,11 @@ UNICODE_STRING g_DeviceName = RTL_CONSTANT_STRING(L"\\Device\\DonnaAC");
UNICODE_STRING g_DeviceSymbolicLink = RTL_CONSTANT_STRING(L"\\??\\DonnaAC");
/*
* Rather then getting the driver state from the device object passed to our IOCTL handlers, store a
* pointer to the device extension here and abstract it with getters which can be accessed globally.
* The reason for this is because there isnt a way for us to pass a context structure to some of
* notify routines so I think it's better to do it this way.
* Rather then getting the driver state from the device object passed to our
* IOCTL handlers, store a pointer to the device extension here and abstract it
* with getters which can be accessed globally. The reason for this is because
* there isnt a way for us to pass a context structure to some of notify
* routines so I think it's better to do it this way.
*
* Note that the device extension pointer should be encrypted
*/
@ -130,9 +132,12 @@ UnsetNmiInProgressFlag()
BOOLEAN
IsNmiInProgress()
{
/* if the initial value is true, we dont own the lock hence return false */
return InterlockedCompareExchange(&g_DriverConfig->nmi_status, TRUE, FALSE) == 0 ? FALSE
: TRUE;
/* if the initial value is true, we dont own the lock hence return false
*/
return InterlockedCompareExchange(
&g_DriverConfig->nmi_status, TRUE, FALSE) == 0
? FALSE
: TRUE;
}
PSHARED_MAPPING
@ -263,8 +268,8 @@ GetProcessList()
}
/*
* The question is, What happens if we attempt to register our callbacks after we
* unregister them but before we free the pool? Hm.. No Good.
* The question is, What happens if we attempt to register our callbacks after
* we unregister them but before we free the pool? Hm.. No Good.
*
* Okay to solve this well acquire the driver lock aswell, we could also just
* store the structure in the .data section but i ceebs atm.
@ -286,10 +291,12 @@ DrvUnloadFreeConfigStrings()
PAGED_CODE();
if (g_DriverConfig->unicode_driver_name.Buffer)
ImpExFreePoolWithTag(g_DriverConfig->unicode_driver_name.Buffer, POOL_TAG_STRINGS);
ImpExFreePoolWithTag(g_DriverConfig->unicode_driver_name.Buffer,
POOL_TAG_STRINGS);
if (g_DriverConfig->driver_path.Buffer)
ImpExFreePoolWithTag(g_DriverConfig->driver_path.Buffer, POOL_TAG_STRINGS);
ImpExFreePoolWithTag(g_DriverConfig->driver_path.Buffer,
POOL_TAG_STRINGS);
if (g_DriverConfig->ansi_driver_name.Buffer)
ImpRtlFreeAnsiString(&g_DriverConfig->ansi_driver_name);
@ -352,9 +359,10 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
InterlockedExchange(&g_DriverConfig->unload_in_progress, TRUE);
/*
* This blocks the thread dispatching the unload routine, which I don't think is ideal.
* This is the issue with using APCs, we have very little safe control over when they
* complete and thus when we can free them.. For now, thisl do.
* This blocks the thread dispatching the unload routine, which I don't
* think is ideal. This is the issue with using APCs, we have very
* little safe control over when they complete and thus when we can free
* them.. For now, thisl do.
*/
while (DrvUnloadFreeAllApcContextStructures() == FALSE)
YieldProcessor();
@ -390,26 +398,29 @@ DrvLoadEnableNotifyRoutines()
status = PsSetLoadImageNotifyRoutine(ImageLoadNotifyRoutineCallback);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsSetLoadImageNotifyRoutine failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("PsSetLoadImageNotifyRoutine failed with status %x",
status);
return status;
}
status = ImpPsSetCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsSetCreateThreadNotifyRoutine failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"PsSetCreateThreadNotifyRoutine failed with status %x",
status);
PsRemoveLoadImageNotifyRoutine(ImageLoadNotifyRoutineCallback);
return status;
}
status = ImpPsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine, FALSE);
status = ImpPsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine,
FALSE);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsSetCreateProcessNotifyRoutine failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"PsSetCreateProcessNotifyRoutine failed with status %x",
status);
ImpPsRemoveCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine);
PsRemoveLoadImageNotifyRoutine(ImageLoadNotifyRoutineCallback);
return status;
@ -429,20 +440,20 @@ DrvLoadSetupDriverLists()
status = InitialiseDriverList();
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
UnregisterProcessCreateNotifyRoutine();
UnregisterThreadCreateNotifyRoutine();
UnregisterImageLoadNotifyRoutine();
DEBUG_ERROR("InitialiseDriverList failed with status %x", status);
DEBUG_ERROR("InitialiseDriverList failed with status %x",
status);
return status;
}
status = InitialiseThreadList();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InitialiseThreadList failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseThreadList failed with status %x",
status);
UnregisterProcessCreateNotifyRoutine();
UnregisterThreadCreateNotifyRoutine();
UnregisterImageLoadNotifyRoutine();
@ -452,9 +463,9 @@ DrvLoadSetupDriverLists()
status = InitialiseProcessList();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InitialiseProcessList failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseProcessList failed with status %x",
status);
UnregisterProcessCreateNotifyRoutine();
UnregisterThreadCreateNotifyRoutine();
UnregisterImageLoadNotifyRoutine();
@ -489,9 +500,10 @@ RegistryPathQueryCallbackRoutine(IN PWSTR ValueName,
ImpRtlInitUnicodeString(&value_name, ValueName);
if (ImpRtlCompareUnicodeString(&value_name, &image_path, FALSE) == FALSE)
{
temp_buffer = ImpExAllocatePool2(POOL_FLAG_PAGED, ValueLength, POOL_TAG_STRINGS);
if (ImpRtlCompareUnicodeString(&value_name, &image_path, FALSE) ==
FALSE) {
temp_buffer = ImpExAllocatePool2(
POOL_FLAG_PAGED, ValueLength, POOL_TAG_STRINGS);
if (!temp_buffer)
return STATUS_MEMORY_NOT_ALLOCATED;
@ -503,26 +515,28 @@ RegistryPathQueryCallbackRoutine(IN PWSTR ValueName,
g_DriverConfig->driver_path.MaximumLength = ValueLength;
}
if (ImpRtlCompareUnicodeString(&value_name, &display_name, FALSE) == FALSE)
{
temp_buffer =
ImpExAllocatePool2(POOL_FLAG_PAGED, ValueLength + 20, POOL_TAG_STRINGS);
if (ImpRtlCompareUnicodeString(&value_name, &display_name, FALSE) ==
FALSE) {
temp_buffer = ImpExAllocatePool2(
POOL_FLAG_PAGED, ValueLength + 20, POOL_TAG_STRINGS);
if (!temp_buffer)
return STATUS_MEMORY_NOT_ALLOCATED;
/*
* The registry path driver name does not contain the .sys extension which is
* required for us since when we enumerate the system modules we are comparing the
* entire path including the .sys extension. Hence we add it to the end of the
* buffer here.
* The registry path driver name does not contain the .sys
* extension which is required for us since when we enumerate
* the system modules we are comparing the entire path including
* the .sys extension. Hence we add it to the end of the buffer
* here.
*/
RtlCopyMemory(temp_buffer, ValueData, ValueLength);
wcscpy((UINT64)temp_buffer + ValueLength - 2, L".sys");
g_DriverConfig->unicode_driver_name.Buffer = (PWCH)temp_buffer;
g_DriverConfig->unicode_driver_name.Length = ValueLength + 20;
g_DriverConfig->unicode_driver_name.MaximumLength = ValueLength + 20;
g_DriverConfig->unicode_driver_name.Buffer = (PWCH)temp_buffer;
g_DriverConfig->unicode_driver_name.Length = ValueLength + 20;
g_DriverConfig->unicode_driver_name.MaximumLength =
ValueLength + 20;
}
return STATUS_SUCCESS;
@ -551,33 +565,33 @@ GetSystemProcessorType()
__cpuid(cpuid, 0);
DEBUG_VERBOSE("Cpuid: EBX: %lx, ECX: %lx, EDX: %lx", cpuid[1], cpuid[2], cpuid[3]);
DEBUG_VERBOSE("Cpuid: EBX: %lx, ECX: %lx, EDX: %lx",
cpuid[1],
cpuid[2],
cpuid[3]);
if (cpuid[EBX_REGISTER] == CPUID_AUTHENTIC_AMD_EBX &&
cpuid[ECX_REGISTER] == CPUID_AUTHENTIC_AMD_ECX &&
cpuid[EDX_REGISTER] == CPUID_AUTHENTIC_AMD_EDX)
{
cpuid[EDX_REGISTER] == CPUID_AUTHENTIC_AMD_EDX) {
g_DriverConfig->system_information.processor = GenuineIntel;
return STATUS_SUCCESS;
}
else if (cpuid[EBX_REGISTER] == CPUID_GENUINE_INTEL_EBX &&
cpuid[ECX_REGISTER] == CPUID_GENUINE_INTEL_ECX &&
cpuid[EDX_REGISTER] == CPUID_GENUINE_INTEL_EDX)
{
cpuid[EDX_REGISTER] == CPUID_GENUINE_INTEL_EDX) {
g_DriverConfig->system_information.processor = AuthenticAmd;
return STATUS_SUCCESS;
}
else
{
else {
g_DriverConfig->system_information.processor = Unknown;
return STATUS_UNSUCCESSFUL;
}
}
/*
* Even though we are technically not meant to be operating when running under a virtualized system,
* it is still useful to test the attainment of system information under a virtualized system for
* testing purposes.
* Even though we are technically not meant to be operating when running under a
* virtualized system, it is still useful to test the attainment of system
* information under a virtualized system for testing purposes.
*/
STATIC
NTSTATUS
@ -590,49 +604,49 @@ ParseSmbiosForGivenSystemEnvironment()
SmbiosInformation,
SMBIOS_VENDOR_STRING_SUB_INDEX);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ParseSMBIOSTable failed with status %x", status);
return status;
}
if (strstr(&g_DriverConfig->system_information.vendor, "VMware, Inc"))
g_DriverConfig->system_information.environment = Vmware;
else if (strstr(&g_DriverConfig->system_information.vendor, "innotek GmbH"))
else if (strstr(&g_DriverConfig->system_information.vendor,
"innotek GmbH"))
g_DriverConfig->system_information.environment = VirtualBox;
else
g_DriverConfig->system_information.environment = NativeWindows;
switch (g_DriverConfig->system_information.environment)
{
case NativeWindows:
{
switch (g_DriverConfig->system_information.environment) {
case NativeWindows: {
/*
* TODO: double check that amd indexes are the same should be, but should check just
* in case
* TODO: double check that amd indexes are the same should be,
* but should check just in case
*/
status = ParseSMBIOSTable(&g_DriverConfig->system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
VendorSpecificInformation,
SMBIOS_NATIVE_SERIAL_NUMBER_SUB_INDEX);
status = ParseSMBIOSTable(
&g_DriverConfig->system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
VendorSpecificInformation,
SMBIOS_NATIVE_SERIAL_NUMBER_SUB_INDEX);
break;
}
case Vmware:
{
status = ParseSMBIOSTable(&g_DriverConfig->system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
SystemInformation,
SMBIOS_VMWARE_SERIAL_NUMBER_SUB_INDEX);
case Vmware: {
status = ParseSMBIOSTable(
&g_DriverConfig->system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
SystemInformation,
SMBIOS_VMWARE_SERIAL_NUMBER_SUB_INDEX);
break;
}
case VirtualBox:
default: DEBUG_WARNING("Environment type not supported."); return STATUS_NOT_SUPPORTED;
default:
DEBUG_WARNING("Environment type not supported.");
return STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ParseSMBIOSTable 2 failed with status %x", status);
return status;
}
@ -650,51 +664,59 @@ DrvLoadGatherSystemEnvironmentSettings()
* On Vmware, the APERF_MSR is not emulated hence this will return TRUE.
*/
if (APERFMsrTimingCheck())
g_DriverConfig->system_information.virtualised_environment = TRUE;
g_DriverConfig->system_information.virtualised_environment =
TRUE;
status = GetOsVersionInformation(&g_DriverConfig->system_information.os_information);
status = GetOsVersionInformation(
&g_DriverConfig->system_information.os_information);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetOsVersionInformation failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("GetOsVersionInformation failed with status %x",
status);
return status;
}
status = GetSystemProcessorType();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetSystemProcessorType failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("GetSystemProcessorType failed with status %x",
status);
return status;
}
status = ParseSmbiosForGivenSystemEnvironment();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ParseSmbiosForGivenSystemEnvironment failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"ParseSmbiosForGivenSystemEnvironment failed with status %x",
status);
return status;
}
status =
GetHardDiskDriveSerialNumber(&g_DriverConfig->system_information.drive_0_serial,
sizeof(g_DriverConfig->system_information.drive_0_serial));
status = GetHardDiskDriveSerialNumber(
&g_DriverConfig->system_information.drive_0_serial,
sizeof(g_DriverConfig->system_information.drive_0_serial));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetHardDiskDriverSerialNumber failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"GetHardDiskDriverSerialNumber failed with status %x",
status);
return status;
}
DEBUG_VERBOSE("OS Major Version: %lx, Minor Version: %lx, Build Number: %lx",
g_DriverConfig->system_information.os_information.dwMajorVersion,
g_DriverConfig->system_information.os_information.dwMinorVersion,
g_DriverConfig->system_information.os_information.dwBuildNumber);
DEBUG_VERBOSE("Environment type: %lx", g_DriverConfig->system_information.environment);
DEBUG_VERBOSE("Processor type: %lx", g_DriverConfig->system_information.processor);
DEBUG_VERBOSE(
"OS Major Version: %lx, Minor Version: %lx, Build Number: %lx",
g_DriverConfig->system_information.os_information.dwMajorVersion,
g_DriverConfig->system_information.os_information.dwMinorVersion,
g_DriverConfig->system_information.os_information.dwBuildNumber);
DEBUG_VERBOSE("Environment type: %lx",
g_DriverConfig->system_information.environment);
DEBUG_VERBOSE("Processor type: %lx",
g_DriverConfig->system_information.processor);
DEBUG_VERBOSE("Motherboard serial: %s",
g_DriverConfig->system_information.motherboard_serial);
DEBUG_VERBOSE("Drive 0 serial: %s", g_DriverConfig->system_information.drive_0_serial);
DEBUG_VERBOSE("Drive 0 serial: %s",
g_DriverConfig->system_information.drive_0_serial);
return status;
}
@ -722,33 +744,42 @@ DrvLoadRetrieveDriverNameFromRegistry(_In_ PUNICODE_STRING RegistryPath)
query_table[1].EntryContext = NULL;
query_table[1].QueryRoutine = RegistryPathQueryCallbackRoutine;
status = RtlxQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE, RegistryPath->Buffer, &query_table, NULL, NULL);
status = RtlxQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
RegistryPath->Buffer,
&query_table,
NULL,
NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("RtlxQueryRegistryValues failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("RtlxQueryRegistryValues failed with status %x",
status);
return status;
}
/*
* The registry path contains the name of the driver i.e Driver, but does not contain the
* .sys extension. Lets add it to our stored driver name since we need the .sys extension
* when querying the system modules for our driver.
* The registry path contains the name of the driver i.e Driver, but
* does not contain the .sys extension. Lets add it to our stored driver
* name since we need the .sys extension when querying the system
* modules for our driver.
*/
status = ImpRtlUnicodeStringToAnsiString(
&g_DriverConfig->ansi_driver_name, &g_DriverConfig->unicode_driver_name, TRUE);
&g_DriverConfig->ansi_driver_name,
&g_DriverConfig->unicode_driver_name,
TRUE);
if (!NT_SUCCESS(status))
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", status);
DEBUG_ERROR(
"RtlUnicodeStringToAnsiString failed with status %x",
status);
return status;
}
STATIC
NTSTATUS
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath)
{
PAGED_CODE();
DEBUG_VERBOSE("Initialising driver configuration");
@ -766,38 +797,41 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
status = DrvLoadRetrieveDriverNameFromRegistry(RegistryPath);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("DrvLoadRetrieveDriverNameFromRegistry failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"DrvLoadRetrieveDriverNameFromRegistry failed with status %x",
status);
return status;
}
/* when this function failed, we bugcheck in freeconfigstrings todo: fix */
/* when this function failed, we bugcheck in freeconfigstrings todo: fix
*/
status = DrvLoadGatherSystemEnvironmentSettings();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GatherSystemEnvironmentSettings failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"GatherSystemEnvironmentSettings failed with status %x",
status);
return status;
}
status = InitialiseTimerObject(&g_DriverConfig->timer);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InitialiseTimerObject failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseTimerObject failed with status %x",
status);
return status;
}
status = IrpQueueInitialise();
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("IrpQueueInitialise failed with status %x", status);
return status;
}
DEBUG_VERBOSE("driver name: %s", g_DriverConfig->ansi_driver_name.Buffer);
DEBUG_VERBOSE("driver name: %s",
g_DriverConfig->ansi_driver_name.Buffer);
return status;
}
@ -827,13 +861,12 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
FALSE,
&DriverObject->DeviceObject);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("IoCreateDevice failed with status %x", status);
return status;
}
g_DriverConfig = DriverObject->DeviceObject->DeviceExtension;
g_DriverConfig = DriverObject->DeviceObject->DeviceExtension;
g_DriverConfig->device_object = DriverObject->DeviceObject;
g_DriverConfig->driver_object = DriverObject;
g_DriverConfig->device_name = &g_DeviceName;
@ -841,9 +874,10 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
status = DrvLoadInitialiseDriverConfig(DriverObject, RegistryPath);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InitialiseDriverConfigOnDriverEntry failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"InitialiseDriverConfigOnDriverEntry failed with status %x",
status);
DrvUnloadFreeConfigStrings();
ImpIoDeleteDevice(DriverObject->DeviceObject);
return status;
@ -851,12 +885,12 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
SessionInitialiseStructure();
status =
IoCreateSymbolicLink(g_DriverConfig->device_symbolic_link, g_DriverConfig->device_name);
status = IoCreateSymbolicLink(g_DriverConfig->device_symbolic_link,
g_DriverConfig->device_name);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("IoCreateSymbolicLink failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("IoCreateSymbolicLink failed with status %x",
status);
DrvUnloadFreeConfigStrings();
DrvUnloadFreeTimerObject();
ImpIoDeleteDevice(DriverObject->DeviceObject);
@ -865,9 +899,9 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
status = DrvLoadEnableNotifyRoutines();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("EnablenotifyRoutines failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("EnablenotifyRoutines failed with status %x",
status);
DrvUnloadFreeConfigStrings();
DrvUnloadFreeTimerObject();
DrvUnloadDeleteSymbolicLink();
@ -877,9 +911,9 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
status = DrvLoadSetupDriverLists();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("DrvLoadSetupDriverLists failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("DrvLoadSetupDriverLists failed with status %x",
status);
DrvUnloadFreeConfigStrings();
DrvUnloadFreeTimerObject();
DrvUnloadDeleteSymbolicLink();
@ -887,7 +921,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
return status;
}
g_DriverConfig->has_driver_loaded = TRUE;
g_DriverConfig->has_driver_loaded = TRUE;
DEBUG_INFO("Driver Entry Complete.");
return STATUS_SUCCESS;

View file

@ -14,15 +14,16 @@
/*
* 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
* 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
*/
BOOLEAN APERFMsrTimingCheck()
BOOLEAN
APERFMsrTimingCheck()
{
KAFFINITY new_affinity = {0};
KAFFINITY old_affinity = {0};
@ -30,16 +31,16 @@ BOOLEAN APERFMsrTimingCheck()
INT cpuid_result[4];
/*
* First thing we do is we lock the current thread to the logical processor
* its executing on.
* First thing we do is we lock the current thread to the logical
* processor its executing on.
*/
new_affinity = (KAFFINITY)(1ull << KeGetCurrentProcessorNumber());
old_affinity = ImpKeSetSystemAffinityThreadEx(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.
* 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);
@ -64,17 +65,17 @@ BOOLEAN APERFMsrTimingCheck()
* 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.
* to the threads previous irql before it was raised and then restore
* the threads affinity back to its original affinity.
*/
_enable();
__writecr8(old_irql);
ImpKeRevertToUserAffinityThreadEx(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.
* 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;
@ -86,11 +87,12 @@ PerformVirtualizationDetection(_Inout_ PIRP Irp)
{
PAGED_CODE();
NTSTATUS status = ValidateIrpOutputBuffer(Irp, sizeof(HYPERVISOR_DETECTION_REPORT));
NTSTATUS status =
ValidateIrpOutputBuffer(Irp, sizeof(HYPERVISOR_DETECTION_REPORT));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x",
status);
return status;
}
@ -100,8 +102,9 @@ PerformVirtualizationDetection(_Inout_ PIRP Irp)
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;
}

View file

@ -11,15 +11,18 @@ USHORT FLAGGED_DEVICE_IDS[FLAGGED_DEVICE_ID_COUNT] = {
0x0666, // default PCIe Squirrel DeviceID (used by PCI Leech)
0xffff};
typedef NTSTATUS (*PCI_DEVICE_CALLBACK)(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context);
typedef NTSTATUS (*PCI_DEVICE_CALLBACK)(_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context);
/*
* Every PCI device has a set of registers commonly referred to as the PCI configuration space. In
* modern PCI-e devices an extended configuration space was implemented. These configuration spaces
* are mapped into main memory and this allows us to read/write to the registers.
* Every PCI device has a set of registers commonly referred to as the PCI
* configuration space. In modern PCI-e devices an extended configuration space
* was implemented. These configuration spaces are mapped into main memory and
* this allows us to read/write to the registers.
*
* The configuration space consists of a standard header, containing information such as the
* DeviceID, VendorID, Status and so on. Below is the header schema including offsets.
* The configuration space consists of a standard header, containing information
* such as the DeviceID, VendorID, Status and so on. Below is the header schema
* including offsets.
*
* | Offset 0x00: Header Type
* | Offset 0x01: Multi-Function Device Indicator
@ -52,9 +55,10 @@ typedef NTSTATUS (*PCI_DEVICE_CALLBACK)(_In_ PDEVICE_OBJECT DeviceObject, _In_op
* | Offset 0x3E: Interrupt Pin
* | Offset 0x3F: Interrupt Line
*
* We can use this to then query important information from PCI devices within the device tree. To
* keep up with modern windows kernel programming, we can make use of the IRP_MN_READ_CONFIG code,
* which as the name suggests, reads from a PCI devices configuration space.
* We can use this to then query important information from PCI devices within
* the device tree. To keep up with modern windows kernel programming, we can
* make use of the IRP_MN_READ_CONFIG code, which as the name suggests, reads
* from a PCI devices configuration space.
*/
STATIC
NTSTATUS
@ -75,34 +79,37 @@ QueryPciDeviceConfigurationSpace(_In_ PDEVICE_OBJECT DeviceObject,
KeInitializeEvent(&event, NotificationEvent, FALSE);
/*
* we dont need to free this IRP as the IO manager will free it when the request is
* completed
* we dont need to free this IRP as the IO manager will free it when the
* request is completed
*/
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, DeviceObject, NULL, 0, NULL, &event, &io);
irp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP, DeviceObject, NULL, 0, NULL, &event, &io);
if (!irp)
{
DEBUG_ERROR("IoBuildSynchronousFsdRequest failed with no status.");
if (!irp) {
DEBUG_ERROR(
"IoBuildSynchronousFsdRequest failed with no status.");
return STATUS_INSUFFICIENT_RESOURCES;
}
io_stack_location = IoGetNextIrpStackLocation(irp);
io_stack_location->MinorFunction = IRP_MN_READ_CONFIG;
io_stack_location->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
io_stack_location->Parameters.ReadWriteConfig.Offset = Offset;
io_stack_location->Parameters.ReadWriteConfig.Buffer = Buffer;
io_stack_location->Parameters.ReadWriteConfig.Length = BufferLength;
io_stack_location = IoGetNextIrpStackLocation(irp);
io_stack_location->MinorFunction = IRP_MN_READ_CONFIG;
io_stack_location->Parameters.ReadWriteConfig.WhichSpace =
PCI_WHICHSPACE_CONFIG;
io_stack_location->Parameters.ReadWriteConfig.Offset = Offset;
io_stack_location->Parameters.ReadWriteConfig.Buffer = Buffer;
io_stack_location->Parameters.ReadWriteConfig.Length = BufferLength;
status = IoCallDriver(DeviceObject, irp);
if (status = STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
if (status = STATUS_PENDING) {
KeWaitForSingleObject(
&event, Executive, KernelMode, FALSE, NULL);
status = io.Status;
}
if (!NT_SUCCESS(status))
DEBUG_ERROR("Failed to read configuration space with status %x", status);
DEBUG_ERROR("Failed to read configuration space with status %x",
status);
return status;
}
@ -123,30 +130,33 @@ EnumerateDriverObjectDeviceObjects(_In_ PDRIVER_OBJECT DriverObject,
*DeviceObjectArray = NULL;
status = IoEnumerateDeviceObjectList(DriverObject, NULL, 0, &object_count);
status =
IoEnumerateDeviceObjectList(DriverObject, NULL, 0, &object_count);
if (status != STATUS_BUFFER_TOO_SMALL)
{
DEBUG_ERROR("IoEnumerateDeviceObjectList failed with status %x", status);
if (status != STATUS_BUFFER_TOO_SMALL) {
DEBUG_ERROR("IoEnumerateDeviceObjectList failed with status %x",
status);
return status;
}
buffer_size = object_count * sizeof(UINT64);
buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, buffer_size, POOL_TAG_HW);
buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, buffer_size, POOL_TAG_HW);
if (!buffer)
return STATUS_INSUFFICIENT_RESOURCES;
status = IoEnumerateDeviceObjectList(DriverObject, buffer, buffer_size, &object_count);
status = IoEnumerateDeviceObjectList(
DriverObject, buffer, buffer_size, &object_count);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("IoEnumerateDeviceObjectList failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("IoEnumerateDeviceObjectList failed with status %x",
status);
ExFreePoolWithTag(buffer, POOL_TAG_HW);
return status;
}
DEBUG_VERBOSE("EnumerateDriverObjectDeviceObjects: Object Count: %lx", object_count);
DEBUG_VERBOSE("EnumerateDriverObjectDeviceObjects: Object Count: %lx",
object_count);
*DeviceObjectArray = buffer;
*ArrayEntries = object_count;
@ -155,8 +165,9 @@ EnumerateDriverObjectDeviceObjects(_In_ PDRIVER_OBJECT DriverObject,
}
/*
* While this isnt a perfect check to determine whether a DEVICE_OBJECT is indeed a PDO or FDO, this
* is Peters preferred method... hence it is now my preferred method... :smiling_imp:
* While this isnt a perfect check to determine whether a DEVICE_OBJECT is
* indeed a PDO or FDO, this is Peters preferred method... hence it is now my
* preferred method... :smiling_imp:
*/
STATIC
BOOLEAN
@ -171,22 +182,23 @@ IsDeviceObjectValidPdo(_In_ PDEVICE_OBJECT DeviceObject)
* Physical Device Object (PDO)
* Functional Device Object (FDO)
*
* A PDO represents each device that is connected to a physical bus. Each PDO has an associated
* DEVICE_NODE. An FDO represents the functionality of the device. Its how the system interacts with
* the device objects.
* A PDO represents each device that is connected to a physical bus. Each PDO
* has an associated DEVICE_NODE. An FDO represents the functionality of the
* device. Its how the system interacts with the device objects.
*
* More information can be found here:
* https://learn.microsoft.com/en-gb/windows-hardware/drivers/gettingstarted/device-nodes-and-device-stacks
*
* A device stack can have multiple PDO's, but can only have one FDO. This means to access each PCI
* device on the system, we can enumerate all device objects given the PCI FDO which is called
* pci.sys.
* A device stack can have multiple PDO's, but can only have one FDO. This means
* to access each PCI device on the system, we can enumerate all device objects
* given the PCI FDO which is called pci.sys.
*/
NTSTATUS
EnumeratePciDeviceObjects(_In_ PCI_DEVICE_CALLBACK CallbackRoutine, _In_opt_ PVOID Context)
EnumeratePciDeviceObjects(_In_ PCI_DEVICE_CALLBACK CallbackRoutine,
_In_opt_ PVOID Context)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING pci = RTL_CONSTANT_STRING(L"\\Driver\\pci");
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING pci = RTL_CONSTANT_STRING(L"\\Driver\\pci");
PDRIVER_OBJECT pci_driver_object = NULL;
PDEVICE_OBJECT* pci_device_objects = NULL;
PDEVICE_OBJECT current_device = NULL;
@ -195,28 +207,27 @@ EnumeratePciDeviceObjects(_In_ PCI_DEVICE_CALLBACK CallbackRoutine, _In_opt_ PVO
status = GetDriverObjectByDriverName(&pci, &pci_driver_object);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetDriverObjectByDriverName failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("GetDriverObjectByDriverName failed with status %x",
status);
return status;
}
status = EnumerateDriverObjectDeviceObjects(
pci_driver_object, &pci_device_objects, &pci_device_objects_count);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("EnumerateDriverObjectDeviceObjects failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"EnumerateDriverObjectDeviceObjects failed with status %x",
status);
return status;
}
for (UINT32 index = 0; index < pci_device_objects_count; index++)
{
for (UINT32 index = 0; index < pci_device_objects_count; index++) {
current_device = pci_device_objects[index];
/* make sure we have a valid PDO */
if (!IsDeviceObjectValidPdo(current_device))
{
if (!IsDeviceObjectValidPdo(current_device)) {
ObDereferenceObject(current_device);
continue;
}
@ -241,8 +252,7 @@ end:
BOOLEAN
IsPciConfigurationSpaceFlagged(_In_ PPCI_COMMON_HEADER Configuration)
{
for (UINT32 index = 0; index < FLAGGED_DEVICE_ID_COUNT; index++)
{
for (UINT32 index = 0; index < FLAGGED_DEVICE_ID_COUNT; index++) {
if (Configuration->DeviceID == FLAGGED_DEVICE_IDS[index])
return TRUE;
}
@ -257,23 +267,25 @@ PciDeviceQueryCallback(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
NTSTATUS status = STATUS_UNSUCCESSFUL;
PCI_COMMON_HEADER header = {0};
status = QueryPciDeviceConfigurationSpace(
DeviceObject, PCI_VENDOR_ID_OFFSET, &header, sizeof(PCI_COMMON_HEADER));
status = QueryPciDeviceConfigurationSpace(DeviceObject,
PCI_VENDOR_ID_OFFSET,
&header,
sizeof(PCI_COMMON_HEADER));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("QueryPciDeviceConfigurationSpace failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"QueryPciDeviceConfigurationSpace failed with status %x",
status);
return status;
}
if (IsPciConfigurationSpaceFlagged(&header))
{
DEBUG_VERBOSE("Flagged DeviceID found. Device: %llx, DeviceId: %lx",
(UINT64)DeviceObject,
header.DeviceID);
if (IsPciConfigurationSpaceFlagged(&header)) {
DEBUG_VERBOSE(
"Flagged DeviceID found. Device: %llx, DeviceId: %lx",
(UINT64)DeviceObject,
header.DeviceID);
}
else
{
else {
DEBUG_VERBOSE("Device: %llx, DeviceID: %lx, VendorID: %lx",
DeviceObject,
header.DeviceID,
@ -291,7 +303,8 @@ ValidatePciDevices()
status = EnumeratePciDeviceObjects(PciDeviceQueryCallback, NULL);
if (!NT_SUCCESS(status))
DEBUG_ERROR("EnumeratePciDeviceObjects failed with status %x", status);
DEBUG_ERROR("EnumeratePciDeviceObjects failed with status %x",
status);
return status;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,15 +5,14 @@
#include "common.h"
typedef struct _MODULE_DISPATCHER_HEADER
{
volatile UINT32 validated; // if this is > 0, a thread is already using it
UINT8 result;
typedef struct _MODULE_DISPATCHER_HEADER {
volatile UINT32
validated; // if this is > 0, a thread is already using it
UINT8 result;
} MODULE_DISPATCHER_HEADER, *PMODULE_DISPATCHER_HEADER;
typedef struct _SYSTEM_MODULE_INFORMATION
{
typedef struct _SYSTEM_MODULE_INFORMATION {
MODULE_DISPATCHER_HEADER dispatcher_header;
RTL_MODULE_EXTENDED_INFO module_information;
@ -21,8 +20,7 @@ typedef struct _SYSTEM_MODULE_INFORMATION
#define VERIFICATION_THREAD_COUNT 4
typedef struct _SYS_MODULE_VAL_CONTEXT
{
typedef struct _SYS_MODULE_VAL_CONTEXT {
/* Stores the number of actively executing worker threads */
volatile LONG active_thread_count;
@ -47,13 +45,13 @@ typedef struct _SYS_MODULE_VAL_CONTEXT
/* pointer to the array of dispatcher info used to synchonize threads */
PMODULE_DISPATCHER_HEADER dispatcher_info;
/* array of pointers to work items, used to free work items when complete */
/* array of pointers to work items, used to free work items when
* complete */
PIO_WORKITEM work_items[VERIFICATION_THREAD_COUNT];
} SYS_MODULE_VAL_CONTEXT, *PSYS_MODULE_VAL_CONTEXT;
typedef enum _SMBIOS_TABLE_INDEX
{
typedef enum _SMBIOS_TABLE_INDEX {
SmbiosInformation = 0,
SystemInformation,
VendorSpecificInformation,
@ -75,7 +73,8 @@ NTSTATUS
ValidateProcessLoadedModule(_Inout_ PIRP Irp);
NTSTATUS
GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T ConfigDrive0MaxSize);
GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial,
_In_ SIZE_T ConfigDrive0MaxSize);
NTSTATUS
ParseSMBIOSTable(_Out_ PVOID Buffer,

View file

@ -72,15 +72,15 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation);
#define APC_OPERATION_STACKWALK 0x1
/*
* Basic cancel-safe IRP queue implementation. Stores pending IRPs in a list, allowing us to dequeue
* entries to send data back to user mode without being invoked by the user mode module via an io
* completion port.
* Basic cancel-safe IRP queue implementation. Stores pending IRPs in a list,
* allowing us to dequeue entries to send data back to user mode without being
* invoked by the user mode module via an io completion port.
*
* user mode program will automatically queue another irp when an irp completes, ensuring queue has
* a sufficient supply.
* user mode program will automatically queue another irp when an irp completes,
* ensuring queue has a sufficient supply.
*
* note: maybe we should use a spinlock here? Dont really want competing threads sleeping. I think
* spinlock should be used here.
* note: maybe we should use a spinlock here? Dont really want competing threads
* sleeping. I think spinlock should be used here.
*/
VOID
IrpQueueAcquireLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
@ -103,7 +103,8 @@ IrpQueuePeekNextEntry(_In_ PIO_CSQ Csq, _In_ PIRP Irp, _In_ PVOID Context)
if (queue->count == 0)
return NULL;
return CONTAINING_RECORD(queue->queue.Flink, IRP, Tail.Overlay.ListEntry);
return CONTAINING_RECORD(
queue->queue.Flink, IRP, Tail.Overlay.ListEntry);
}
VOID
@ -142,7 +143,10 @@ IrpQueueCompleteDeferredReport(_In_ PDEFERRED_REPORT Report, _In_ PIRP Irp)
if (!NT_SUCCESS(status))
return status;
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Report->buffer, Report->buffer_size);
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
Report->buffer,
Report->buffer_size);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = Report->buffer_size;
IofCompleteRequest(Irp, IO_NO_INCREMENT);
@ -159,30 +163,29 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
KIRQL irql = 0;
/*
* Important we hold the lock before we call IsThereDeferredReport to prevent the race
* condition where in the period between when we get a TRUE result and another thread
* removes the last entry from the list. We then request a deferred report and will receive
* a null value leading to a bugcheck in the subsequent call to CompleteDeferredReport.
* Important we hold the lock before we call IsThereDeferredReport to
* prevent the race condition where in the period between when we get a
* TRUE result and another thread removes the last entry from the list.
* We then request a deferred report and will receive a null value
* leading to a bugcheck in the subsequent call to
* CompleteDeferredReport.
*/
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
if (IrpQueueIsThereDeferredReport(queue))
{
if (IrpQueueIsThereDeferredReport(queue)) {
report = IrpQueueRemoveDeferredReport(queue);
status = IrpQueueCompleteDeferredReport(report, Irp);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
IrpQueueFreeDeferredReport(report);
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
goto end;
}
queue->deferred_reports.count--;
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
goto end;
}
end:
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
}
@ -207,8 +210,8 @@ IrpQueueCompleteCancelledIrp(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
PDEFERRED_REPORT
IrpQueueAllocateDeferredReport(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
{
PDEFERRED_REPORT report =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DEFERRED_REPORT), REPORT_POOL_TAG);
PDEFERRED_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(DEFERRED_REPORT), REPORT_POOL_TAG);
if (!report)
return NULL;
@ -221,16 +224,17 @@ IrpQueueAllocateDeferredReport(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
#define MAX_DEFERRED_REPORTS_COUNT 100
VOID
IrpQueueDeferReport(_In_ PIRP_QUEUE_HEAD Queue, _In_ PVOID Buffer, _In_ UINT32 BufferSize)
IrpQueueDeferReport(_In_ PIRP_QUEUE_HEAD Queue,
_In_ PVOID Buffer,
_In_ UINT32 BufferSize)
{
PDEFERRED_REPORT report = NULL;
KIRQL irql = 0;
KIRQL irql = {0};
/*
* arbitrary number, if we ever do have 100 deferred reports, theres probably a catastrophic
* error somewhere else
* arbitrary number, if we ever do have 100 deferred reports, theres
* probably a catastrophic error somewhere else
*/
if (Queue->deferred_reports.count > MAX_DEFERRED_REPORTS_COUNT)
{
if (Queue->deferred_reports.count > MAX_DEFERRED_REPORTS_COUNT) {
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
return;
}
@ -260,11 +264,11 @@ IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
PIRP irp = IoCsqRemoveNextIrp(&queue->csq, NULL);
/*
* If no irps are available in our queue, lets store it in a deferred reports list which
* should be checked each time we insert a new irp into the queue.
* If no irps are available in our queue, lets store it in a deferred
* reports list which should be checked each time we insert a new irp
* into the queue.
*/
if (!irp)
{
if (!irp) {
IrpQueueDeferReport(queue, Buffer, BufferSize);
return STATUS_SUCCESS;
}
@ -272,11 +276,10 @@ IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
status = ValidateIrpOutputBuffer(irp, BufferSize);
/*
* Not sure how we should handle this, for now lets just free the buffer and return a
* status.
* Not sure how we should handle this, for now lets just free the buffer
* and return a status.
*/
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
@ -302,8 +305,7 @@ IrpQueueFreeDeferredReports()
/* just in case... */
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
while (IrpQueueIsThereDeferredReport(queue))
{
while (IrpQueueIsThereDeferredReport(queue)) {
report = IrpQueueRemoveDeferredReport(queue);
IrpQueueFreeDeferredReport(report);
}
@ -337,7 +339,8 @@ IrpQueueInitialise()
}
VOID
SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE handle = NULL;
@ -348,22 +351,24 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Contex
DEBUG_VERBOSE("SharedMapping work routine called. OperationId: %lx",
state->kernel_buffer->operation_id);
switch (state->kernel_buffer->operation_id)
{
switch (state->kernel_buffer->operation_id) {
case ssRunNmiCallbacks:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: RunNmiCallbacks Received.");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: RunNmiCallbacks Received.");
status = HandleNmiIOCTL();
if (!NT_SUCCESS(status))
DEBUG_ERROR("RunNmiCallbacks failed with status %lx", status);
DEBUG_ERROR("RunNmiCallbacks failed with status %lx",
status);
break;
case ssValidateDriverObjects:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: ValidateDriverObjects Received.");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ValidateDriverObjects Received.");
status = ImpPsCreateSystemThread(&handle,
PROCESS_ALL_ACCESS,
@ -373,9 +378,10 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Contex
HandleValidateDriversIOCTL,
NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"PsCreateSystemThread failed with status %x",
status);
goto end;
}
@ -384,38 +390,48 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Contex
case ssEnumerateHandleTables:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: EnumerateHandleTables Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: EnumerateHandleTables Received");
/* can maybe implement this better so we can extract a status value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL);
/* can maybe implement this better so we can extract a status
* value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles,
NULL);
break;
case ssScanForUnlinkedProcesses:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: ScanForUnlinkedProcesses Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ScanForUnlinkedProcesses Received");
status = FindUnlinkedProcesses();
if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUnlinkedProcesses failed with status %x", status);
DEBUG_ERROR(
"FindUnlinkedProcesses failed with status %x",
status);
break;
case ssPerformModuleIntegrityCheck:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: PerformIntegrityCheck Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: PerformIntegrityCheck Received");
status = ValidateOurDriverImage();
if (!NT_SUCCESS(status))
DEBUG_ERROR("VerifyInMemoryImageVsDiskImage failed with status %x", status);
DEBUG_ERROR(
"VerifyInMemoryImageVsDiskImage failed with status %x",
status);
break;
case ssScanForAttachedThreads:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: ScanForAttachedThreads Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ScanForAttachedThreads Received");
DetectThreadsAttachedToProtectedProcess();
@ -423,12 +439,15 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Contex
case ssScanForEptHooks:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: ScanForEptHooks Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ScanForEptHooks Received");
status = DetectEptHooksInKeyFunctions();
if (!NT_SUCCESS(status))
DEBUG_ERROR("DetectEpthooksInKeyFunctions failed with status %x", status);
DEBUG_ERROR(
"DetectEpthooksInKeyFunctions failed with status %x",
status);
break;
@ -439,19 +458,23 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Contex
status = DispatchStackwalkToEachCpuViaDpc();
if (!NT_SUCCESS(status))
DEBUG_ERROR("DispatchStackwalkToEachCpuViaDpc failed with status %x",
status);
DEBUG_ERROR(
"DispatchStackwalkToEachCpuViaDpc failed with status %x",
status);
break;
case ssValidateSystemModules:
DEBUG_INFO("SHARED_STATE_OPERATION_ID: ValidateSystemModules Received");
DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ValidateSystemModules Received");
status = SystemModuleVerificationDispatcher();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateSystemModules failed with status %x", status);
DEBUG_ERROR(
"ValidateSystemModules failed with status %x",
status);
break;
@ -474,7 +497,10 @@ SharedMappingDpcRoutine(_In_ PKDPC Dpc,
if (!mapping->active || mapping->work_item_status)
return;
IoQueueWorkItem(mapping->work_item, SharedMappingWorkRoutine, NormalWorkQueue, mapping);
IoQueueWorkItem(mapping->work_item,
SharedMappingWorkRoutine,
NormalWorkQueue,
mapping);
}
#define REPEAT_TIME_15_SEC 30000
@ -513,15 +539,15 @@ SharedMappingInitialiseTimer(_In_ PSHARED_MAPPING Mapping)
Mapping->work_item = IoAllocateWorkItem(GetDriverDeviceObject());
if (!Mapping->work_item)
{
if (!Mapping->work_item) {
DEBUG_ERROR("IoAllocateWorkItem failed with no status.");
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeDpc(&Mapping->timer_dpc, SharedMappingDpcRoutine, Mapping);
KeInitializeTimer(&Mapping->timer);
KeSetTimerEx(&Mapping->timer, due_time, REPEAT_TIME_15_SEC, &Mapping->timer_dpc);
KeSetTimerEx(
&Mapping->timer, due_time, REPEAT_TIME_15_SEC, &Mapping->timer_dpc);
DEBUG_VERBOSE("Initialised shared mapping event timer.");
return STATUS_SUCCESS;
@ -544,22 +570,25 @@ SharedMappingInitialise(_In_ PIRP Irp)
/* TODO: need to copy these out */
status = ValidateIrpOutputBuffer(Irp, sizeof(SHARED_MAPPING_INIT));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x",
status);
return status;
}
/* remember that ExAllocatePool2 zeroes the allocation, so no need to zero */
buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, PAGE_SIZE, POOL_TAG_INTEGRITY);
/*
* remember that ExAllocatePool2 zeroes the allocation, so no need to
* zero
*/
buffer =
ExAllocatePool2(POOL_FLAG_NON_PAGED, PAGE_SIZE, POOL_TAG_INTEGRITY);
if (!buffer)
return STATUS_INSUFFICIENT_RESOURCES;
mdl = IoAllocateMdl(buffer, PAGE_SIZE, FALSE, FALSE, NULL);
if (!mdl)
{
if (!mdl) {
DEBUG_ERROR("IoAllocateMdl failed with no status");
ExFreePoolWithTag(buffer, POOL_TAG_INTEGRITY);
return STATUS_INSUFFICIENT_RESOURCES;
@ -567,15 +596,20 @@ SharedMappingInitialise(_In_ PIRP Irp)
MmBuildMdlForNonPagedPool(mdl);
__try
{
__try {
user_buffer = MmMapLockedPagesSpecifyCache(
mdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority | MdlMappingNoExecute);
mdl,
UserMode,
MmCached,
NULL,
FALSE,
NormalPagePriority | MdlMappingNoExecute);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
DEBUG_ERROR("MmMapLockedPagesSpecifyCache failed with status %x", status);
DEBUG_ERROR(
"MmMapLockedPagesSpecifyCache failed with status %x",
status);
IoFreeMdl(mdl);
ExFreePoolWithTag(buffer, POOL_TAG_INTEGRITY);
return status;
@ -590,7 +624,7 @@ SharedMappingInitialise(_In_ PIRP Irp)
SharedMappingInitialiseTimer(mapping);
mapping_init = (PSHARED_MAPPING_INIT)Irp->AssociatedIrp.SystemBuffer;
mapping_init = (PSHARED_MAPPING_INIT)Irp->AssociatedIrp.SystemBuffer;
mapping_init->buffer = user_buffer;
mapping_init->size = PAGE_SIZE;
@ -607,41 +641,48 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation)
DEBUG_VERBOSE("Dispatching APC Operation...");
switch (Operation->operation_id)
{
switch (Operation->operation_id) {
case APC_OPERATION_STACKWALK:
DEBUG_INFO("Initiating APC stackwalk operation with operation id %i",
Operation->operation_id);
DEBUG_INFO(
"Initiating APC stackwalk operation with operation id %i",
Operation->operation_id);
status = ValidateThreadsViaKernelApc();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateThreadsViaKernelApc failed with status %x", status);
DEBUG_ERROR(
"ValidateThreadsViaKernelApc failed with status %x",
status);
return status;
default: DEBUG_WARNING("Invalid operation ID passed"); return STATUS_INVALID_PARAMETER;
default:
DEBUG_WARNING("Invalid operation ID passed");
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
/*
* 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.
* 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.
* 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.
* 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)
@ -701,15 +742,14 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
*/
SessionIsActive(&security_flag);
if (security_flag == FALSE && stack_location->Parameters.DeviceIoControl.IoControlCode !=
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH)
{
if (security_flag == FALSE &&
stack_location->Parameters.DeviceIoControl.IoControlCode !=
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH) {
status = STATUS_ACCESS_DENIED;
goto end;
}
switch (stack_location->Parameters.DeviceIoControl.IoControlCode)
{
switch (stack_location->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_RUN_NMI_CALLBACKS:
DEBUG_INFO("IOCTL_RUN_NMI_CALLBACKS Received.");
@ -717,7 +757,8 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = HandleNmiIOCTL(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("RunNmiCallbacks failed with status %lx", status);
DEBUG_ERROR("RunNmiCallbacks failed with status %lx",
status);
break;
@ -726,11 +767,12 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_VALIDATE_DRIVER_OBJECTS Received.");
/*
* 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.
* 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.
*/
status = ImpPsCreateSystemThread(&handle,
@ -741,9 +783,10 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
HandleValidateDriversIOCTL,
NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"PsCreateSystemThread failed with status %x",
status);
goto end;
}
@ -756,16 +799,17 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = SessionInitialise(Irp);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("InitialiseSession failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseSession failed with status %x",
status);
goto end;
}
status = RegisterProcessObCallbacks();
if (!NT_SUCCESS(status))
DEBUG_ERROR("EnableObCallbacks failed with status %x", status);
DEBUG_ERROR("EnableObCallbacks failed with status %x",
status);
break;
@ -776,8 +820,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = QueryActiveApcContextsForCompletion();
if (!NT_SUCCESS(status))
DEBUG_ERROR("QueryActiveApcContextsForCompletion failed with status %x",
status);
DEBUG_ERROR(
"QueryActiveApcContextsForCompletion failed with status %x",
status);
break;
@ -788,7 +833,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = PerformVirtualizationDetection(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("PerformVirtualizationDetection failed with status %x", status);
DEBUG_ERROR(
"PerformVirtualizationDetection failed with status %x",
status);
break;
@ -796,40 +843,51 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_ENUMERATE_HANDLE_TABLES Received");
/* can maybe implement this better so we can extract a status value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL);
/* can maybe implement this better so we can extract a status
* value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles,
NULL);
break;
case IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS:
DEBUG_VERBOSE("IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS Received");
DEBUG_VERBOSE(
"IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS Received");
status = ImpPsCreateSystemThread(&handle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
RetrieveInMemoryModuleExecutableSections,
Irp);
status = ImpPsCreateSystemThread(
&handle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
RetrieveInMemoryModuleExecutableSections,
Irp);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"PsCreateSystemThread failed with status %x",
status);
goto end;
}
status = ImpObReferenceObjectByHandle(
handle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &thread, NULL);
status = ImpObReferenceObjectByHandle(handle,
THREAD_ALL_ACCESS,
*PsThreadType,
KernelMode,
&thread,
NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ObReferenceObjectbyhandle failed with status %lx", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"ObReferenceObjectbyhandle failed with status %lx",
status);
ImpZwClose(handle);
goto end;
}
ImpKeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
ImpKeWaitForSingleObject(
thread, Executive, KernelMode, FALSE, NULL);
ImpZwClose(handle);
ImpObDereferenceObject(thread);
@ -843,13 +901,15 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = GetDriverImageSize(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("GetDriverImageSize failed with status %x", status);
DEBUG_ERROR("GetDriverImageSize failed with status %x",
status);
break;
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION:
DEBUG_INFO("IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION Received");
DEBUG_INFO(
"IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION Received");
SessionTerminate();
UnregisterProcessObCallbacks();
@ -863,7 +923,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = FindUnlinkedProcesses();
if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUnlinkedProcesses failed with status %x", status);
DEBUG_ERROR(
"FindUnlinkedProcesses failed with status %x",
status);
break;
@ -874,7 +936,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = ValidateOurDriverImage();
if (!NT_SUCCESS(status))
DEBUG_ERROR("VerifyInMemoryImageVsDiskImage failed with status %x", status);
DEBUG_ERROR(
"VerifyInMemoryImageVsDiskImage failed with status %x",
status);
break;
@ -893,7 +957,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = ValidateProcessLoadedModule(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateProcessLoadedModule failed with status %x", status);
DEBUG_ERROR(
"ValidateProcessLoadedModule failed with status %x",
status);
break;
@ -901,13 +967,16 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_REQUEST_HARDWARE_INFORMATION Received");
PSYSTEM_INFORMATION system_information = GetDriverConfigSystemInformation();
PSYSTEM_INFORMATION system_information =
GetDriverConfigSystemInformation();
status = ValidateIrpOutputBuffer(Irp, sizeof(SYSTEM_INFORMATION));
status =
ValidateIrpOutputBuffer(Irp, sizeof(SYSTEM_INFORMATION));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"ValidateIrpOutputBuffer failed with status %x",
status);
goto end;
}
@ -923,12 +992,15 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_INITIATE_APC_OPERATION Received");
PAPC_OPERATION_ID operation = (PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
PAPC_OPERATION_ID operation =
(PAPC_OPERATION_ID)Irp->AssociatedIrp.SystemBuffer;
status = DispatchApcOperation(operation);
if (!NT_SUCCESS(status))
DEBUG_ERROR("DispatchApcOperation failed with status %x", status);
DEBUG_ERROR(
"DispatchApcOperation failed with status %x",
status);
break;
@ -939,7 +1011,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = DetectEptHooksInKeyFunctions();
if (!NT_SUCCESS(status))
DEBUG_ERROR("DetectEpthooksInKeyFunctions failed with status %x", status);
DEBUG_ERROR(
"DetectEpthooksInKeyFunctions failed with status %x",
status);
break;
@ -950,7 +1024,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = SystemModuleVerificationDispatcher();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateSystemModules failed with status %x", status);
DEBUG_ERROR(
"ValidateSystemModules failed with status %x",
status);
break;
@ -961,8 +1037,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = DispatchStackwalkToEachCpuViaDpc();
if (!NT_SUCCESS(status))
DEBUG_ERROR("DispatchStackwalkToEachCpuViaDpc failed with status %x",
status);
DEBUG_ERROR(
"DispatchStackwalkToEachCpuViaDpc failed with status %x",
status);
break;
@ -973,19 +1050,22 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
/*
* Given the nature of the Windows IO subsystem and the cancel-safe queue
* implementation we use, we need to query for deferred reports before insert an irp
* into the queue. The reason for this is the cancel-safe queue will automically
* mark the irp as pending, so if we then use that irp to return a deferred report
* and return success here verifier has a lil cry.
* Given the nature of the Windows IO subsystem and the
* cancel-safe queue implementation we use, we need to query for
* deferred reports before insert an irp into the queue. The
* reason for this is the cancel-safe queue will automically
* mark the irp as pending, so if we then use that irp to return
* a deferred report and return success here verifier has a lil
* cry.
*/
/* before we queue our IRP, check if we can complete a deferred report */
/* before we queue our IRP, check if we can complete a deferred
* report */
status = IrpQueueQueryPendingReports(Irp);
/* if we return success, weve completed the irp, we can return success */
if (!NT_SUCCESS(status))
{
/* if we return success, weve completed the irp, we can return
* success */
if (!NT_SUCCESS(status)) {
/* if there are no deferred reports, store the irp in
* the queue */
IoCsqInsertIrp(&queue->csq, Irp, NULL);
@ -1003,7 +1083,9 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = SharedMappingInitialise(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("SharedMappingInitialise failed with status %x", status);
DEBUG_ERROR(
"SharedMappingInitialise failed with status %x",
status);
break;
@ -1014,13 +1096,15 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
status = ValidatePciDevices();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidatePciDevices failed with status %x", status);
DEBUG_ERROR("ValidatePciDevices failed with status %x",
status);
break;
default:
DEBUG_WARNING("Invalid IOCTL passed to driver: %lx",
stack_location->Parameters.DeviceIoControl.IoControlCode);
DEBUG_WARNING(
"Invalid IOCTL passed to driver: %lx",
stack_location->Parameters.DeviceIoControl.IoControlCode);
status = STATUS_INVALID_PARAMETER;
break;

View file

@ -6,15 +6,13 @@
#include <wdf.h>
#include "common.h"
typedef struct _SHARED_MAPPING_INIT
{
typedef struct _SHARED_MAPPING_INIT {
PVOID buffer;
SIZE_T size;
} SHARED_MAPPING_INIT, *PSHARED_MAPPING_INIT;
typedef enum _SHARED_STATE_OPERATION_ID
{
typedef enum _SHARED_STATE_OPERATION_ID {
ssRunNmiCallbacks = 0,
ssValidateDriverObjects,
ssEnumerateHandleTables,
@ -27,15 +25,13 @@ typedef enum _SHARED_STATE_OPERATION_ID
} SHARED_STATE_OPERATION_ID;
typedef struct _SHARED_STATE
{
typedef struct _SHARED_STATE {
volatile UINT32 status;
volatile UINT16 operation_id;
} SHARED_STATE, *PSHARED_STATE;
typedef struct _SHARED_MAPPING
{
typedef struct _SHARED_MAPPING {
volatile LONG work_item_status;
PVOID user_buffer;
PSHARED_STATE kernel_buffer;

View file

@ -15,13 +15,13 @@
* ...
* };
*
* 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.
* 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.
* 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.
*/
#define LIST_POOL_TAG 'list'
@ -62,8 +62,7 @@ ListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
BOOLEAN result = FALSE;
ImpKeAcquireGuardedMutex(Lock);
if (Head->Next)
{
if (Head->Next) {
PSINGLE_LIST_ENTRY entry = Head->Next;
if (CallbackRoutine)
@ -79,8 +78,8 @@ ListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
}
/*
* 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.
*/
VOID
ListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
@ -94,17 +93,14 @@ ListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
if (!entry)
goto unlock;
if (entry == Entry)
{
if (entry == Entry) {
Head->Next = entry->Next;
ImpExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
goto unlock;
}
while (entry->Next)
{
if (entry->Next == Entry)
{
while (entry->Next) {
if (entry->Next == Entry) {
entry->Next = Entry->Next;
ImpExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
goto unlock;
@ -130,17 +126,14 @@ LookasideListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
if (!entry)
goto unlock;
if (entry == Entry)
{
if (entry == Entry) {
Head->Next = entry->Next;
ExFreeToLookasideListEx(&head->lookaside_list, Entry);
goto unlock;
}
while (entry->Next)
{
if (entry->Next == Entry)
{
while (entry->Next) {
if (entry->Next == Entry) {
entry->Next = Entry->Next;
ExFreeToLookasideListEx(&head->lookaside_list, Entry);
goto unlock;
@ -163,8 +156,7 @@ LookasideListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
PTHREAD_LIST_HEAD head = GetThreadList();
BOOLEAN result = FALSE;
if (Head->Next)
{
if (Head->Next) {
PSINGLE_LIST_ENTRY entry = Head->Next;
if (CallbackRoutine)

File diff suppressed because it is too large Load diff

View file

@ -7,16 +7,14 @@
#include "common.h"
#include "queue.h"
typedef struct _APC_OPERATION_ID
{
typedef struct _APC_OPERATION_ID {
int operation_id;
} APC_OPERATION_ID, *PAPC_OPERATION_ID;
/* system modules information */
typedef struct _SYSTEM_MODULES
{
typedef struct _SYSTEM_MODULES {
PVOID address;
INT module_count;
@ -24,16 +22,14 @@ typedef struct _SYSTEM_MODULES
#define APC_CONTEXT_ID_STACKWALK 0x1
typedef struct _APC_CONTEXT_HEADER
{
typedef struct _APC_CONTEXT_HEADER {
LONG context_id;
volatile INT count;
volatile INT allocation_in_progress;
} APC_CONTEXT_HEADER, *PAPC_CONTEXT_HEADER;
typedef struct _APC_STACKWALK_CONTEXT
{
typedef struct _APC_STACKWALK_CONTEXT {
APC_CONTEXT_HEADER header;
PSYSTEM_MODULES modules;
@ -46,7 +42,8 @@ NTSTATUS
HandleValidateDriversIOCTL();
PRTL_MODULE_EXTENDED_INFO
FindSystemModuleByName(_In_ LPCSTR ModuleName, _In_ PSYSTEM_MODULES SystemModules);
FindSystemModuleByName(_In_ LPCSTR ModuleName,
_In_ PSYSTEM_MODULES SystemModules);
NTSTATUS
HandleNmiIOCTL();
@ -66,7 +63,9 @@ IsInstructionPointerInInvalidRegion(_In_ UINT64 RIP,
_Out_ PBOOLEAN Result);
VOID
FlipKThreadMiscFlagsFlag(_In_ PKTHREAD Thread, _In_ ULONG FlagIndex, _In_ BOOLEAN NewValue);
FlipKThreadMiscFlagsFlag(_In_ PKTHREAD Thread,
_In_ ULONG FlagIndex,
_In_ BOOLEAN NewValue);
NTSTATUS
DispatchStackwalkToEachCpuViaDpc();
@ -78,6 +77,7 @@ PVOID
FindDriverBaseNoApi(_In_ PDRIVER_OBJECT DriverObject, _In_ PWCH Name);
NTSTATUS
GetDriverObjectByDriverName(_In_ PUNICODE_STRING DriverName, _Out_ PDRIVER_OBJECT* DriverObject);
GetDriverObjectByDriverName(_In_ PUNICODE_STRING DriverName,
_Out_ PDRIVER_OBJECT* DriverObject);
#endif

View file

@ -45,8 +45,7 @@ CHAR EXECUTIVE_OBJECT_POOL_TAGS[EXECUTIVE_OBJECT_COUNT][POOL_TAG_LENGTH] = {
"\x4C\x69\x6E\x6B" /* Symbolic links */
};
typedef struct _PROCESS_SCAN_CONTEXT
{
typedef struct _PROCESS_SCAN_CONTEXT {
ULONG process_count;
PVOID process_buffer;
@ -54,7 +53,8 @@ typedef struct _PROCESS_SCAN_CONTEXT
STATIC
BOOLEAN
ValidateIfAddressIsProcessStructure(_In_ PVOID Address, _In_ PPOOL_HEADER PoolHeader);
ValidateIfAddressIsProcessStructure(_In_ PVOID Address,
_In_ PPOOL_HEADER PoolHeader);
STATIC
VOID
@ -65,8 +65,9 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
STATIC
BOOLEAN
IsPhysicalAddressInPhysicalMemoryRange(_In_ UINT64 PhysicalAddress,
_In_ PPHYSICAL_MEMORY_RANGE PhysicalMemoryRanges);
IsPhysicalAddressInPhysicalMemoryRange(_In_ UINT64 PhysicalAddress,
_In_ PPHYSICAL_MEMORY_RANGE
PhysicalMemoryRanges);
STATIC
VOID
@ -81,12 +82,13 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context);
STATIC
VOID
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context);
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_Inout_opt_ PVOID Context);
STATIC
VOID
CheckIfProcessAllocationIsInProcessList(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_Inout_opt_ PVOID Context);
CheckIfProcessAllocationIsInProcessList(
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context);
#ifdef ALLOC_PRAGMA
# pragma alloc_text(PAGE, GetGlobalDebuggerData)
@ -110,20 +112,26 @@ GetGlobalDebuggerData()
RtlCaptureContext(&context);
dump_header = ImpExAllocatePool2(POOL_FLAG_NON_PAGED, DUMP_BLOCK_SIZE, POOL_DUMP_BLOCK_TAG);
dump_header = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, DUMP_BLOCK_SIZE, POOL_DUMP_BLOCK_TAG);
if (!dump_header)
goto end;
KeCapturePersistentThreadState(&context, NULL, NULL, NULL, NULL, NULL, NULL, dump_header);
KeCapturePersistentThreadState(
&context, NULL, NULL, NULL, NULL, NULL, NULL, dump_header);
debugger_data = (PKDDEBUGGER_DATA64)ExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(KDDEBUGGER_DATA64), POOL_DEBUGGER_DATA_TAG);
debugger_data =
(PKDDEBUGGER_DATA64)ExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(KDDEBUGGER_DATA64),
POOL_DEBUGGER_DATA_TAG);
if (!debugger_data)
goto end;
RtlCopyMemory(debugger_data, dump_header->KdDebuggerDataBlock, sizeof(KDDEBUGGER_DATA64));
RtlCopyMemory(debugger_data,
dump_header->KdDebuggerDataBlock,
sizeof(KDDEBUGGER_DATA64));
end:
@ -150,12 +158,14 @@ GetPsActiveProcessHead(_Out_ PUINT64 Address)
}
/*
* Here we define a signature that can be used to find EPROCESS structures consistently across
* major windows versions. The fields we test have proven to be consistent in the following study:
* Here we define a signature that can be used to find EPROCESS structures
*consistently across major windows versions. The fields we test have proven to
*be consistent in the following study:
*
* https://www.cise.ufl.edu/~traynor/papers/ccs09b.pdf
*
* Aswell as some of my own additional research and testing. The following signature is used:
* Aswell as some of my own additional research and testing. The following
*signature is used:
*
* PeakVirtualSize must be greater then 0 for any valid process:
* -> EPROCESS->PeakVirtualSize > 0
@ -163,9 +173,11 @@ GetPsActiveProcessHead(_Out_ PUINT64 Address)
* The DirectoryTableBase must be 0x20 aligned:
* -> EPROCESS->DirectoryTableBase % 20 == 0
*
* The pool allocation size must be greater then the size of an EPROCESS allocation and
* less then the size of a page. Allocation size can be found with the following formula:
* -> AllocationSize = POOL_HEADER->BlockSize * CHUNK_SIZE - sizeof(POOL_HEADER)
* The pool allocation size must be greater then the size of an EPROCESS
*allocation and less then the size of a page. Allocation size can be found with
*the following formula:
* -> AllocationSize = POOL_HEADER->BlockSize * CHUNK_SIZE -
*sizeof(POOL_HEADER)
* -> AllocationSize > sizeof(EPROCESS)
* -> AllocationSize < PAGE_SIZE (4096)
*
@ -176,17 +188,20 @@ GetPsActiveProcessHead(_Out_ PUINT64 Address)
* -> EPROCESS->Peb & 0x7ffd0000 == 0x7ffd0000 && EPROCESS->Peb % 0x1000 == 0
*
* The object table must have the following properties and be 0x8 aligned:
* -> EPROCESS->ObjectTable & 0xe0000000 == 0xe0000000 && EPROCESS->ObjectTable % 0x8 == 0
* -> EPROCESS->ObjectTable & 0xe0000000 == 0xe0000000 && EPROCESS->ObjectTable
*% 0x8 == 0
*
* The allocation size, when AND'd with 0xfff0 must not equal 0xfff0:
* -> AllocationSize & 0xfff0 != 0xfff0
*
* This signature will allow us to consistently and accurately determine if a given pool allocation
*is indeed an executive process allocation across major versions of Windows.
* This signature will allow us to consistently and accurately determine if a
*given pool allocation is indeed an executive process allocation across major
*versions of Windows.
*/
STATIC
BOOLEAN
ValidateIfAddressIsProcessStructure(_In_ PVOID Address, _In_ PPOOL_HEADER PoolHeader)
ValidateIfAddressIsProcessStructure(_In_ PVOID Address,
_In_ PPOOL_HEADER PoolHeader)
{
UINT64 peak_virtual_size = 0;
UINT64 dir_table_base = 0;
@ -197,31 +212,42 @@ ValidateIfAddressIsProcessStructure(_In_ PVOID Address, _In_ PPOOL_HEADER PoolHe
BOOLEAN object_table_test = FALSE;
UINT64 allocation_size_test = 0;
if (ImpMmIsAddressValid((UINT64)Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET))
dir_table_base = *(UINT64*)((UINT64)Address + KPROCESS_DIRECTORY_TABLE_BASE_OFFSET);
if (ImpMmIsAddressValid((UINT64)Address +
KPROCESS_DIRECTORY_TABLE_BASE_OFFSET))
dir_table_base =
*(UINT64*)((UINT64)Address +
KPROCESS_DIRECTORY_TABLE_BASE_OFFSET);
if (ImpMmIsAddressValid((UINT64)Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET))
peak_virtual_size = *(UINT64*)((UINT64)Address + EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET);
if (ImpMmIsAddressValid((UINT64)Address +
EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET))
peak_virtual_size =
*(UINT64*)((UINT64)Address +
EPROCESS_PEAK_VIRTUAL_SIZE_OFFSET);
if (ImpMmIsAddressValid((UINT64)PoolHeader + POOL_HEADER_BLOCK_SIZE_OFFSET))
allocation_size = PoolHeader->BlockSize * CHUNK_SIZE - sizeof(POOL_HEADER);
if (ImpMmIsAddressValid((UINT64)PoolHeader +
POOL_HEADER_BLOCK_SIZE_OFFSET))
allocation_size =
PoolHeader->BlockSize * CHUNK_SIZE - sizeof(POOL_HEADER);
if (ImpMmIsAddressValid((UINT64)Address + EPROCESS_PEB_OFFSET))
peb = *(UINT64*)((UINT64)Address + EPROCESS_PEB_OFFSET);
if (ImpMmIsAddressValid((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET))
object_table = *(UINT64*)((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET);
object_table =
*(UINT64*)((UINT64)Address + EPROCESS_OBJECT_TABLE_OFFSET);
peb_test = peb == NULL || (peb & 0x7ffd0000 == 0x7ffd0000 && peb % 0x1000 == NULL);
object_table_test = object_table == NULL ||
(object_table & 0xe0000000 == 0xe0000000 && object_table % 0x8 == 0);
peb_test = peb == NULL ||
(peb & 0x7ffd0000 == 0x7ffd0000 && peb % 0x1000 == NULL);
object_table_test =
object_table == NULL || (object_table & 0xe0000000 == 0xe0000000 &&
object_table % 0x8 == 0);
allocation_size_test = allocation_size & 0xfff0;
if (peak_virtual_size > 0 && (dir_table_base & 0x20) == 0 &&
allocation_size > (EPROCESS_SIZE + OBJECT_HEADER_SIZE + sizeof(POOL_HEADER)) &&
PoolHeader->PoolType != NULL && !(allocation_size_test == 0xfff0) && !peb_test &&
!object_table_test)
{
allocation_size >
(EPROCESS_SIZE + OBJECT_HEADER_SIZE + sizeof(POOL_HEADER)) &&
PoolHeader->PoolType != NULL && !(allocation_size_test == 0xfff0) &&
!peb_test && !object_table_test) {
return TRUE;
}
@ -242,14 +268,16 @@ ValidateIfAddressIsProcessStructure(_In_ PVOID Address, _In_ PPOOL_HEADER PoolHe
*/
/*
* Idea: since we don't know the number of headers or the exact memory layout of the object
* header section for these proc allocations, we can form an estimate address of base + 0x70
* and then iterate the loaded process list and if theres an address within say 0x50 of it we
* can assume that the process is legitmate. Then to find an unlinked process, it wouldn't
* exist in the loaded module list, check that it hasnt been deallocated and then focus on
* scanning it for name etc. Maybe scan for .exe extension?
* Idea: since we don't know the number of headers or the exact memory layout of
* the object header section for these proc allocations, we can form an estimate
* address of base + 0x70 and then iterate the loaded process list and if theres
* an address within say 0x50 of it we can assume that the process is legitmate.
* Then to find an unlinked process, it wouldn't exist in the loaded module
* list, check that it hasnt been deallocated and then focus on scanning it for
* name etc. Maybe scan for .exe extension?
*
* Also use the full name so we get the file extension and path not the 15 char long one
* Also use the full name so we get the file extension and path not the 15 char
* long one
*/
STATIC
VOID
@ -275,44 +303,46 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
if (!PageBase || !PageSize)
return;
for (INT offset = 0; offset <= PageSize - POOL_TAG_LENGTH - minimum_process_allocation_size;
offset++)
{
for (INT sig_index = 0; sig_index < POOL_TAG_LENGTH + 1; sig_index++)
{
for (INT offset = 0; offset <= PageSize - POOL_TAG_LENGTH -
minimum_process_allocation_size;
offset++) {
for (INT sig_index = 0; sig_index < POOL_TAG_LENGTH + 1;
sig_index++) {
if (!ImpMmIsAddressValid(PageBase + offset + sig_index))
break;
current_char = *(PCHAR)(PageBase + offset + sig_index);
current_sig_byte = EXECUTIVE_OBJECT_POOL_TAGS[ObjectIndex][sig_index];
current_char = *(PCHAR)(PageBase + offset + sig_index);
current_sig_byte =
EXECUTIVE_OBJECT_POOL_TAGS[ObjectIndex][sig_index];
if (sig_index == POOL_TAG_LENGTH)
{
pool_header = (UINT64)PageBase + offset - POOL_HEADER_TAG_OFFSET;
if (sig_index == POOL_TAG_LENGTH) {
pool_header = (UINT64)PageBase + offset -
POOL_HEADER_TAG_OFFSET;
if (!ImpMmIsAddressValid((PVOID)pool_header))
break;
/*
* Since every executive allocation is required to have an
* _OBJECT_HEADER, we start iterating from the size of this object
* header, then jump up in blocks of 0x10 since every object header
* is divisible by 0x10. We iterate up to 0xb0 which is equal to the
* following:
* Since every executive allocation is required
* to have an _OBJECT_HEADER, we start iterating
* from the size of this object header, then
* jump up in blocks of 0x10 since every object
* header is divisible by 0x10. We iterate up to
* 0xb0 which is equal to the following:
*
* 0xb0 = sizeof(ALL_HEADER_OBJECTS) + 0x10 where the 0x10 is 16
* bytes of padding.
* 0xb0 = sizeof(ALL_HEADER_OBJECTS) + 0x10
* where the 0x10 is 16 bytes of padding.
*/
for (ULONG header_size = OBJECT_HEADER_SIZE; header_size < 0xb0;
header_size += 0x10)
{
for (ULONG header_size = OBJECT_HEADER_SIZE;
header_size < 0xb0;
header_size += 0x10) {
test_process =
(PEPROCESS)((UINT64)pool_header + sizeof(POOL_HEADER) +
(PEPROCESS)((UINT64)pool_header +
sizeof(POOL_HEADER) +
header_size);
if (ValidateIfAddressIsProcessStructure(test_process,
pool_header))
{
if (ValidateIfAddressIsProcessStructure(
test_process, pool_header)) {
process = test_process;
break;
}
@ -321,15 +351,16 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
if (!process)
break;
DEBUG_VERBOSE("Found process via pt walk: %llx", (UINT64)process);
DEBUG_VERBOSE("Found process via pt walk: %llx",
(UINT64)process);
address_list = (PUINT64)Context->process_buffer;
for (INT i = 0; i < Context->process_count; i++)
{
if (address_list[i] == NULL)
{
address_list[i] = (UINT64)process;
for (INT i = 0; i < Context->process_count;
i++) {
if (address_list[i] == NULL) {
address_list[i] =
(UINT64)process;
break;
}
}
@ -345,26 +376,30 @@ ScanPageForKernelObjectAllocation(_In_ UINT64 PageBase,
/*
* Using MmGetPhysicalMemoryRangesEx2(), we can get a block of structures that
* describe the physical memory layout. With each physical page base we are going
* to enumerate, we want to make sure it lies within an appropriate region of
* physical memory, so this function is to check for exactly that.
* describe the physical memory layout. With each physical page base we are
* going to enumerate, we want to make sure it lies within an appropriate region
* of physical memory, so this function is to check for exactly that.
*/
STATIC
BOOLEAN
IsPhysicalAddressInPhysicalMemoryRange(_In_ UINT64 PhysicalAddress,
_In_ PPHYSICAL_MEMORY_RANGE PhysicalMemoryRanges)
IsPhysicalAddressInPhysicalMemoryRange(_In_ UINT64 PhysicalAddress,
_In_ PPHYSICAL_MEMORY_RANGE
PhysicalMemoryRanges)
{
ULONG page_index = 0;
UINT64 start_address = 0;
UINT64 end_address = 0;
while (PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart != NULL)
{
start_address = PhysicalMemoryRanges[page_index].BaseAddress.QuadPart;
while (PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart !=
NULL) {
start_address =
PhysicalMemoryRanges[page_index].BaseAddress.QuadPart;
end_address =
start_address + PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart;
start_address +
PhysicalMemoryRanges[page_index].NumberOfBytes.QuadPart;
if (PhysicalAddress >= start_address && PhysicalAddress <= end_address)
if (PhysicalAddress >= start_address &&
PhysicalAddress <= end_address)
return TRUE;
page_index++;
@ -383,35 +418,38 @@ EnumerateKernelLargePages(_In_ UINT64 PageBase,
/*
* Split the large pages up into blocks of 0x1000 and scan each block
*/
for (UINT64 page_index = 0; page_index < PageSize; page_index++)
{
for (UINT64 page_index = 0; page_index < PageSize; page_index++) {
UINT64 page_base = PageBase + (page_index * PAGE_SIZE);
ScanPageForKernelObjectAllocation(
PageBase + (page_index * PAGE_SIZE), PAGE_SIZE, ObjectIndex, Context);
page_base, PAGE_SIZE, ObjectIndex, Context);
}
}
/*
* This is your basic page table walk function. On intel systems, paging has 4 levels,
* each table holds 512 entries with a total size of 0x1000 (512 * sizeof(QWORD)). Each entry
* in each table contains a value with a subset bitfield containing the physical address
* of the base of the next table in the structure. So for example, a PML4 entry contains
* a physical address that points to the base of the PDPT table, it is the same for a PDPT
* entry -> PD base and so on.
* This is your basic page table walk function. On intel systems, paging has 4
* levels, each table holds 512 entries with a total size of 0x1000 (512 *
* sizeof(QWORD)). Each entry in each table contains a value with a subset
* bitfield containing the physical address of the base of the next table in the
* structure. So for example, a PML4 entry contains a physical address that
* points to the base of the PDPT table, it is the same for a PDPT entry -> PD
* base and so on.
*
* However, as with all good things Windows has implemented security features meaning
* we cannot use functions such as MmCopyMemory or MmMapIoSpace on paging structures,
* so we must find another way to walk the pages. Luckily for us, there exists
* MmGetVirtualForPhysical. This function is self explanatory and returns the corresponding
* virtual address given a physical address. What this means is that we can extract a page
* entry physical address, pass it to MmGetVirtualForPhysical which returns us the virtual
* address of the base of the next page structure. This is because page tables are still
* mapped by the kernel and exist in virtual memory just like everything else and hence
* reading the value at all 512 entries from the virtual base will give us the equivalent
* value as directly reading the physical address.
* However, as with all good things Windows has implemented security features
* meaning we cannot use functions such as MmCopyMemory or MmMapIoSpace on
* paging structures, so we must find another way to walk the pages. Luckily for
* us, there exists MmGetVirtualForPhysical. This function is self explanatory
* and returns the corresponding virtual address given a physical address. What
* this means is that we can extract a page entry physical address, pass it to
* MmGetVirtualForPhysical which returns us the virtual address of the base of
* the next page structure. This is because page tables are still mapped by the
* kernel and exist in virtual memory just like everything else and hence
* reading the value at all 512 entries from the virtual base will give us the
* equivalent value as directly reading the physical address.
*
* Using this, we essentially walk the page tables as any regular translation would
* except instead of simply reading the physical we translate it to a virtual address
* and extract the physical address from the value at each virtual address page entry.
* Using this, we essentially walk the page tables as any regular translation
* would except instead of simply reading the physical we translate it to a
* virtual address and extract the physical address from the value at each
* virtual address page entry.
*
* TODO: rewrite this its kinda ugly
*/
@ -440,9 +478,9 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
physical_memory_ranges = ImpMmGetPhysicalMemoryRangesEx2(NULL, NULL);
if (!physical_memory_ranges)
{
DEBUG_ERROR("MmGetPhysicalMemoryRangesEx2 failed with no status.");
if (!physical_memory_ranges) {
DEBUG_ERROR(
"MmGetPhysicalMemoryRangesEx2 failed with no status.");
return;
}
@ -455,108 +493,127 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
if (!ImpMmIsAddressValid(pml4_base.BitAddress) || !pml4_base.BitAddress)
return;
for (INT pml4_index = 0; pml4_index < PML4_ENTRY_COUNT; pml4_index++)
{
if (!ImpMmIsAddressValid(pml4_base.BitAddress + pml4_index * sizeof(UINT64)))
for (INT pml4_index = 0; pml4_index < PML4_ENTRY_COUNT; pml4_index++) {
if (!ImpMmIsAddressValid(pml4_base.BitAddress +
pml4_index * sizeof(UINT64)))
continue;
pml4_entry.BitAddress =
*(UINT64*)(pml4_base.BitAddress + pml4_index * sizeof(UINT64));
pml4_entry.BitAddress = *(UINT64*)(pml4_base.BitAddress +
pml4_index * sizeof(UINT64));
if (pml4_entry.Bits.Present == NULL)
continue;
physical.QuadPart = pml4_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
physical.QuadPart = pml4_entry.Bits.PhysicalAddress
<< PAGE_4KB_SHIFT;
pdpt_base = ImpMmGetVirtualForPhysical(physical);
if (!pdpt_base || !ImpMmIsAddressValid(pdpt_base))
continue;
for (INT pdpt_index = 0; pdpt_index < PDPT_ENTRY_COUNT; pdpt_index++)
{
if (!ImpMmIsAddressValid(pdpt_base + pdpt_index * sizeof(UINT64)))
for (INT pdpt_index = 0; pdpt_index < PDPT_ENTRY_COUNT;
pdpt_index++) {
if (!ImpMmIsAddressValid(pdpt_base +
pdpt_index * sizeof(UINT64)))
continue;
pdpt_entry.BitAddress = *(UINT64*)(pdpt_base + pdpt_index * sizeof(UINT64));
pdpt_entry.BitAddress =
*(UINT64*)(pdpt_base + pdpt_index * sizeof(UINT64));
if (pdpt_entry.Bits.Present == NULL)
continue;
if (IS_LARGE_PAGE(pdpt_entry.BitAddress))
{
if (IS_LARGE_PAGE(pdpt_entry.BitAddress)) {
/* 1gb size page */
pdpt_large_entry.BitAddress = pdpt_entry.BitAddress;
pdpt_large_entry.BitAddress =
pdpt_entry.BitAddress;
physical.QuadPart = pdpt_large_entry.Bits.PhysicalAddress
<< PAGE_1GB_SHIFT;
physical.QuadPart =
pdpt_large_entry.Bits.PhysicalAddress
<< PAGE_1GB_SHIFT;
if (IsPhysicalAddressInPhysicalMemoryRange(
physical.QuadPart, physical_memory_ranges) == FALSE)
physical.QuadPart,
physical_memory_ranges) == FALSE)
continue;
base_1gb_virtual_page = ImpMmGetVirtualForPhysical(physical);
base_1gb_virtual_page =
ImpMmGetVirtualForPhysical(physical);
if (!base_1gb_virtual_page ||
!ImpMmIsAddressValid(base_1gb_virtual_page))
continue;
EnumerateKernelLargePages(base_1gb_virtual_page,
LARGE_PAGE_1GB_ENTRIES,
Context,
INDEX_PROCESS_POOL_TAG);
EnumerateKernelLargePages(
base_1gb_virtual_page,
LARGE_PAGE_1GB_ENTRIES,
Context,
INDEX_PROCESS_POOL_TAG);
continue;
}
physical.QuadPart = pdpt_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
physical.QuadPart = pdpt_entry.Bits.PhysicalAddress
<< PAGE_4KB_SHIFT;
pd_base = ImpMmGetVirtualForPhysical(physical);
if (!pd_base || !ImpMmIsAddressValid(pd_base))
continue;
for (INT pd_index = 0; pd_index < PD_ENTRY_COUNT; pd_index++)
{
if (!ImpMmIsAddressValid(pd_base + pd_index * sizeof(UINT64)))
for (INT pd_index = 0; pd_index < PD_ENTRY_COUNT;
pd_index++) {
if (!ImpMmIsAddressValid(
pd_base + pd_index * sizeof(UINT64)))
continue;
pd_entry.BitAddress =
*(UINT64*)(pd_base + pd_index * sizeof(UINT64));
*(UINT64*)(pd_base +
pd_index * sizeof(UINT64));
if (pd_entry.Bits.Present == NULL)
continue;
if (IS_LARGE_PAGE(pd_entry.BitAddress))
{
if (IS_LARGE_PAGE(pd_entry.BitAddress)) {
/* 2MB size page */
pd_large_entry.BitAddress = pd_entry.BitAddress;
pd_large_entry.BitAddress =
pd_entry.BitAddress;
physical.QuadPart = pd_large_entry.Bits.PhysicalAddress
<< PAGE_2MB_SHIFT;
physical.QuadPart =
pd_large_entry.Bits.PhysicalAddress
<< PAGE_2MB_SHIFT;
if (IsPhysicalAddressInPhysicalMemoryRange(
physical.QuadPart, physical_memory_ranges) == FALSE)
physical.QuadPart,
physical_memory_ranges) ==
FALSE)
continue;
base_2mb_virtual_page =
ImpMmGetVirtualForPhysical(physical);
ImpMmGetVirtualForPhysical(
physical);
if (!base_2mb_virtual_page ||
!ImpMmIsAddressValid(base_2mb_virtual_page))
!ImpMmIsAddressValid(
base_2mb_virtual_page))
continue;
EnumerateKernelLargePages(base_2mb_virtual_page,
LARGE_PAGE_2MB_ENTRIES,
Context,
INDEX_PROCESS_POOL_TAG);
EnumerateKernelLargePages(
base_2mb_virtual_page,
LARGE_PAGE_2MB_ENTRIES,
Context,
INDEX_PROCESS_POOL_TAG);
continue;
}
physical.QuadPart = pd_entry.Bits.PhysicalAddress << PAGE_4KB_SHIFT;
physical.QuadPart =
pd_entry.Bits.PhysicalAddress
<< PAGE_4KB_SHIFT;
if (!ImpMmIsAddressValid(pd_base + pd_index * sizeof(UINT64)))
if (!ImpMmIsAddressValid(
pd_base + pd_index * sizeof(UINT64)))
continue;
pt_base = ImpMmGetVirtualForPhysical(physical);
@ -564,37 +621,49 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
if (!pt_base || !ImpMmIsAddressValid(pt_base))
continue;
for (INT pt_index = 0; pt_index < PT_ENTRY_COUNT; pt_index++)
{
if (!ImpMmIsAddressValid(pt_base +
pt_index * sizeof(UINT64)))
for (INT pt_index = 0;
pt_index < PT_ENTRY_COUNT;
pt_index++) {
if (!ImpMmIsAddressValid(
pt_base +
pt_index * sizeof(UINT64)))
continue;
pt_entry.BitAddress =
*(UINT64*)(pt_base + pt_index * sizeof(UINT64));
pt_entry.BitAddress = *(
UINT64*)(pt_base +
pt_index * sizeof(UINT64));
if (pt_entry.Bits.Present == NULL)
continue;
physical.QuadPart = pt_entry.Bits.PhysicalAddress
<< PAGE_4KB_SHIFT;
physical.QuadPart =
pt_entry.Bits.PhysicalAddress
<< PAGE_4KB_SHIFT;
/* if the page base isnt in a legit region, go next */
/* if the page base isnt in a legit
* region, go next */
if (IsPhysicalAddressInPhysicalMemoryRange(
physical.QuadPart, physical_memory_ranges) == FALSE)
physical.QuadPart,
physical_memory_ranges) ==
FALSE)
continue;
base_virtual_page = ImpMmGetVirtualForPhysical(physical);
base_virtual_page =
ImpMmGetVirtualForPhysical(
physical);
/* stupid fucking intellisense error GO AWAY! */
/* stupid fucking intellisense error GO
* AWAY! */
if (base_virtual_page == NULL ||
!ImpMmIsAddressValid(base_virtual_page))
!ImpMmIsAddressValid(
base_virtual_page))
continue;
ScanPageForKernelObjectAllocation(base_virtual_page,
PAGE_BASE_SIZE,
INDEX_PROCESS_POOL_TAG,
Context);
ScanPageForKernelObjectAllocation(
base_virtual_page,
PAGE_BASE_SIZE,
INDEX_PROCESS_POOL_TAG,
Context);
}
}
}
@ -605,7 +674,8 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
STATIC
VOID
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context)
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_Inout_opt_ PVOID Context)
{
PAGED_CODE();
@ -621,35 +691,36 @@ IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ P
STATIC
VOID
CheckIfProcessAllocationIsInProcessList(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_Inout_opt_ PVOID Context)
CheckIfProcessAllocationIsInProcessList(
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context)
{
PAGED_CODE();
PUINT64 allocation_address = NULL;
PPROCESS_SCAN_CONTEXT context = (PPROCESS_SCAN_CONTEXT)Context;
PPROCESS_SCAN_CONTEXT context = (PPROCESS_SCAN_CONTEXT)Context;
if (!context)
return;
for (INT i = 0; i < context->process_count; i++)
{
for (INT i = 0; i < context->process_count; i++) {
allocation_address = (PUINT64)context->process_buffer;
if ((UINT64)ProcessListEntry->process >=
allocation_address[i] - PROCESS_OBJECT_ALLOCATION_MARGIN &&
allocation_address[i] -
PROCESS_OBJECT_ALLOCATION_MARGIN &&
(UINT64)ProcessListEntry->process <=
allocation_address[i] + PROCESS_OBJECT_ALLOCATION_MARGIN)
{
RtlZeroMemory((UINT64)context->process_buffer + i * sizeof(UINT64),
allocation_address[i] +
PROCESS_OBJECT_ALLOCATION_MARGIN) {
RtlZeroMemory((UINT64)context->process_buffer +
i * sizeof(UINT64),
sizeof(UINT64));
}
}
}
/*
* This is actually broken right now since changing to use our process list, will need to fix at
* somepoint.
* This is actually broken right now since changing to use our process list,
* will need to fix at somepoint.
*/
NTSTATUS
FindUnlinkedProcesses()
@ -660,58 +731,66 @@ FindUnlinkedProcesses()
PROCESS_SCAN_CONTEXT context = {0};
PINVALID_PROCESS_ALLOCATION_REPORT report_buffer = NULL;
EnumerateProcessListWithCallbackRoutine(IncrementProcessCounter, &context);
EnumerateProcessListWithCallbackRoutine(IncrementProcessCounter,
&context);
if (context.process_count == 0)
{
if (context.process_count == 0) {
DEBUG_ERROR("IncrementProcessCounter failed with no status.");
return STATUS_ABANDONED;
}
context.process_buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED,
context.process_count * 2 * sizeof(UINT64),
PROCESS_ADDRESS_LIST_TAG);
context.process_buffer =
ExAllocatePool2(POOL_FLAG_NON_PAGED,
context.process_count * 2 * sizeof(UINT64),
PROCESS_ADDRESS_LIST_TAG);
if (!context.process_buffer)
return STATUS_MEMORY_NOT_ALLOCATED;
WalkKernelPageTables(&context);
EnumerateProcessListWithCallbackRoutine(CheckIfProcessAllocationIsInProcessList, &context);
EnumerateProcessListWithCallbackRoutine(
CheckIfProcessAllocationIsInProcessList, &context);
allocation_address = (PUINT64)context.process_buffer;
for (INT index = 0; index < context.process_count; index++)
{
for (INT index = 0; index < context.process_count; index++) {
if (allocation_address[index] == NULL)
continue;
UINT64 allocation = (UINT64)allocation_address[index] - OBJECT_HEADER_SIZE;
UINT64 allocation =
(UINT64)allocation_address[index] - OBJECT_HEADER_SIZE;
/*
* It's important to remember that at this point it is still not guaranteed that we
* have found an unlinked process allocation. It is better to have a few false
* positives that can be later analysed rather then enforce a strict signature and
* It's important to remember that at this point it is still not
* guaranteed that we have found an unlinked process allocation.
* It is better to have a few false positives that can be later
* analysed rather then enforce a strict signature and
* potentially miss a real unlinked process.
*/
DEBUG_WARNING("Potentially found an unlinked process allocation at address: %llx",
allocation);
DEBUG_WARNING(
"Potentially found an unlinked process allocation at address: %llx",
allocation);
report_buffer = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
POOL_FLAG_NON_PAGED,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT),
REPORT_POOL_TAG);
if (!report_buffer)
continue;
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
RtlCopyMemory(
report_buffer->process, allocation, REPORT_INVALID_PROCESS_BUFFER_SIZE);
RtlCopyMemory(report_buffer->process,
allocation,
REPORT_INVALID_PROCESS_BUFFER_SIZE);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report_buffer,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
if (!NT_SUCCESS(IrpQueueCompleteIrp(
report_buffer,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT)))) {
DEBUG_ERROR(
"IrpQueueCompleteIrp failed with no status.");
continue;
}
}
@ -719,14 +798,15 @@ FindUnlinkedProcesses()
end:
if (context.process_buffer)
ImpExFreePoolWithTag(context.process_buffer, PROCESS_ADDRESS_LIST_TAG);
ImpExFreePoolWithTag(context.process_buffer,
PROCESS_ADDRESS_LIST_TAG);
return STATUS_SUCCESS;
}
/*
* Allocations greater then a page in size are stored in a linked list and are called
* big pool allocations.
* Allocations greater then a page in size are stored in a linked list and are
* called big pool allocations.
*/
NTSTATUS
@ -737,11 +817,12 @@ EnumerateBigPoolAllocations()
PSYSTEM_BIGPOOL_ENTRY entry = NULL;
SYSTEM_BIGPOOL_INFORMATION pool_information = {0};
PSYSTEM_BIGPOOL_INFORMATION pool_entries = NULL;
UNICODE_STRING routine = RTL_CONSTANT_STRING(L"ZwQuerySystemInformation");
ZwQuerySystemInformation pZwQuerySystemInformation = ImpMmGetSystemRoutineAddress(&routine);
UNICODE_STRING routine =
RTL_CONSTANT_STRING(L"ZwQuerySystemInformation");
ZwQuerySystemInformation pZwQuerySystemInformation =
ImpMmGetSystemRoutineAddress(&routine);
if (!pZwQuerySystemInformation)
{
if (!pZwQuerySystemInformation) {
DEBUG_ERROR("MmGetSystemRoutineAddress failed with no status.");
return status;
}
@ -751,30 +832,32 @@ EnumerateBigPoolAllocations()
sizeof(pool_information),
&return_length);
if (status != STATUS_INFO_LENGTH_MISMATCH)
{
DEBUG_ERROR("ZwQuerySystemInformation failed with status %x", status);
if (status != STATUS_INFO_LENGTH_MISMATCH) {
DEBUG_ERROR("ZwQuerySystemInformation failed with status %x",
status);
return status;
}
return_length += sizeof(SYSTEM_BIGPOOL_INFORMATION);
pool_entries = ImpExAllocatePool2(POOL_FLAG_NON_PAGED, return_length, POOL_TAG_INTEGRITY);
pool_entries = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, return_length, POOL_TAG_INTEGRITY);
if (!pool_entries)
return STATUS_MEMORY_NOT_ALLOCATED;
status = pZwQuerySystemInformation(
SYSTEM_BIGPOOL_INFORMATION_ID, pool_entries, return_length, &return_length);
status = pZwQuerySystemInformation(SYSTEM_BIGPOOL_INFORMATION_ID,
pool_entries,
return_length,
&return_length);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ZwQuerySystemInformation 2 failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ZwQuerySystemInformation 2 failed with status %x",
status);
goto end;
}
for (INT index = 0; index < pool_entries->Count; index++)
{
for (INT index = 0; index < pool_entries->Count; index++) {
entry = &pool_entries->AllocatedInfo[index];
}
// MiGetPteAddress of va

View file

@ -16,7 +16,8 @@ QueuePush(_Inout_ PQUEUE_HEAD Head, _In_ PVOID Data)
{
ImpKeAcquireGuardedMutex(&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;

View file

@ -6,8 +6,7 @@
#define MAX_REPORTS_PER_IRP 20
typedef struct QUEUE_HEAD
{
typedef struct QUEUE_HEAD {
struct _QUEUE_NODE* start;
struct _QUEUE_NODE* end;
KGUARDED_MUTEX lock;
@ -23,29 +22,25 @@ typedef struct QUEUE_HEAD
* can be pushed into the queue before the next iteration can take ownership
* of the spinlock.
*/
typedef struct _REPORT_QUEUE_HEAD
{
typedef struct _REPORT_QUEUE_HEAD {
QUEUE_HEAD head;
volatile BOOLEAN is_driver_unloading;
KGUARDED_MUTEX lock;
} REPORT_QUEUE_HEAD, *PREPORT_QUEUE_HEAD;
typedef struct _QUEUE_NODE
{
typedef struct _QUEUE_NODE {
struct _QUEUE_NODE* next;
PVOID data;
} QUEUE_NODE, *PQUEUE_NODE;
typedef struct _GLOBAL_REPORT_QUEUE_HEADER
{
typedef struct _GLOBAL_REPORT_QUEUE_HEADER {
INT count;
} GLOBAL_REPORT_QUEUE_HEADER, *PGLOBAL_REPORT_QUEUE_HEADER;
typedef struct _REPORT_HEADER
{
typedef struct _REPORT_HEADER {
INT report_id;
} REPORT_HEADER, *PREPORT_HEADER;

View file

@ -4,8 +4,7 @@
/* for now, lets just xor the aes key with our cookie */
typedef struct _SESSION_INITIATION_PACKET
{
typedef struct _SESSION_INITIATION_PACKET {
UINT32 session_cookie;
CHAR session_aes_key[AES_128_KEY_SIZE];
PVOID protected_process_id;
@ -54,7 +53,8 @@ SessionGetProcessId(_Out_ PLONG ProcessId)
}
VOID
SessionGetCallbackConfiguration(_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration)
SessionGetCallbackConfiguration(
_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration)
{
ImpKeAcquireGuardedMutex(&GetActiveSession()->lock);
*CallbackConfiguration = &GetActiveSession()->callback_configuration;
@ -91,13 +91,14 @@ SessionInitialise(_In_ PIRP Irp)
status = ValidateIrpInputBuffer(Irp, sizeof(SESSION_INITIATION_PACKET));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x", status);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x",
status);
return status;
}
information = (PSESSION_INITIATION_PACKET)Irp->AssociatedIrp.SystemBuffer;
information =
(PSESSION_INITIATION_PACKET)Irp->AssociatedIrp.SystemBuffer;
ImpKeAcquireGuardedMutex(&session->lock);
@ -106,8 +107,7 @@ SessionInitialise(_In_ PIRP Irp)
/* What if we pass an invalid handle here? not good. */
status = ImpPsLookupProcessByProcessId(session->um_handle, &process);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
status = STATUS_INVALID_PARAMETER;
goto end;
}
@ -116,7 +116,9 @@ SessionInitialise(_In_ PIRP Irp)
session->process = process;
session->is_session_active = TRUE;
session->session_cookie = information->session_cookie;
RtlCopyMemory(session->session_aes_key, information->session_aes_key, AES_128_KEY_SIZE);
RtlCopyMemory(session->session_aes_key,
information->session_aes_key,
AES_128_KEY_SIZE);
end:
ImpKeReleaseGuardedMutex(&session->lock);
@ -133,20 +135,21 @@ SessionTerminateProcess()
SessionGetProcessId(&process_id);
if (!process_id)
{
DEBUG_ERROR("Failed to terminate process as process id is null");
if (!process_id) {
DEBUG_ERROR(
"Failed to terminate process as process id is null");
return;
}
/* Make sure we pass a km handle to ZwTerminateProcess and NOT a usermode handle. */
status = ZwTerminateProcess(process_id, STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION);
/* Make sure we pass a km handle to ZwTerminateProcess and NOT a
* usermode handle. */
status = ZwTerminateProcess(process_id,
STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
/*
* We don't want to clear the process config if ZwTerminateProcess fails
* so we can try again.
* We don't want to clear the process config if
* ZwTerminateProcess fails so we can try again.
*/
DEBUG_ERROR("ZwTerminateProcess failed with status %x", status);
return;

View file

@ -21,7 +21,8 @@ VOID
SessionGetProcessId(_Out_ PLONG ProcessId);
VOID
SessionGetCallbackConfiguration(_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration);
SessionGetCallbackConfiguration(
_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration);
VOID
SessionTerminate();

View file

@ -29,28 +29,30 @@ ValidateThreadsPspCidTableEntry(_In_ PETHREAD Thread)
thread_id = ImpPsGetThreadId(Thread);
/*
* For each core on the processor, the first x threads equal to x cores will be assigned a
* cid equal to its equivalent core. These threads are generally executing the HLT
* instruction or some other boring stuff while the processor is not busy. The reason this
* is important is because passing in a handle value of 0 which, even though is a valid cid,
* returns a non success status meaning we mark it an invalid cid entry even though it is.
* To combat this we simply add a little check here. The problem is this can be easily
* bypassed by simply modifying the ETHREAD->Cid.UniqueThread identifier.. So while it isnt
* For each core on the processor, the first x threads equal to x cores
* will be assigned a cid equal to its equivalent core. These threads
* are generally executing the HLT instruction or some other boring
* stuff while the processor is not busy. The reason this is important
* is because passing in a handle value of 0 which, even though is a
* valid cid, returns a non success status meaning we mark it an invalid
* cid entry even though it is. To combat this we simply add a little
* check here. The problem is this can be easily bypassed by simply
* modifying the ETHREAD->Cid.UniqueThread identifier.. So while it isnt
* a perfect detection method for now it's good enough.
*/
if ((UINT64)thread_id < (UINT64)ImpKeQueryActiveProcessorCount(NULL))
return TRUE;
/*
* PsLookupThreadByThreadId will use a threads id to find its cid entry, and return
* the pointer contained in the HANDLE_TABLE entry pointing to the thread object.
* Meaning if we pass a valid thread id which we retrieved above and dont receive a
* STATUS_SUCCESS the cid entry could potentially be removed or disrupted..
* PsLookupThreadByThreadId will use a threads id to find its cid entry,
* and return the pointer contained in the HANDLE_TABLE entry pointing
* to the thread object. Meaning if we pass a valid thread id which we
* retrieved above and dont receive a STATUS_SUCCESS the cid entry could
* potentially be removed or disrupted..
*/
status = ImpPsLookupThreadByThreadId(thread_id, &thread);
if (!NT_SUCCESS(status))
{
if (!NT_SUCCESS(status)) {
DEBUG_WARNING(
"Failed to lookup thread by id. PspCidTable entry potentially removed.");
return FALSE;
@ -60,17 +62,18 @@ ValidateThreadsPspCidTableEntry(_In_ PETHREAD Thread)
}
/*
* I did not reverse this myself and previously had no idea how you would go about
* detecting KiAttachProcess so credits to KANKOSHEV for the find:
* I did not reverse this myself and previously had no idea how you would go
* about detecting KiAttachProcess so credits to KANKOSHEV for the find:
*
* 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.
* 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.
*/
STATIC VOID
DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
@ -86,32 +89,37 @@ DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
if (!protected_process)
return;
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread + KTHREAD_APC_STATE_OFFSET);
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread +
KTHREAD_APC_STATE_OFFSET);
/*
* We don't care if a thread owned by our protected process is attached
*
* todo: this is filterless and will just report anything, need to have a look into what
* processes actually attach to real games
* todo: this is filterless and will just report anything, need to have
* a look into what processes actually attach to real games
*/
if (apc_state->Process == protected_process &&
ThreadListEntry->owning_process != protected_process)
{
DEBUG_WARNING("Thread is attached to our protected process: %llx",
(UINT64)ThreadListEntry->thread);
ThreadListEntry->owning_process != protected_process) {
DEBUG_WARNING(
"Thread is attached to our protected process: %llx",
(UINT64)ThreadListEntry->thread);
PATTACH_PROCESS_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);
PATTACH_PROCESS_REPORT report =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(ATTACH_PROCESS_REPORT),
REPORT_POOL_TAG);
if (!report)
return;
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
report->thread_id = ImpPsGetThreadId(ThreadListEntry->thread);
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
report->thread_id = ImpPsGetThreadId(ThreadListEntry->thread);
report->thread_address = ThreadListEntry->thread;
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(ATTACH_PROCESS_REPORT))))
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
if (!NT_SUCCESS(IrpQueueCompleteIrp(
report, sizeof(ATTACH_PROCESS_REPORT))))
DEBUG_ERROR(
"IrpQueueCompleteIrp failed with no status.");
}
}
@ -120,5 +128,6 @@ DetectThreadsAttachedToProtectedProcess()
{
PAGED_CODE();
DEBUG_VERBOSE("Detecting threads attached to our process...");
EnumerateThreadListWithCallbackRoutine(DetectAttachedThreadsProcessCallback, NULL);
EnumerateThreadListWithCallbackRoutine(
DetectAttachedThreadsProcessCallback, NULL);
}