mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
80 line limit - need to refactor lots of code but ceebs atm
This commit is contained in:
parent
4037283f59
commit
c3e0dc65b0
23 changed files with 2961 additions and 2493 deletions
|
@ -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
|
93
driver/apc.c
93
driver/apc.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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,
|
||||
|
|
437
driver/common.h
437
driver/common.h
|
@ -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;
|
||||
|
|
|
@ -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(¤t_block, &Array[block_index * block_size], sizeof(__m256i));
|
||||
RtlCopyMemory(¤t_block,
|
||||
&Array[block_index * block_size],
|
||||
sizeof(__m256i));
|
||||
|
||||
load_block = _mm256_loadu_si256(¤t_block);
|
||||
xored_block = _mm256_xor_si256(load_block, CryptGenerateSseXorKey());
|
||||
load_block = _mm256_loadu_si256(¤t_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
332
driver/driver.c
332
driver/driver.c
|
@ -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;
|
||||
|
|
43
driver/hv.c
43
driver/hv.c
|
@ -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;
|
||||
}
|
155
driver/hw.c
155
driver/hw.c
|
@ -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;
|
||||
}
|
563
driver/imports.c
563
driver/imports.c
File diff suppressed because it is too large
Load diff
1062
driver/integrity.c
1062
driver/integrity.c
File diff suppressed because it is too large
Load diff
|
@ -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,
|
||||
|
|
418
driver/io.c
418
driver/io.c
|
@ -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;
|
||||
|
|
12
driver/io.h
12
driver/io.h
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
1039
driver/modules.c
1039
driver/modules.c
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
519
driver/pool.c
519
driver/pool.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -21,7 +21,8 @@ VOID
|
|||
SessionGetProcessId(_Out_ PLONG ProcessId);
|
||||
|
||||
VOID
|
||||
SessionGetCallbackConfiguration(_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration);
|
||||
SessionGetCallbackConfiguration(
|
||||
_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration);
|
||||
|
||||
VOID
|
||||
SessionTerminate();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue