Rewrite IO handling (#6)

* csq stuff

* oh yea

* bugfix

* epicc

* some formating n dat

* bug fix

* class changes

* e

* fix up some of the io stuff

* fix io PLEASEEE

* fff
This commit is contained in:
donnaskiez 2024-01-21 18:22:06 +11:00 committed by GitHub
parent 44d026bb88
commit 85c6fd6665
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 2098 additions and 3275 deletions

View file

@ -1,131 +1,4 @@
Language: Cpp
BasedOnStyle: webkit
AccessModifierOffset: -4
---
BasedOnStyle: LLVM
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true #false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: false
AllowAllParametersOfDeclarationOnNextLine: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakStringLiterals: false
ColumnLimit: 100
CommentPragmas: '^begin_wpp|^end_wpp|^FUNC |^USESUFFIX |^USESUFFIX '
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 8
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MacroBlockBegin: '^BEGIN_MODULE$|^BEGIN_TEST_CLASS$|^BEGIN_TEST_METHOD$'
MacroBlockEnd: '^END_MODULE$|^END_TEST_CLASS$|^END_TEST_METHOD$'
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None #All
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros: [
'EXTERN_C',
'PAGED',
'PAGEDX',
'NONPAGED',
'PNPCODE',
'INITCODE',
'_At_',
'_When_',
'_Success_',
'_Check_return_',
'_Must_inspect_result_',
'_IRQL_requires_same_',
'_IRQL_requires_',
'_IRQL_requires_max_',
'_IRQL_requires_min_',
'_IRQL_saves_',
'_IRQL_restores_',
'_IRQL_saves_global_',
'_IRQL_restores_global_',
'_IRQL_raises_',
'_IRQL_lowers_',
'_Acquires_lock_',
'_Releases_lock_',
'_Acquires_exclusive_lock_',
'_Releases_exclusive_lock_',
'_Acquires_shared_lock_',
'_Releases_shared_lock_',
'_Requires_lock_held_',
'_Use_decl_annotations_',
'_Guarded_by_',
'__drv_preferredFunction',
'__drv_allocatesMem',
'__drv_freesMem',
]
TabWidth: '8'
UseTab: Never
...

131
.clang-format-c Normal file
View file

@ -0,0 +1,131 @@
Language: Cpp
BasedOnStyle: webkit
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true #false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: false
AllowAllParametersOfDeclarationOnNextLine: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakStringLiterals: false
ColumnLimit: 100
CommentPragmas: '^begin_wpp|^end_wpp|^FUNC |^USESUFFIX |^USESUFFIX '
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 8
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
MacroBlockBegin: '^BEGIN_MODULE$|^BEGIN_TEST_CLASS$|^BEGIN_TEST_METHOD$'
MacroBlockEnd: '^END_MODULE$|^END_TEST_CLASS$|^END_TEST_METHOD$'
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None #All
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros: [
'EXTERN_C',
'PAGED',
'PAGEDX',
'NONPAGED',
'PNPCODE',
'INITCODE',
'_At_',
'_When_',
'_Success_',
'_Check_return_',
'_Must_inspect_result_',
'_IRQL_requires_same_',
'_IRQL_requires_',
'_IRQL_requires_max_',
'_IRQL_requires_min_',
'_IRQL_saves_',
'_IRQL_restores_',
'_IRQL_saves_global_',
'_IRQL_restores_global_',
'_IRQL_raises_',
'_IRQL_lowers_',
'_Acquires_lock_',
'_Releases_lock_',
'_Acquires_exclusive_lock_',
'_Releases_exclusive_lock_',
'_Acquires_shared_lock_',
'_Releases_shared_lock_',
'_Requires_lock_held_',
'_Use_decl_annotations_',
'_Guarded_by_',
'__drv_preferredFunction',
'__drv_allocatesMem',
'__drv_freesMem',
]
TabWidth: '8'
UseTab: Never

68
ac.sln
View file

@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33502.453
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "user", "user\user.vcxproj", "{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver\driver.vcxproj", "{0AE83EC6-DDEA-4EDE-B1B2-1B2AB1E8BB54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "service", "service\service.csproj", "{6228E9DD-E1EA-45D8-8054-A00FC2D63414}"
@ -13,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server", "server\server.csp
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdrv", "test\driver\testdrv.vcxproj", "{3CE9C9B1-1FB1-4770-ABBB-EE4E6AA949B0}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "module", "module\module.vcxproj", "{3B18467A-4358-45EF-81B1-5C6F9B0B6728}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -33,38 +33,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|Any CPU.ActiveCfg = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|Any CPU.Build.0 = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|ARM64.ActiveCfg = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|ARM64.Build.0 = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|x64.ActiveCfg = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|x64.Build.0 = Debug|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|x86.ActiveCfg = Debug|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Debug|x86.Build.0 = Debug|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|Any CPU.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|Any CPU.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|ARM64.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|ARM64.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|x64.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|x64.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|x86.ActiveCfg = Release - No Server|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win10|x86.Build.0 = Release - No Server|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|Any CPU.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|Any CPU.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|ARM64.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|ARM64.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|x64.ActiveCfg = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|x64.Build.0 = Release - No Server|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|x86.ActiveCfg = Release - No Server|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release - No Server - Win11|x86.Build.0 = Release - No Server|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|Any CPU.ActiveCfg = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|Any CPU.Build.0 = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|ARM64.ActiveCfg = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|ARM64.Build.0 = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|x64.ActiveCfg = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|x64.Build.0 = Release|x64
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|x86.ActiveCfg = Release|Win32
{3C8194C7-9F20-4FF8-8C4C-B26C3D053611}.Release|x86.Build.0 = Release|Win32
{0AE83EC6-DDEA-4EDE-B1B2-1B2AB1E8BB54}.Debug|Any CPU.ActiveCfg = Debug|x64
{0AE83EC6-DDEA-4EDE-B1B2-1B2AB1E8BB54}.Debug|Any CPU.Build.0 = Debug|x64
{0AE83EC6-DDEA-4EDE-B1B2-1B2AB1E8BB54}.Debug|Any CPU.Deploy.0 = Debug|x64
@ -225,6 +193,38 @@ Global
{3CE9C9B1-1FB1-4770-ABBB-EE4E6AA949B0}.Release|x86.ActiveCfg = Release|x64
{3CE9C9B1-1FB1-4770-ABBB-EE4E6AA949B0}.Release|x86.Build.0 = Release|x64
{3CE9C9B1-1FB1-4770-ABBB-EE4E6AA949B0}.Release|x86.Deploy.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|Any CPU.ActiveCfg = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|Any CPU.Build.0 = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|ARM64.ActiveCfg = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|ARM64.Build.0 = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|x64.ActiveCfg = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|x64.Build.0 = Debug|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|x86.ActiveCfg = Debug|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Debug|x86.Build.0 = Debug|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|Any CPU.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|Any CPU.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|ARM64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|ARM64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|x64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|x64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|x86.ActiveCfg = Release|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win10|x86.Build.0 = Release|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|Any CPU.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|Any CPU.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|ARM64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|ARM64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|x64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|x64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|x86.ActiveCfg = Release|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release - No Server - Win11|x86.Build.0 = Release|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|Any CPU.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|Any CPU.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|ARM64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|ARM64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|x64.ActiveCfg = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|x64.Build.0 = Release|x64
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|x86.ActiveCfg = Release|Win32
{3B18467A-4358-45EF-81B1-5C6F9B0B6728}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -75,6 +75,7 @@ VOID
CleanupProcessListOnDriverUnload()
{
PPROCESS_LIST_HEAD list = GetProcessList();
DEBUG_VERBOSE("Freeing process list");
for (;;)
{
if (!LookasideListFreeFirstEntry(
@ -90,6 +91,7 @@ VOID
CleanupThreadListOnDriverUnload()
{
PTHREAD_LIST_HEAD list = GetThreadList();
DEBUG_VERBOSE("Freeing thread list!");
for (;;)
{
if (!LookasideListFreeFirstEntry(
@ -575,7 +577,9 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
*/
if (!strcmp(process_creator_name, "lsass.exe") ||
!strcmp(process_creator_name, "csrss.exe") ||
!strcmp(process_creator_name, "WerFault.exe"))
!strcmp(process_creator_name, "WerFault.exe") ||
!strcmp(process_creator_name, "MsMpEng.exe") ||
!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
@ -604,28 +608,31 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
!strcmp(process_creator_name, "explorer.exe"))
goto end;
// DEBUG_LOG("handle stripped from: %s", process_creator_name);
//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;
if (!report)
goto end;
//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 =
// OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
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 =
OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
//RtlCopyMemory(report->process_name,
// process_creator_name,
// HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
RtlCopyMemory(report->process_name,
process_creator_name,
HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
InsertReportToQueue(report);
//if (!NT_SUCCESS(
// IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
//{
// DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
// goto end;
//}
}
}
@ -799,7 +806,11 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
RtlCopyMemory(
&report->process_name, process_name, HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
InsertReportToQueue(report);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
goto end;
}
}
end:
@ -842,6 +853,8 @@ EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOI
#define REPEAT_TIME_10_SEC 10000
ULONG value = 10;
VOID
TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
{

View file

@ -12,19 +12,6 @@ typedef void (*THREADLIST_CALLBACK_ROUTINE)(_In_ PTHREAD_LIST_ENTRY ThreadListEn
typedef void (*PROCESSLIST_CALLBACK_ROUTINE)(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_In_opt_ PVOID Context);
#define HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH 64
typedef struct _OPEN_HANDLE_FAILURE_REPORT
{
INT report_code;
INT is_kernel_handle;
LONG process_id;
LONG thread_id;
LONG access;
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
} OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT;
#define DRIVER_PATH_LENGTH 0x100
#define SHA_256_HASH_LENGTH 32

View file

@ -3,6 +3,9 @@
#include <ntifs.h>
#include <wdftypes.h>
#include "io.h"
#include "types/types.h"
/*
* For numbers < 32, these are equivalent to 0ul < x.
@ -39,6 +42,8 @@
#define STATIC static
#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
@ -169,11 +174,29 @@ typedef struct _OB_CALLBACKS_CONFIG
} OB_CALLBACKS_CONFIG, *POB_CALLBACKS_CONFIG;
typedef struct _DEFERRED_REPORT
{
LIST_ENTRY list_entry;
PVOID buffer;
UINT32 buffer_size;
} DEFERRED_REPORT, *PDEFERRED_REPORT;
typedef struct _DEFERRED_REPORTS_HEAD
{
LIST_ENTRY head;
UINT32 count;
KGUARDED_MUTEX lock;
} DEFERRED_REPORTS_HEAD, *PDEFERRED_REPORTS_HEAD;
typedef struct _IRP_QUEUE_HEAD
{
SINGLE_LIST_ENTRY start;
volatile INT count;
KGUARDED_MUTEX lock;
LIST_ENTRY queue;
volatile UINT32 count;
IO_CSQ csq;
KGUARDED_MUTEX lock;
DEFERRED_REPORTS_HEAD reports;
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;
@ -282,15 +305,6 @@ typedef struct _PROCESS_CONFIG
#define KPRCB_OFFSET_FROM_GS_BASE 0x180
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
#define REPORT_NMI_CALLBACK_FAILURE 50
#define REPORT_MODULE_VALIDATION_FAILURE 60
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
#define REPORT_INVALID_PROCESS_ALLOCATION 80
#define REPORT_HIDDEN_SYSTEM_THREAD 90
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
#define REPORT_APC_STACKWALK 110
#define REPORT_DPC_STACKWALK 120
#define REPORT_DATA_TABLE_ROUTINE 130
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1

View file

@ -1,7 +1,7 @@
#include "driver.h"
#include "common.h"
#include "ioctl.h"
#include "io.h"
#include "callbacks.h"
#include "hv.h"
@ -41,10 +41,6 @@ STATIC
VOID
DrvUnloadFreeSymbolicLink();
STATIC
VOID
DrvUnloadFreeGlobalReportQueue();
STATIC
VOID
DrvUnloadFreeThreadList();
@ -84,7 +80,6 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
# pragma alloc_text(PAGE, DrvUnloadUnregisterObCallbacks)
# pragma alloc_text(PAGE, DrvUnloadFreeConfigStrings)
# pragma alloc_text(PAGE, DrvUnloadFreeSymbolicLink)
# pragma alloc_text(PAGE, DrvUnloadFreeGlobalReportQueue)
# pragma alloc_text(PAGE, DrvUnloadFreeThreadList)
# pragma alloc_text(PAGE, DrvLoadEnableNotifyRoutines)
# pragma alloc_text(PAGE, DrvLoadEnableNotifyRoutines)
@ -115,7 +110,6 @@ typedef struct _DRIVER_CONFIG
THREAD_LIST_HEAD thread_list;
DRIVER_LIST_HEAD driver_list;
PROCESS_LIST_HEAD process_list;
REPORT_QUEUE_HEAD report_queue;
} DRIVER_CONFIG, *PDRIVER_CONFIG;
@ -239,13 +233,6 @@ GetDriverConfigSystemInformation()
return &g_DriverConfig->system_information;
}
PREPORT_QUEUE_HEAD
GetDriverReportQueue()
{
PAGED_CODE();
return &g_DriverConfig->report_queue;
}
PTHREAD_LIST_HEAD
GetThreadList()
{
@ -390,14 +377,6 @@ DrvUnloadFreeSymbolicLink()
ImpIoDeleteSymbolicLink(&g_DriverConfig->device_symbolic_link);
}
STATIC
VOID
DrvUnloadFreeGlobalReportQueue()
{
PAGED_CODE();
FreeGlobalReportQueueObjects();
}
STATIC
VOID
DrvUnloadFreeThreadList()
@ -475,7 +454,6 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
DrvUnloadFreeDriverList();
DrvUnloadFreeConfigStrings();
DrvUnloadFreeGlobalReportQueue();
DrvUnloadFreeSymbolicLink();
ImpIoDeleteDevice(DriverObject->DeviceObject);
@ -566,14 +544,6 @@ DrvLoadSetupDriverLists()
return status;
}
STATIC
VOID
DrvLoadInitialiseReportQueue()
{
PAGED_CODE();
InitialiseGlobalReportQueue(&g_DriverConfig->report_queue);
}
STATIC
VOID
DrvLoadInitialiseProcessConfig()
@ -956,6 +926,15 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
return status;
}
status = IrpQueueInitialise();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("IrpQueueInitialise failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
DEBUG_VERBOSE("driver name: %s", g_DriverConfig->ansi_driver_name.Buffer);
return status;
}
@ -1000,7 +979,11 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
status = ResolveDynamicImports(DriverObject);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ResolveDynamicImports failed with status %x", status);
ImpIoDeleteDevice(DriverObject->DeviceObject);
return status;
}
status = DrvLoadInitialiseDriverConfig(DriverObject, RegistryPath);
@ -1008,10 +991,10 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
DEBUG_ERROR("InitialiseDriverConfigOnDriverEntry failed with status %x", status);
ImpIoDeleteDevice(DriverObject->DeviceObject);
DrvUnloadFreeImportsStructure();
return status;
}
DrvLoadInitialiseReportQueue();
DrvLoadInitialiseProcessConfig();
status = IoCreateSymbolicLink(&symbolic_link, &device_name);
@ -1022,6 +1005,7 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
DrvUnloadFreeConfigStrings();
ImpIoDeleteDevice(DriverObject->DeviceObject);
DrvUnloadFreeTimerObject();
DrvUnloadFreeImportsStructure();
return STATUS_FAILED_DRIVER_ENTRY;
}

View file

@ -64,9 +64,6 @@ GetDriverSymbolicLink();
PSYSTEM_INFORMATION
GetDriverConfigSystemInformation();
PREPORT_QUEUE_HEAD
GetDriverReportQueue();
PTHREAD_LIST_HEAD
GetThreadList();

View file

@ -250,7 +250,7 @@
<ClCompile Include="hv.c" />
<ClCompile Include="imports.c" />
<ClCompile Include="integrity.c" />
<ClCompile Include="ioctl.c" />
<ClCompile Include="io.c" />
<ClCompile Include="list.c" />
<ClCompile Include="modules.c" />
<ClCompile Include="pool.c" />
@ -266,12 +266,13 @@
<ClInclude Include="ia32.h" />
<ClInclude Include="imports.h" />
<ClInclude Include="integrity.h" />
<ClInclude Include="ioctl.h" />
<ClInclude Include="io.h" />
<ClInclude Include="list.h" />
<ClInclude Include="modules.h" />
<ClInclude Include="pool.h" />
<ClInclude Include="queue.h" />
<ClInclude Include="thread.h" />
<ClInclude Include="types\types.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="arch.asm" />

View file

@ -27,9 +27,6 @@
<ClCompile Include="driver.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ioctl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="modules.c">
<Filter>Source Files</Filter>
</ClCompile>
@ -60,6 +57,9 @@
<ClCompile Include="list.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="io.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="driver.h">
@ -68,9 +68,6 @@
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ioctl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="modules.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -104,6 +101,12 @@
<ClInclude Include="list.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="io.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="types\types.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="arch.asm">

View file

@ -3,7 +3,7 @@
#include <intrin.h>
#include "imports.h"
#include "common.h"
#include "ioctl.h"
#include "io.h"
#ifdef ALLOC_PRAGMA
# pragma alloc_text(PAGE, PerformVirtualizationDetection)

View file

@ -4,13 +4,6 @@
#include <ntifs.h>
#include "common.h"
typedef struct _HYPERVISOR_DETECTION_REPORT
{
INT aperf_msr_timing_check;
INT invd_emulation_check;
} HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
NTSTATUS
PerformVirtualizationDetection(_Inout_ PIRP Irp);

View file

@ -4,7 +4,7 @@
#include "driver.h"
#include "modules.h"
#include "callbacks.h"
#include "ioctl.h"
#include "io.h"
#include "imports.h"
#include <bcrypt.h>
@ -18,8 +18,6 @@ typedef struct _INTEGRITY_CHECK_HEADER
} INTEGRITY_CHECK_HEADER, *PINTEGRITY_CHECK_HEADER;
#define MAX_MODULE_PATH 256
typedef struct _PROCESS_MODULE_INFORMATION
{
PVOID module_base;
@ -933,28 +931,29 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
goto end;
}
/*
* Because each module is passed per IRP we don't need to send any reports
* to the queue we can simply pass it back to usermode via the same IRP.
* We also don't need to send any module information since usermode has everything
* needed to file the report.
*/
validation_result.is_module_valid = CompareHashes(disk_hash, memory_hash, memory_hash_size);
status = ValidateIrpOutputBuffer(Irp, sizeof(PROCESS_MODULE_VALIDATION_RESULT));
if (!NT_SUCCESS(status))
if (!CompareHashes(disk_hash, memory_hash, memory_hash_size))
{
DEBUG_ERROR("Failed to validate IRP output buffer");
goto end;
PPROCESS_MODULE_VALIDATION_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(PROCESS_MODULE_VALIDATION_REPORT), REPORT_POOL_TAG);
if (!report)
goto end;
report->report_code = REPORT_INVALID_PROCESS_MODULE;
report->image_base = module_info->module_base;
report->image_size = module_info->module_size;
RtlCopyMemory(report->module_path, module_info->module_path,
sizeof(report->module_path));
status = IrpQueueCompleteIrp(report, sizeof(PROCESS_MODULE_VALIDATION_REPORT));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with status %x", status);
goto end;
}
}
Irp->IoStatus.Information = sizeof(PROCESS_MODULE_VALIDATION_RESULT);
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
&validation_result,
sizeof(PROCESS_MODULE_VALIDATION_RESULT));
end:
if (section_handle)

View file

@ -1,4 +1,4 @@
#include "ioctl.h"
#include "io.h"
#include "modules.h"
#include "driver.h"
@ -60,49 +60,226 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation);
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_INSERT_IRP_INTO_QUEUE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20021, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_QUERY_DEFERRED_REPORTS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20022, METHOD_BUFFERED, FILE_ANY_ACCESS)
#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.
*
* user mode program will automatically queue another irp when an irp completes, ensuring queue has
* a sufficient supply.
*/
VOID
IrpQueueMarkIrpCompleteCallback(_In_ PIRP_QUEUE_ENTRY Entry)
IrpQueueAcquireLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
{
ImpIofCompleteRequest(Entry->irp, IO_NO_INCREMENT);
KeAcquireGuardedMutex(&GetIrpQueueHead()->lock);
}
VOID
IrpQueueDequeue(PVOID Callback)
IrpQueueReleaseLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
{
KeReleaseGuardedMutex(&GetIrpQueueHead()->lock);
}
PIRP
IrpQueuePeekNextEntry(_In_ PIO_CSQ Csq, _In_ PIRP Irp, _In_ PVOID Context)
{
UNREFERENCED_PARAMETER(Context);
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
ListFreeFirstEntry(&queue->start, &queue->lock, Callback);
if (queue->count == 0)
return NULL;
return CONTAINING_RECORD(queue->queue.Flink, IRP, Tail.Overlay.ListEntry);
}
VOID
IrpQueueInitialise()
IrpQueueRemove(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
{
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
queue->count = 0;
ImpKeInitializeGuardedMutex(&queue->lock);
ListInit(&queue->start, &queue->lock);
UNREFERENCED_PARAMETER(Csq);
GetIrpQueueHead()->count--;
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
}
BOOLEAN
IrpQueueIsThereDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
{
return Queue->reports.count > 0 ? TRUE : FALSE;
}
PDEFERRED_REPORT
IrpQueueRemoveDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
{
return RemoveHeadList(&Queue->reports.head);
}
NTSTATUS
IrpQueueCompleteDeferredReport(_In_ PDEFERRED_REPORT Report, _In_ PIRP Irp)
{
NTSTATUS status = ValidateIrpOutputBuffer(Irp, Report->buffer_size);
if (!NT_SUCCESS(status))
return status;
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);
return STATUS_SUCCESS;
}
NTSTATUS
IrpQueueQueryPendingReports(_In_ PIRP Irp)
{
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
PDEFERRED_REPORT report = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
if (IrpQueueIsThereDeferredReport(queue))
{
KeAcquireGuardedMutex(&queue->reports.lock);
report = IrpQueueRemoveDeferredReport(queue);
status = IrpQueueCompleteDeferredReport(report, Irp);
if (!NT_SUCCESS(status))
{
KeReleaseGuardedMutex(&queue->reports.lock);
return status;
}
queue->reports.count--;
KeReleaseGuardedMutex(&queue->reports.lock);
return status;
}
return status;
}
VOID
IrpQueueInsert(PIRP Irp)
IrpQueueInsert(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
{
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
PIRP_QUEUE_ENTRY entry = NULL;
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
InsertTailList(&queue->queue, &Irp->Tail.Overlay.ListEntry);
queue->count++;
}
entry = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(IRP_QUEUE_ENTRY), POOL_TAG_IRP_QUEUE);
VOID
IrpQueueCompleteCancelledIrp(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
{
UNREFERENCED_PARAMETER(Csq);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Status = 0;
ImpIofCompleteRequest(Irp, IO_NO_INCREMENT);
}
if (!entry)
PDEFERRED_REPORT
IrpQueueAllocateDeferredReport(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
{
PDEFERRED_REPORT report =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DEFERRED_REPORT), REPORT_POOL_TAG);
if (!report)
return NULL;
report->buffer = Buffer;
report->buffer_size = BufferSize;
return report;
}
VOID
IrpQueueDeferReport(_In_ PIRP_QUEUE_HEAD Queue, _In_ PVOID Buffer, _In_ UINT32 BufferSize)
{
if (Queue->reports.count > 100)
{
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
return;
}
PDEFERRED_REPORT report = IrpQueueAllocateDeferredReport(Buffer, BufferSize);
if (!report)
return;
Irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
entry->irp = Irp;
queue->count++;
KeAcquireGuardedMutex(&Queue->reports.lock);
InsertTailList(&Queue->reports.head, &report->list_entry);
Queue->reports.count++;
KeReleaseGuardedMutex(&Queue->reports.lock);
}
ListInsert(&queue->start, &entry->entry, &queue->lock);
IrpQueueDequeue(IrpQueueMarkIrpCompleteCallback);
/* takes ownership of the buffer, and regardless of the outcome will free it. */
NTSTATUS
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
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 (!irp)
{
IrpQueueDeferReport(queue, Buffer, BufferSize);
return STATUS_SUCCESS;
}
status = ValidateIrpOutputBuffer(irp, BufferSize);
if (!NT_SUCCESS(status))
{
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
return status;
}
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = BufferSize;
RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, Buffer, BufferSize);
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
ImpIofCompleteRequest(irp, IO_NO_INCREMENT);
}
VOID
IrpQueueFreeDeferredReports()
{
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
PDEFERRED_REPORT report = NULL;
while (IrpQueueIsThereDeferredReport(queue))
{
report = IrpQueueRemoveDeferredReport(queue);
ExFreePoolWithTag(report, REPORT_POOL_TAG);
}
}
NTSTATUS
IrpQueueInitialise()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
KeInitializeGuardedMutex(&queue->lock);
KeInitializeGuardedMutex(&queue->reports.lock);
InitializeListHead(&queue->queue);
InitializeListHead(&queue->reports.head);
status = IoCsqInitialize(&queue->csq,
IrpQueueInsert,
IrpQueueRemove,
IrpQueuePeekNextEntry,
IrpQueueAcquireLock,
IrpQueueReleaseLock,
IrpQueueCompleteCancelledIrp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("IoCsqInitialize failed with status %x", status);
return status;
}
STATIC
@ -132,7 +309,7 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation)
default: DEBUG_WARNING("Invalid operation ID passed"); return STATUS_INVALID_PARAMETER;
}
return status;
return STATUS_SUCCESS;
}
/*
@ -241,8 +418,13 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
* it will issue a bug check under windows driver verifier.
*/
status = ImpPsCreateSystemThread(
&handle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, HandleValidateDriversIOCTL, Irp);
status = ImpPsCreateSystemThread(&handle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
HandleValidateDriversIOCTL,
NULL);
if (!NT_SUCCESS(status))
{
@ -250,27 +432,7 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
goto end;
}
/*
* Thread objects are a type of dispatcher object, meaning when they are freed
* its set to the signal state and any waiters will be signalled. This allows
* us to wait til our threads terminated and the IRP buffer has been either filled
* or left empty and then from there we can complete the IRP and return.
*/
status = ImpObReferenceObjectByHandle(
handle, THREAD_ALL_ACCESS, *PsThreadType, KernelMode, &thread, NULL);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ObReferenceObjectByHandle failed with status %lx", status);
ImpZwClose(handle);
goto end;
}
ImpKeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
ImpZwClose(handle);
ImpObDereferenceObject(thread);
break;
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:;
@ -302,11 +464,11 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_ERROR("QueryActiveApcContextsForCompletion failed with status %x",
status);
status = HandlePeriodicGlobalReportQueueQuery(Irp);
// status = HandlePeriodicGlobalReportQueueQuery(Irp);
if (!NT_SUCCESS(status))
DEBUG_ERROR("HandlePeriodicGlobalReportQueueQuery failed with status %x",
status);
// if (!NT_SUCCESS(status))
// DEBUG_ERROR("HandlePeriodicGlobalReportQueueQuery failed with status %x",
// status);
break;
@ -478,7 +640,7 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_VALIDATE_SYSTEM_MODULES Received");
status = SystemModuleVerificationDispatcher();
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateSystemModules failed with status %x", status);
@ -496,13 +658,36 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
break;
case IOCTL_INSERT_IRP_INTO_QUEUE:
case IOCTL_INSERT_IRP_INTO_QUEUE:;
DEBUG_INFO("IOCTL_INSERT_IRP_INTO_QUEUE Received");
//DEBUG_INFO("IOCTL_INSERT_IRP_INTO_QUEUE Received");
IrpQueueInsert(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.
*
* TODO: some issue with using an incoming irp meant for the queue and finishing 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 there are no deferred reports, store the irp in
* the queue */
IoCsqInsertIrp(&queue->csq, Irp, NULL);
/* we dont want to complete the request */
return STATUS_PENDING;
}
/* we dont want to complete the request */
return STATUS_SUCCESS;
default:
@ -529,7 +714,6 @@ DeviceClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("Handle to driver closed.");
/* we also lose reports here, so sohuld pass em into the irp before freeing */
FreeGlobalReportQueueObjects();
ProcCloseClearProcessConfiguration();
UnregisterProcessObCallbacks();

View file

@ -1,5 +1,5 @@
#ifndef IOCTL_H
#define IOCTL_H
#ifndef IO_H
#define IO_H
#include <ntifs.h>
#include <wdftypes.h>
@ -27,7 +27,10 @@ ValidateIrpOutputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
NTSTATUS
ValidateIrpInputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
VOID
NTSTATUS
IrpQueueInitialise();
NTSTATUS
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize);
#endif

View file

@ -2,7 +2,7 @@
#include "callbacks.h"
#include "driver.h"
#include "ioctl.h"
#include "io.h"
#include "ia32.h"
#include "imports.h"
#include "apc.h"
@ -621,12 +621,11 @@ end:
}
NTSTATUS
HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
HandleValidateDriversIOCTL()
{
PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID buffer = NULL;
ULONG buffer_size = 0;
SYSTEM_MODULES system_modules = {0};
MODULE_VALIDATION_FAILURE_HEADER header = {0};
@ -676,34 +675,6 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
{
DEBUG_VERBOSE("System has an invalid driver count of: %i", head->count);
buffer_size =
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT * sizeof(MODULE_VALIDATION_FAILURE);
status = ValidateIrpOutputBuffer(Irp, buffer_size);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Failed to validate output buffer.");
goto end;
}
buffer =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED, buffer_size, MODULES_REPORT_POOL_TAG);
if (!buffer)
{
ImpExFreePoolWithTag(head, INVALID_DRIVER_LIST_HEAD_POOL);
ImpExFreePoolWithTag(system_modules.address, SYSTEM_MODULES_POOL);
return STATUS_MEMORY_NOT_ALLOCATED;
}
Irp->IoStatus.Information =
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT * sizeof(MODULE_VALIDATION_FAILURE);
RtlCopyMemory(buffer, &header, sizeof(MODULE_VALIDATION_FAILURE_HEADER));
for (INT index = 0; index < head->count; index++)
{
/* make sure we free any non reported modules */
@ -713,16 +684,21 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
continue;
}
MODULE_VALIDATION_FAILURE report = {0};
report.report_code = REPORT_MODULE_VALIDATION_FAILURE;
report.report_type = head->first_entry->reason;
report.driver_base_address = head->first_entry->driver->DriverStart;
report.driver_size = head->first_entry->driver->DriverSize;
PMODULE_VALIDATION_FAILURE report = ImpExAllocatePool2(
POOL_FLAG_PAGED, sizeof(MODULE_VALIDATION_FAILURE), POOL_TAG_INTEGRITY);
if (!report)
continue;
report->report_code = REPORT_MODULE_VALIDATION_FAILURE;
report->report_type = head->first_entry->reason;
report->driver_base_address = head->first_entry->driver->DriverStart;
report->driver_size = head->first_entry->driver->DriverSize;
ANSI_STRING string = {0};
string.Length = 0;
string.MaximumLength = MODULE_REPORT_DRIVER_NAME_BUFFER_SIZE;
string.Buffer = &report.driver_name;
string.Buffer = &report->driver_name;
status = ImpRtlUnicodeStringToAnsiString(
&string, &head->first_entry->driver->DriverName, FALSE);
@ -732,21 +708,16 @@ HandleValidateDriversIOCTL(_Inout_ PIRP Irp)
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x",
status);
RtlCopyMemory((UINT64)buffer + sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
index * sizeof(MODULE_VALIDATION_FAILURE),
&report,
sizeof(MODULE_VALIDATION_FAILURE));
status = IrpQueueCompleteIrp(report, sizeof(MODULE_VALIDATION_FAILURE));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with status %x", status);
continue;
}
RemoveInvalidDriverFromList(head);
}
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
buffer,
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT *
sizeof(MODULE_VALIDATION_FAILURE));
ImpExFreePoolWithTag(buffer, MODULES_REPORT_POOL_TAG);
}
else
{
@ -906,7 +877,12 @@ AnalyseNmiData(_In_ PNMI_CONTEXT NmiContext, _In_ PSYSTEM_MODULES SystemModules,
RtlCopyMemory(
report->thread, NmiContext[core].kthread, sizeof(report->thread));
InsertReportToQueue(report);
if (!NT_SUCCESS(
IrpQueueCompleteIrp(report, sizeof(HIDDEN_SYSTEM_THREAD_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
continue;
}
}
else
{
@ -1193,7 +1169,7 @@ ApcKernelRoutine(_In_ PRKAPC Apc,
if (flag == FALSE)
{
PAPC_STACKWALK_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(APC_STACKWALK_REPORT), POOL_TAG_APC);
POOL_FLAG_NON_PAGED, sizeof(APC_STACKWALK_REPORT), REPORT_POOL_TAG);
if (!report)
goto free;
@ -1202,11 +1178,11 @@ ApcKernelRoutine(_In_ PRKAPC Apc,
report->kthread_address = (UINT64)KeGetCurrentThread();
report->invalid_rip = stack_frame;
RtlCopyMemory(&report->driver,
(UINT64)stack_frame - 0x500,
APC_STACKWALK_BUFFER_SIZE);
InsertReportToQueue(report);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(APC_STACKWALK_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
continue;
}
}
}
@ -1486,7 +1462,7 @@ ValidateDpcCapturedStack(_In_ PSYSTEM_MODULES Modules, _In_ PDPC_CONTEXT Context
{
report = ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(DPC_STACKWALK_REPORT),
POOL_TAG_DPC);
REPORT_POOL_TAG);
if (!report)
continue;
@ -1495,11 +1471,16 @@ ValidateDpcCapturedStack(_In_ PSYSTEM_MODULES Modules, _In_ PDPC_CONTEXT Context
report->kthread_address = PsGetCurrentThread();
report->invalid_rip = Context[core].stack_frame[frame];
//RtlCopyMemory(report->driver,
// (UINT64)Context[core].stack_frame[frame] - 0x50,
// APC_STACKWALK_BUFFER_SIZE);
// RtlCopyMemory(report->driver,
// (UINT64)Context[core].stack_frame[frame] - 0x50,
// APC_STACKWALK_BUFFER_SIZE);
InsertReportToQueue(report);
if (!NT_SUCCESS(
IrpQueueCompleteIrp(report, sizeof(DPC_STACKWALK_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
continue;
}
}
}
}
@ -1806,7 +1787,7 @@ VOID
ReportDataTableInvalidRoutine(_In_ TABLE_ID TableId, _In_ UINT64 Address)
{
PDATA_TABLE_ROUTINE_REPORT report = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, sizeof(DATA_TABLE_ROUTINE_REPORT), POOL_TAG_INTEGRITY);
POOL_FLAG_NON_PAGED, sizeof(DATA_TABLE_ROUTINE_REPORT), REPORT_POOL_TAG);
if (!report)
return;
@ -1819,7 +1800,8 @@ ReportDataTableInvalidRoutine(_In_ TABLE_ID TableId, _In_ UINT64 Address)
report->id = REPORT_DATA_TABLE_ROUTINE;
RtlCopyMemory(report->routine, Address, DATA_TABLE_ROUTINE_BUF_SIZE);
InsertReportToQueue(report);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(DATA_TABLE_ROUTINE_REPORT))))
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
}
NTSTATUS

View file

@ -7,62 +7,6 @@
#include "common.h"
#include "queue.h"
typedef enum _TABLE_ID
{
HalDispatch = 0,
HalPrivateDispatch
} TABLE_ID;
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
typedef struct _DATA_TABLE_ROUTINE_REPORT
{
UINT32 report_code;
TABLE_ID id;
UINT64 address;
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
} DATA_TABLE_ROUTINE_REPORT, *PDATA_TABLE_ROUTINE_REPORT;
typedef struct _NMI_CALLBACK_FAILURE
{
INT report_code;
INT were_nmis_disabled;
UINT64 kthread_address;
UINT64 invalid_rip;
} NMI_CALLBACK_FAILURE, *PNMI_CALLBACK_FAILURE;
#define APC_STACKWALK_BUFFER_SIZE 0x50
typedef struct _DPC_STACKWALK_REPORT
{
UINT32 report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
} DPC_STACKWALK_REPORT, *PDPC_STACKWALK_REPORT;
typedef struct _MODULE_VALIDATION_FAILURE
{
INT report_code;
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[128];
} MODULE_VALIDATION_FAILURE, *PMODULE_VALIDATION_FAILURE;
typedef struct _APC_STACKWALK_REPORT
{
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
} APC_STACKWALK_REPORT, *PAPC_STACKWALK_REPORT;
typedef struct _APC_OPERATION_ID
{
int operation_id;
@ -99,7 +43,7 @@ NTSTATUS
GetSystemModuleInformation(_Out_ PSYSTEM_MODULES ModuleInformation);
NTSTATUS
HandleValidateDriversIOCTL(_Inout_ PIRP Irp);
HandleValidateDriversIOCTL();
PRTL_MODULE_EXTENDED_INFO
FindSystemModuleByName(_In_ LPCSTR ModuleName, _In_ PSYSTEM_MODULES SystemModules);

View file

@ -701,14 +701,19 @@ FindUnlinkedProcesses()
POOL_FLAG_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
if (!report_buffer)
goto end;
continue;
report_buffer->report_code = REPORT_INVALID_PROCESS_ALLOCATION;
RtlCopyMemory(
report_buffer->process, allocation, REPORT_INVALID_PROCESS_BUFFER_SIZE);
InsertReportToQueue(report_buffer);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report_buffer,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT))))
{
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
continue;
}
}
end:

View file

@ -4,15 +4,6 @@
#include <ntifs.h>
#include "common.h"
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 4096
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
{
INT report_code;
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
} INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
NTSTATUS
FindUnlinkedProcesses();

View file

@ -7,24 +7,10 @@
#include "queue.h"
#include "pool.h"
#include "thread.h"
#include "ioctl.h"
#include "io.h"
#include "common.h"
#include "imports.h"
VOID
InitialiseGlobalReportQueue()
{
PREPORT_QUEUE_HEAD queue = GetDriverReportQueue();
queue->head.start = NULL;
queue->head.end = NULL;
queue->head.entries = 0;
queue->is_driver_unloading = FALSE;
ImpKeInitializeGuardedMutex(&queue->head.lock);
ImpKeInitializeGuardedMutex(&queue->lock);
}
VOID
QueuePush(_Inout_ PQUEUE_HEAD Head, _In_ PVOID Data)
{
@ -75,195 +61,4 @@ QueuePop(_Inout_ PQUEUE_HEAD Head)
end:
ImpKeReleaseGuardedMutex(&Head->lock);
return data;
}
VOID
InsertReportToQueue(_In_ PVOID Report)
{
PREPORT_QUEUE_HEAD queue = GetDriverReportQueue();
if (InterlockedExchange(&queue->is_driver_unloading, queue->is_driver_unloading))
return;
ImpKeAcquireGuardedMutex(&queue->lock);
QueuePush(&queue->head, Report);
ImpKeReleaseGuardedMutex(&queue->lock);
}
VOID
FreeGlobalReportQueueObjects()
{
PREPORT_QUEUE_HEAD queue = GetDriverReportQueue();
InterlockedExchange(&queue->is_driver_unloading, TRUE);
ImpKeAcquireGuardedMutex(&queue->lock);
PVOID report = QueuePop(&queue->head);
while (report)
{
ImpExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop(&queue->head);
}
end:
ImpKeReleaseGuardedMutex(&queue->lock);
}
/*
* This function handles sending all the pending reports in the global report
* queue to the usermode application. This function is called periodically by the
* usermode application. The reason I have implemented this is because as this application
* expanded, it became apparent that some of the driver functions will generate multiple
* reports as a result of a single usermode request and hence it makes dealing with
* reports generated from ObRegisterCallbacks for example much easier.
*/
NTSTATUS
HandlePeriodicGlobalReportQueueQuery(_Out_ PIRP Irp)
{
INT count = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID report = NULL;
SIZE_T total_size = 0;
PVOID report_buffer = NULL;
ULONG report_buffer_size = 0;
PREPORT_HEADER report_header = NULL;
GLOBAL_REPORT_QUEUE_HEADER header = {0};
PREPORT_QUEUE_HEAD queue = GetDriverReportQueue();
ImpKeAcquireGuardedMutex(&queue->lock);
report_buffer_size = sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP +
sizeof(GLOBAL_REPORT_QUEUE_HEADER);
status = ValidateIrpOutputBuffer(Irp, report_buffer_size);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ValidateIrpOutputBuffer failed with status %x", status);
ImpKeReleaseGuardedMutex(&queue->lock);
return status;
}
report_buffer = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED, report_buffer_size, REPORT_QUEUE_TEMP_BUFFER_TAG);
if (!report_buffer)
{
ImpKeReleaseGuardedMutex(&queue->lock);
return STATUS_MEMORY_NOT_ALLOCATED;
}
report = QueuePop(&queue->head);
if (report == NULL)
{
DEBUG_VERBOSE("Callback report queue is empty. No reports to be sent to usermode.");
goto end;
}
while (report != NULL)
{
if (count >= MAX_REPORTS_PER_IRP)
goto end;
report_header = (PREPORT_HEADER)report;
switch (report_header->report_id)
{
case REPORT_ILLEGAL_HANDLE_OPERATION:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(OPEN_HANDLE_FAILURE_REPORT));
total_size += sizeof(OPEN_HANDLE_FAILURE_REPORT);
break;
case REPORT_ILLEGAL_ATTACH_PROCESS:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(ATTACH_PROCESS_REPORT));
total_size += sizeof(ATTACH_PROCESS_REPORT);
break;
case REPORT_INVALID_PROCESS_ALLOCATION:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT));
total_size += sizeof(INVALID_PROCESS_ALLOCATION_REPORT);
break;
case REPORT_APC_STACKWALK:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(APC_STACKWALK_REPORT));
total_size += sizeof(APC_STACKWALK_REPORT);
break;
case REPORT_HIDDEN_SYSTEM_THREAD:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(HIDDEN_SYSTEM_THREAD_REPORT));
total_size += sizeof(HIDDEN_SYSTEM_THREAD_REPORT);
break;
case REPORT_DPC_STACKWALK:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(DPC_STACKWALK_REPORT));
total_size += sizeof(DPC_STACKWALK_REPORT);
break;
case REPORT_DATA_TABLE_ROUTINE:
RtlCopyMemory((UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) +
total_size,
report,
sizeof(DATA_TABLE_ROUTINE_REPORT));
total_size += sizeof(DATA_TABLE_ROUTINE_REPORT);
break;
}
/* QueuePop frees the node, but we still need to free the returned data */
ImpExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop(&queue->head);
count += 1;
}
end:
ImpKeReleaseGuardedMutex(&queue->lock);
Irp->IoStatus.Information = sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size;
header.count = count;
RtlCopyMemory(report_buffer, &header, sizeof(GLOBAL_REPORT_QUEUE_HEADER));
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
report_buffer,
sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size);
if (report_buffer)
ImpExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
DEBUG_VERBOSE("All reports moved into the IRP, sending to usermode.");
return STATUS_SUCCESS;
}

View file

@ -56,19 +56,4 @@ QueuePush(_Inout_ PQUEUE_HEAD Head, _In_ PVOID Data);
PVOID
QueuePop(_Inout_ PQUEUE_HEAD Head);
VOID
InitialiseGlobalReportQueue();
VOID
InsertReportToQueue(_In_ PVOID Report);
NTSTATUS
HandlePeriodicGlobalReportQueueQuery(_Out_ PIRP Irp);
NTSTATUS
HandlePeriodicGlobalReportQueueQuery(_Out_ PIRP Irp);
VOID
FreeGlobalReportQueueObjects();
#endif

View file

@ -89,7 +89,7 @@ DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
/*
* 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
*/
@ -109,7 +109,8 @@ DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
report->thread_id = ImpPsGetThreadId(ThreadListEntry->thread);
report->thread_address = ThreadListEntry->thread;
InsertReportToQueue(report);
if (!NT_SUCCESS(IrpQueueCompleteIrp(report, sizeof(ATTACH_PROCESS_REPORT))))
DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
}
}

View file

@ -6,34 +6,6 @@
#include "common.h"
#include "callbacks.h"
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
{
INT report_code;
INT found_in_kthreadlist;
INT found_in_pspcidtable;
UINT64 thread_address;
LONG thread_id;
CHAR thread[4096];
} HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
typedef struct _ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
} ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
typedef struct _KPRCB_THREAD_VALIDATION_CTX
{
UINT64 thread;
BOOLEAN thread_found_in_pspcidtable;
// BOOLEAN thread_found_in_kthreadlist;
BOOLEAN finished;
} KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
BOOLEAN
ValidateThreadsPspCidTableEntry(_In_ PETHREAD Thread);

141
driver/types/types.h Normal file
View file

@ -0,0 +1,141 @@
#ifndef TYPES_H
#define TYPES_H
#include "../common.h"
#define REPORT_NMI_CALLBACK_FAILURE 50
#define REPORT_MODULE_VALIDATION_FAILURE 60
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
#define REPORT_INVALID_PROCESS_ALLOCATION 80
#define REPORT_HIDDEN_SYSTEM_THREAD 90
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
#define REPORT_APC_STACKWALK 110
#define REPORT_DPC_STACKWALK 120
#define REPORT_DATA_TABLE_ROUTINE 130
#define REPORT_INVALID_PROCESS_MODULE 140
typedef enum _TABLE_ID
{
HalDispatch = 0,
HalPrivateDispatch
} TABLE_ID;
typedef struct _HYPERVISOR_DETECTION_REPORT
{
INT aperf_msr_timing_check;
INT invd_emulation_check;
} HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
#define APC_STACKWALK_BUFFER_SIZE 500
typedef struct _APC_STACKWALK_REPORT
{
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
} APC_STACKWALK_REPORT, *PAPC_STACKWALK_REPORT;
typedef struct _DPC_STACKWALK_REPORT
{
UINT32 report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
} DPC_STACKWALK_REPORT, *PDPC_STACKWALK_REPORT;
typedef struct _MODULE_VALIDATION_FAILURE
{
INT report_code;
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[128];
} MODULE_VALIDATION_FAILURE, *PMODULE_VALIDATION_FAILURE;
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
typedef struct _DATA_TABLE_ROUTINE_REPORT
{
UINT32 report_code;
TABLE_ID id;
UINT64 address;
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
} DATA_TABLE_ROUTINE_REPORT, *PDATA_TABLE_ROUTINE_REPORT;
typedef struct _NMI_CALLBACK_FAILURE
{
INT report_code;
INT were_nmis_disabled;
UINT64 kthread_address;
UINT64 invalid_rip;
} NMI_CALLBACK_FAILURE, *PNMI_CALLBACK_FAILURE;
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 500
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
{
INT report_code;
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
} INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
{
INT report_code;
INT found_in_kthreadlist;
INT found_in_pspcidtable;
UINT64 thread_address;
LONG thread_id;
CHAR thread[500];
} HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
typedef struct _ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
} ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
typedef struct _KPRCB_THREAD_VALIDATION_CTX
{
UINT64 thread;
BOOLEAN thread_found_in_pspcidtable;
// BOOLEAN thread_found_in_kthreadlist;
BOOLEAN finished;
} KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
#define HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH 64
typedef struct _OPEN_HANDLE_FAILURE_REPORT
{
INT report_code;
INT is_kernel_handle;
LONG process_id;
LONG thread_id;
LONG access;
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
} OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT;
#define MODULE_PATH_LEN 256
typedef struct _PROCESS_MODULE_VALIDATION_REPORT
{
INT report_code;
UINT64 image_base;
UINT32 image_size;
WCHAR module_path[MODULE_PATH_LEN];
} PROCESS_MODULE_VALIDATION_REPORT, *PPROCESS_MODULE_VALIDATION_REPORT;
#endif

View file

@ -0,0 +1,29 @@
#include "message_queue.h"
#include <Windows.h>
#define TEST_STEAM_64_ID 123456789;
client::message_queue::message_queue(LPTSTR PipeName) {
#if NO_SERVER
LOG_INFO("No_Server build used. Not opening named pipe.");
#else
this->pipe_interface = std::make_unique<client::pipe>(PipeName);
#endif
}
void client::message_queue::dequeue_message(void *Buffer, size_t Size) {
#if NO_SERVER
return;
#else
this->pipe_interface->read_pipe(Buffer, Size);
#endif
}
void client::message_queue::enqueue_message(void *Buffer, size_t Size) {
#if NO_SERVER
return;
#else
return;
#endif
}

View file

@ -0,0 +1,43 @@
#ifndef REPORT_H
#define REPORT_H
#include <Windows.h>
#include "../dispatcher/threadpool.h"
#include "../common.h"
#include "pipe.h"
#define REPORT_BUFFER_SIZE 8192
#define SEND_BUFFER_SIZE 8192
#define MAX_SIGNATURE_SIZE 256
#define MESSAGE_TYPE_CLIENT_REPORT 1
#define MESSAGE_TYPE_CLIENT_SEND 2
#define MESSAGE_TYPE_CLIENT_REQUEST 3
namespace client {
class message_queue {
struct MESSAGE_PACKET_HEADER {
int message_type;
int request_id;
unsigned __int64 steam64_id;
};
std::unique_ptr<client::pipe> pipe_interface;
std::mutex lock;
byte report_buffer[REPORT_BUFFER_SIZE];
public:
message_queue(LPTSTR PipeName);
void enqueue_message(void *Buffer, size_t Size);
void dequeue_message(void *Buffer, size_t Size);
};
} // namespace client
#endif

40
module/client/pipe.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "pipe.h"
#include "../common.h"
#include <intrin.h>
client::pipe::pipe(LPTSTR PipeName) {
this->pipe_name = PipeName;
this->pipe_handle =
CreateFile(this->pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (this->pipe_handle == INVALID_HANDLE_VALUE) {
LOG_ERROR("CreateFile failed with status 0x%x", GetLastError());
return;
}
}
void client::pipe::write_pipe(PVOID Buffer, SIZE_T Size) {
DWORD bytes_written = 0;
WriteFile(this->pipe_handle, Buffer, Size, &bytes_written, NULL);
if (bytes_written == 0) {
LOG_ERROR("WriteFile failed with status code 0x%x", GetLastError());
return;
}
}
void client::pipe::read_pipe(PVOID Buffer, SIZE_T Size) {
BOOL status = FALSE;
DWORD bytes_read = 0;
status = ReadFile(this->pipe_handle, Buffer, Size, &bytes_read, NULL);
if (status == NULL) {
LOG_ERROR("ReadFile failed with status code 0x%x", GetLastError());
return;
}
}

51
module/client/pipe.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <Windows.h>
#define MESSAGE_TYPE_CLIENT_REPORT 1
#define MESSAGE_TYPE_CLIENT_SEND 2
#define MESSAGE_TYPE_CLIENT_REQUEST 3
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
namespace client {
class pipe {
HANDLE pipe_handle;
LPTSTR pipe_name;
public:
pipe(LPTSTR PipeName);
void write_pipe(PVOID Buffer, SIZE_T Size);
void read_pipe(PVOID Buffer, SIZE_T Size);
};
namespace headers {
typedef enum _ENVIRONMENT_TYPE {
NativeWindows = 0,
Vmware,
VirtualBox
} ENVIRONMENT_TYPE;
typedef enum _PROCESSOR_TYPE {
Unknown = 0,
GenuineIntel,
AuthenticAmd
} PROCESSOR_TYPE;
#define VENDOR_STRING_MAX_LENGTH 256
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];
BOOLEAN virtualised_environment;
ENVIRONMENT_TYPE environment;
PROCESSOR_TYPE processor;
RTL_OSVERSIONINFOW os_information;
};
} // namespace headers
} // namespace client

View file

@ -1,11 +1,11 @@
#ifndef COMMON_H
#define COMMON_H
#pragma once
#include <stdio.h>
#include <atomic>
#include <mutex>
#include <optional>
#include <vector>
#define LOG_INFO(fmt, ...) printf("[+] " fmt "\n", ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__)
#endif
#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__)

View file

@ -0,0 +1,62 @@
#include "dispatcher.h"
#include "../client/message_queue.h"
#include "../helper.h"
#include <chrono>
dispatcher::dispatcher::dispatcher(LPCWSTR driver_name,
client::message_queue &message_queue)
: thread_pool(DISPATCHER_THREAD_COUNT),
k_interface(driver_name, message_queue) {}
void dispatcher::dispatcher::run() {
helper::generate_rand_seed();
thread_pool.queue_job([this]() { k_interface.run_completion_port(); });
while (true) {
this->issue_kernel_job();
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
}
}
void dispatcher::dispatcher::issue_kernel_job() {
switch (helper::generate_rand_int(KERNEL_DISPATCH_FUNCTION_COUNT)) {
case 0:
thread_pool.queue_job([this]() { k_interface.enumerate_handle_tables(); });
break;
case 1:
thread_pool.queue_job([this]() { k_interface.perform_integrity_check(); });
break;
case 2:
thread_pool.queue_job(
[this]() { k_interface.scan_for_unlinked_processes(); });
break;
case 3:
thread_pool.queue_job(
[this]() { k_interface.verify_process_module_executable_regions(); });
break;
case 4:
thread_pool.queue_job(
[this]() { k_interface.validate_system_driver_objects(); });
break;
case 5:
thread_pool.queue_job([this]() { k_interface.run_nmi_callbacks(); });
break;
case 6:
thread_pool.queue_job(
[this]() { k_interface.scan_for_attached_threads(); });
break;
case 7:
thread_pool.queue_job([this]() { k_interface.initiate_apc_stackwalk(); });
break;
case 8:
thread_pool.queue_job([this]() { k_interface.scan_for_ept_hooks(); });
break;
case 9:
thread_pool.queue_job([this]() { k_interface.perform_dpc_stackwalk(); });
break;
case 10:
thread_pool.queue_job([this]() { k_interface.validate_system_modules(); });
break;
}
}

View file

@ -0,0 +1,23 @@
#pragma once
#include "threadpool.h"
#include "../kernel_interface/kernel_interface.h"
namespace dispatcher {
static const int DISPATCH_LOOP_SLEEP_TIME = 10;
static const int KERNEL_DISPATCH_FUNCTION_COUNT = 11;
static const int DISPATCHER_THREAD_COUNT = 4;
class dispatcher {
thread_pool thread_pool;
kernel_interface::kernel_interface k_interface;
void issue_kernel_job();
public:
dispatcher(LPCWSTR driver_name, client::message_queue &queue);
void run();
};
} // namespace dispatcher

View file

@ -0,0 +1,92 @@
#include "threadpool.h"
/*
* This is the idle loop each thread will be running until a job is ready
* for execution
*/
void dispatcher::thread_pool::wait_for_task() {
while (true) {
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
/*
* This is equivalent to :
*
* while (!this->jobs.empty() || should_terminate)
* mutex_condition.wait(lock);
*
* we are essentially waiting for a job to be queued up or the terminate
*flag to be set. Another piece of useful information is that the
*predicate is checked under the lock as the precondition for .wait() is
*that the calling thread owns the lock.
*
* Now, when .wait() is run, the lock is unlocked the the executing thread
*is blocked and is added to a list of threads current waiting on the
*predicate. In our case whether there are new jobs available for the
*terminate flag is set. Once the condition variables are true i.e there
*are new jobs or we are terminating, the lock is reacquired by the thread
*and the thread is unblocked.
*/
mutex_condition.wait(lock, [this] {
return !this->jobs.empty() || this->should_terminate;
});
if (this->should_terminate)
return;
/* get the first job in the queue*/
job = jobs.front();
jobs.pop();
}
/* run the job */
job();
}
}
dispatcher::thread_pool::thread_pool(int thread_count) {
this->thread_count = thread_count;
this->should_terminate = false;
/* Initiate our threads and store them in our threads vector */
for (int i = 0; i < this->thread_count; i++) {
this->threads.emplace_back(std::thread(&thread_pool::wait_for_task, this));
}
}
void dispatcher::thread_pool::queue_job(const std::function<void()> &job) {
/* push a job into our job queue safely by holding our queue lock */
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->jobs.push(job);
lock.unlock();
mutex_condition.notify_one();
}
void dispatcher::thread_pool::terminate() {
/* safely set our termination flag to true */
std::unique_lock<std::mutex> lock(this->queue_mutex);
should_terminate = true;
lock.unlock();
/* unlock all threads waiting on our condition */
mutex_condition.notify_all();
/* join the threads and clear our threads vector */
for (std::thread &thread : threads) {
thread.join();
}
threads.clear();
}
bool dispatcher::thread_pool::busy_wait() {
/* allows us to wait for when the job queue is empty allowing us to safely
* call the destructor */
std::unique_lock<std::mutex> lock(this->queue_mutex);
bool pool_busy = !jobs.empty();
this->queue_mutex.unlock();
return pool_busy;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <functional>
#include <mutex>
#include <queue>
#include <vector>
namespace dispatcher {
/*
* This ThreadPool class is a simple threadpool implementation that will allow
* us to delegate jobs to a set number of threads without the constant need to
* close and open new threads.
*/
class thread_pool {
int thread_count;
bool should_terminate;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
void wait_for_task();
public:
thread_pool(int thread_count);
void queue_job(const std::function<void()> &job);
void terminate();
bool busy_wait();
};
} // namespace dispatcher

169
module/helper.cpp Normal file
View file

@ -0,0 +1,169 @@
#include "helper.h"
#include <chrono>
#include <random>
void helper::generate_rand_seed() { srand(time(nullptr)); }
int helper::generate_rand_int(int max) { return rand() % max; }
void helper::sleep_thread(int seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));
}
int helper::get_report_id_from_buffer(void *buffer) {
kernel_interface::report_header *header =
reinterpret_cast<kernel_interface::report_header *>(buffer);
return header->report_id;
}
kernel_interface::report_id helper::get_kernel_report_type(void *buffer) {
switch (helper::get_report_id_from_buffer(buffer)) {
case kernel_interface::report_id::report_nmi_callback_failure:
return kernel_interface::report_id::report_nmi_callback_failure;
case kernel_interface::report_id::report_module_validation_failure:
return kernel_interface::report_id::report_module_validation_failure;
case kernel_interface::report_id::report_illegal_handle_operation:
return kernel_interface::report_id::report_illegal_handle_operation;
case kernel_interface::report_id::report_invalid_process_allocation:
return kernel_interface::report_id::report_invalid_process_allocation;
case kernel_interface::report_id::report_hidden_system_thread:
return kernel_interface::report_id::report_hidden_system_thread;
case kernel_interface::report_id::report_illegal_attach_process:
return kernel_interface::report_id::report_illegal_attach_process;
case kernel_interface::report_id::report_apc_stackwalk:
return kernel_interface::report_id::report_apc_stackwalk;
case kernel_interface::report_id::report_dpc_stackwalk:
return kernel_interface::report_id::report_dpc_stackwalk;
case kernel_interface::report_id::report_data_table_routine:
return kernel_interface::report_id::report_data_table_routine;
}
}
void helper::print_kernel_report(void *buffer) {
switch (get_kernel_report_type(buffer)) {
case kernel_interface::report_id::report_nmi_callback_failure: {
kernel_interface::nmi_callback_failure *r1 =
reinterpret_cast<kernel_interface::nmi_callback_failure *>(buffer);
LOG_INFO("report type: nmi_callback_failure");
LOG_INFO("report code: %lx", r1->report_code);
LOG_INFO("were_nmis_disabled: %lx", r1->were_nmis_disabled);
LOG_INFO("kthread_address: %llx", r1->kthread_address);
LOG_INFO("invalid_rip: %llx", r1->invalid_rip);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_invalid_process_allocation: {
kernel_interface::invalid_process_allocation_report *r2 =
reinterpret_cast<kernel_interface::invalid_process_allocation_report *>(
buffer);
LOG_INFO("report type: invalid_process_allocation_report");
LOG_INFO("report code: %d", r2->report_code);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_hidden_system_thread: {
kernel_interface::hidden_system_thread_report *r3 =
reinterpret_cast<kernel_interface::hidden_system_thread_report *>(
buffer);
LOG_INFO("report type: hidden_system_thread_report");
LOG_INFO("report code: %lx", r3->report_code);
LOG_INFO("found_in_kthreadlist: %lx", r3->found_in_kthreadlist);
LOG_INFO("found_in_pspcidtable: %lx", r3->found_in_pspcidtable);
LOG_INFO("thread_address: %llx", r3->thread_address);
LOG_INFO("thread_id: %lx", r3->thread_id);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_illegal_attach_process: {
kernel_interface::attach_process_report *r4 =
reinterpret_cast<kernel_interface::attach_process_report *>(buffer);
LOG_INFO("report type: attach_process_report");
LOG_INFO("report code: %lx", r4->report_code);
LOG_INFO("thread_id: %lx", r4->thread_id);
LOG_INFO("thread_address: %llx", r4->thread_address);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_illegal_handle_operation: {
kernel_interface::open_handle_failure_report *r5 =
reinterpret_cast<kernel_interface::open_handle_failure_report *>(
buffer);
LOG_INFO("report type: open_handle_failure_report");
LOG_INFO("report code: %lx", r5->report_code);
LOG_INFO("is_kernel_handle: %lx", r5->is_kernel_handle);
LOG_INFO("process_id: %lx", r5->process_id);
LOG_INFO("thread_id: %lx", r5->thread_id);
LOG_INFO("access: %lx", r5->access);
LOG_INFO("process_name: %s", r5->process_name);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_invalid_process_module: {
kernel_interface::process_module_validation_report *r6 =
reinterpret_cast<kernel_interface::process_module_validation_report *>(
buffer);
LOG_INFO("report type: process_module_validation_report");
LOG_INFO("report code: %d", r6->report_code);
LOG_INFO("image_base: %llx", r6->image_base);
LOG_INFO("image_size: %u", r6->image_size);
LOG_INFO("module_path: %ls", r6->module_path);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_apc_stackwalk: {
kernel_interface::apc_stackwalk_report *r7 =
reinterpret_cast<kernel_interface::apc_stackwalk_report *>(buffer);
LOG_INFO("report type: apc_stackwalk_report");
LOG_INFO("report code: %d", r7->report_code);
LOG_INFO("kthread_address: %llx", r7->kthread_address);
LOG_INFO("invalid_rip: %llx", r7->invalid_rip);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_dpc_stackwalk: {
kernel_interface::dpc_stackwalk_report *r8 =
reinterpret_cast<kernel_interface::dpc_stackwalk_report *>(buffer);
LOG_INFO("report type: dpc_stackwalk_report");
LOG_INFO("report code: %d", r8->report_code);
LOG_INFO("kthread_address: %llx", r8->kthread_address);
LOG_INFO("invalid_rip: %llx", r8->invalid_rip);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_data_table_routine: {
kernel_interface::data_table_routine_report *r9 =
reinterpret_cast<kernel_interface::data_table_routine_report *>(buffer);
LOG_INFO("report type: data_table_routine_report");
LOG_INFO("report code: %d", r9->report_code);
LOG_INFO("id: %d", r9->id);
LOG_INFO("address: %llx", r9->address);
LOG_INFO("routine: %s", r9->routine);
LOG_INFO("********************************");
break;
}
case kernel_interface::report_id::report_module_validation_failure: {
kernel_interface::module_validation_failure *r10 =
reinterpret_cast<kernel_interface::module_validation_failure *>(buffer);
LOG_INFO("report type: module_validation_failure");
LOG_INFO("report code: %lx", r10->report_code);
LOG_INFO("report type: %lx", r10->report_type);
LOG_INFO("driver_base_address: %llx", r10->driver_base_address);
LOG_INFO("driver_size: %llx", r10->driver_size);
LOG_INFO("driver_name: %s", r10->driver_name);
LOG_INFO("********************************");
break;
}
default:
LOG_INFO("Invalid report type.");
break;
}
}

12
module/helper.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
#include "kernel_interface/kernel_interface.h"
namespace helper {
void generate_rand_seed();
int generate_rand_int(int max);
void sleep_thread(int seconds);
kernel_interface::report_id get_kernel_report_type(void *buffer);
int get_report_id_from_buffer(void *buffer);
void print_kernel_report(void *buffer);
} // namespace helper

3
module/imports.cpp Normal file
View file

@ -0,0 +1,3 @@
#include "imports.h"
bool imports::initialise_imports() { return false; }

8
module/imports.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
namespace imports
{
bool initialise_imports();
}

View file

@ -0,0 +1,290 @@
#include "kernel_interface.h"
#include <iostream>
#include "../common.h"
#include "../helper.h"
#include <TlHelp32.h>
#include <winternl.h>
typedef BOOLEAN(NTAPI *RtlDosPathNameToNtPathName_U)(PCWSTR DosPathName,
PUNICODE_STRING NtPathName,
PCWSTR *NtFileNamePart,
PVOID DirectoryInfo);
kernel_interface::event_dispatcher *
kernel_interface::kernel_interface::get_free_event_entry() {
std::lock_guard<std::mutex> lock(this->lock);
for (std::vector<event_dispatcher>::iterator it = events.begin();
it != events.end(); it++) {
if (it->in_use == false) {
it->in_use = true;
return &(*it);
}
}
return nullptr;
}
void kernel_interface::kernel_interface::terminate_completion_port() {
std::lock_guard<std::mutex> lock(this->lock);
for (std::vector<event_dispatcher>::iterator it = events.begin();
it != events.end(); it++) {
free(it->buffer);
CloseHandle(it->overlapped.hEvent);
}
}
void kernel_interface::kernel_interface::run_completion_port() {
DWORD bytes = 0;
OVERLAPPED *io = nullptr;
ULONG_PTR key = 0;
while (true) {
GetQueuedCompletionStatus(this->port, &bytes, &key, &io, INFINITE);
if (io == nullptr)
continue;
void *buffer = get_buffer_from_event_object(io);
helper::print_kernel_report(buffer);
release_event_object(io);
send_pending_irp();
}
}
void kernel_interface::kernel_interface::initiate_completion_port() {
for (int index = 0; index < EVENT_COUNT; index++) {
void *buffer = malloc(MAXIMUM_REPORT_BUFFER_SIZE);
this->events.push_back(
event_dispatcher(buffer, MAXIMUM_REPORT_BUFFER_SIZE));
}
this->port = CreateIoCompletionPort(this->driver_handle, nullptr, 0, 0);
if (!this->port) {
LOG_ERROR("CreateIoCompletePort failed with status %x", GetLastError());
return;
}
for (int index = 0; index < EVENT_COUNT; index++) {
send_pending_irp();
}
}
void kernel_interface::kernel_interface::release_event_object(
OVERLAPPED *event) {
std::lock_guard<std::mutex> lock(this->lock);
for (std::vector<event_dispatcher>::iterator it = events.begin();
it != events.end(); it++) {
if (&it->overlapped == event) {
/* simply zero our the buffer, no need to free and realloc */
memset(it->buffer, 0, it->buffer_size);
it->in_use = false;
ResetEvent(it->overlapped.hEvent);
}
}
}
void *kernel_interface::kernel_interface::get_buffer_from_event_object(
OVERLAPPED *event) {
std::lock_guard<std::mutex> lock(this->lock);
for (std::vector<event_dispatcher>::iterator it = events.begin();
it != events.end(); it++) {
if (&it->overlapped == event) {
return it->buffer;
}
}
return nullptr;
}
kernel_interface::kernel_interface::kernel_interface(
LPCWSTR driver_name, client::message_queue &queue)
: message_queue(queue) {
this->driver_name = driver_name;
this->port = INVALID_HANDLE_VALUE;
this->driver_handle = CreateFileW(
driver_name, GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE, 0, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if (this->driver_handle == INVALID_HANDLE_VALUE) {
LOG_ERROR("Failed to open handle to driver with status 0x%x",
GetLastError());
return;
}
this->notify_driver_on_process_launch();
this->initiate_completion_port();
}
kernel_interface::kernel_interface::~kernel_interface() {
this->terminate_completion_port();
this->notify_driver_on_process_termination();
}
unsigned int kernel_interface::kernel_interface::generic_driver_call_output(
ioctl_code ioctl, void *output_buffer, size_t buffer_size,
unsigned long *bytes_returned) {
return DeviceIoControl(this->driver_handle, ioctl, nullptr, 0, output_buffer,
buffer_size, bytes_returned, nullptr);
}
void kernel_interface::kernel_interface::generic_driver_call_input(
ioctl_code ioctl, void *input_buffer, size_t buffer_size,
unsigned long *bytes_returned) {
if (!DeviceIoControl(this->driver_handle, ioctl, input_buffer, buffer_size,
nullptr, 0, bytes_returned, nullptr))
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
}
void kernel_interface::kernel_interface::generic_driver_call_apc(
apc_operation operation) {
apc_operation_init init = {0};
init.operation_id = operation;
this->generic_driver_call_input(ioctl_code::InitiateApcStackwalkOperation,
&init, sizeof(init), nullptr);
}
void kernel_interface::kernel_interface::notify_driver_on_process_launch() {
unsigned long bytes_returned = 0;
process_load_packet packet = {0};
packet.protected_process_id = GetCurrentProcessId();
generic_driver_call_input(ioctl_code::NotifyDriverOnProcessLaunch, &packet,
sizeof(packet), &bytes_returned);
}
void kernel_interface::kernel_interface::detect_system_virtualization() {
unsigned int status = 0;
unsigned long bytes_returned = 0;
hv_detection_packet packet = {0};
status = generic_driver_call_output(ioctl_code::PerformVirtualisationCheck,
&packet, sizeof(packet), &bytes_returned);
if (!status) {
LOG_ERROR("Failed virtualization detection with status %x", GetLastError());
return;
}
if (packet.aperf_msr_timing_check == true ||
packet.invd_emulation_check == true)
LOG_INFO("HYPERVISOR DETECTED!!!");
}
void kernel_interface::kernel_interface::generic_driver_call(ioctl_code ioctl) {
if (!DeviceIoControl(this->driver_handle, ioctl, nullptr, 0, nullptr, 0,
nullptr, nullptr))
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
}
void kernel_interface::kernel_interface::run_nmi_callbacks() {
this->generic_driver_call(ioctl_code::RunNmiCallbacks);
}
void kernel_interface::kernel_interface::validate_system_driver_objects() {
this->generic_driver_call(ioctl_code::ValidateDriverObjects);
}
void kernel_interface::kernel_interface::enumerate_handle_tables() {
this->generic_driver_call(ioctl_code::EnumerateHandleTables);
}
void kernel_interface::kernel_interface::scan_for_unlinked_processes() {
this->generic_driver_call(ioctl_code::ScanForUnlinkedProcesses);
}
void kernel_interface::kernel_interface::perform_integrity_check() {
this->generic_driver_call(ioctl_code::PerformModuleIntegrityCheck);
}
void kernel_interface::kernel_interface::
notify_driver_on_process_termination() {
this->generic_driver_call(ioctl_code::NotifyDriverOnProcessTermination);
}
void kernel_interface::kernel_interface::scan_for_attached_threads() {
this->generic_driver_call(ioctl_code::ScanFroAttachedThreads);
}
void kernel_interface::kernel_interface::scan_for_ept_hooks() {
this->generic_driver_call(ioctl_code::ScanForEptHooks);
}
void kernel_interface::kernel_interface::perform_dpc_stackwalk() {
this->generic_driver_call(ioctl_code::InitiateDpcStackwalk);
}
void kernel_interface::kernel_interface::validate_system_modules() {
this->generic_driver_call(ioctl_code::ValidateSystemModules);
}
void kernel_interface::kernel_interface::
verify_process_module_executable_regions() {
HANDLE handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
BOOLEAN status = FALSE;
process_module module = {0};
unsigned long bytes_returned = 0;
RtlDosPathNameToNtPathName_U pRtlDosPathNameToNtPathName_U = NULL;
UNICODE_STRING nt_path_name = {0};
pRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_U)GetProcAddress(
GetModuleHandle(L"ntdll.dll"), "RtlDosPathNameToNtPathName_U");
handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
GetCurrentProcessId());
if (handle == INVALID_HANDLE_VALUE) {
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with "
"status 0x%x",
GetLastError());
return;
}
module_entry.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(handle, &module_entry)) {
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
return;
}
do {
module.module_base = module_entry.modBaseAddr;
module.module_size = module_entry.modBaseSize;
status = (*pRtlDosPathNameToNtPathName_U)(module_entry.szExePath,
&nt_path_name, NULL, NULL);
if (!status) {
LOG_ERROR("RtlDosPathNameToNtPathName_U failed with no status.");
continue;
}
memcpy(module.module_path, nt_path_name.Buffer, MAX_MODULE_PATH);
this->generic_driver_call_input(ioctl_code::ValidateProcessLoadedModule,
&module, sizeof(module), &bytes_returned);
} while (Module32Next(handle, &module_entry));
end:
CloseHandle(handle);
}
void kernel_interface::kernel_interface::initiate_apc_stackwalk() {
this->generic_driver_call_apc(apc_operation::operation_stackwalk);
}
void kernel_interface::kernel_interface::send_pending_irp() {
DWORD status = 0;
event_dispatcher *event = get_free_event_entry();
if (!event) {
LOG_ERROR("All event objects in use.");
return;
}
status = DeviceIoControl(
this->driver_handle, ioctl_code::InsertIrpIntoIrpQueue, NULL, NULL,
event->buffer, event->buffer_size, NULL, &event->overlapped);
/*
* im not sure why this returns a status of ERROR_INVALID_FUNCTION when we use
* the inserted irp to complete a deferred irp - even though that procedure
* should return STATUS_SUCCESS? Weird.. Anyhow it works.
*/
if (status == ERROR_IO_PENDING || status == ERROR_SUCCESS ||
status == ERROR_INVALID_FUNCTION)
return;
LOG_ERROR("failed to insert irp into irp queue %x", status);
}
//void kernel_interface::kernel_interface::query_deferred_reports() {
// unsigned long bytes_returned = 0;
// void *buffer = malloc(MAXIMUM_REPORT_BUFFER_SIZE);
// if (!buffer)
// return;
// for (int i = 0; i < QUERY_DEFERRED_REPORT_COUNT; i++) {
// unsigned int status =
// generic_driver_call_output(ioctl_code::QueryDeferredReports, buffer,
// MAXIMUM_REPORT_BUFFER_SIZE, &bytes_returned);
// if (status && bytes_returned > 0)
// helper::print_kernel_report(buffer);
// memset(buffer, 0, MAXIMUM_REPORT_BUFFER_SIZE);
// }
// free(buffer);
//}

View file

@ -0,0 +1,221 @@
#pragma once
#include <Windows.h>
#include "../client/message_queue.h"
namespace kernel_interface {
static constexpr int EVENT_COUNT = 5;
static constexpr int MAX_MODULE_PATH = 256;
static constexpr int MAXIMUM_REPORT_BUFFER_SIZE = 1000;
static constexpr int QUERY_DEFERRED_REPORT_COUNT = 10;
enum report_id {
report_nmi_callback_failure = 50,
report_module_validation_failure = 60,
report_illegal_handle_operation = 70,
report_invalid_process_allocation = 80,
report_hidden_system_thread = 90,
report_illegal_attach_process = 100,
report_apc_stackwalk = 110,
report_dpc_stackwalk = 120,
report_data_table_routine = 130,
report_invalid_process_module = 140
};
struct report_header {
int report_id;
};
constexpr int APC_STACKWALK_BUFFER_SIZE = 500;
constexpr int DATA_TABLE_ROUTINE_BUF_SIZE = 256;
constexpr int REPORT_INVALID_PROCESS_BUFFER_SIZE = 500;
constexpr int HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH = 64;
constexpr int MODULE_PATH_LEN = 256;
struct apc_stackwalk_report {
int report_code;
uint64_t kthread_address;
uint64_t invalid_rip;
char driver[APC_STACKWALK_BUFFER_SIZE];
};
struct dpc_stackwalk_report {
uint32_t report_code;
uint64_t kthread_address;
uint64_t invalid_rip;
char driver[APC_STACKWALK_BUFFER_SIZE];
};
struct module_validation_failure {
int report_code;
int report_type;
uint64_t driver_base_address;
uint64_t driver_size;
char driver_name[128];
};
enum table_id { hal_dispatch = 0, hal_private_dispatch };
struct data_table_routine_report {
uint32_t report_code;
table_id id;
uint64_t address;
char routine[DATA_TABLE_ROUTINE_BUF_SIZE];
};
struct nmi_callback_failure {
int report_code;
int were_nmis_disabled;
uint64_t kthread_address;
uint64_t invalid_rip;
};
struct invalid_process_allocation_report {
int report_code;
char process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
};
struct hidden_system_thread_report {
int report_code;
int found_in_kthreadlist;
int found_in_pspcidtable;
uint64_t thread_address;
long thread_id;
char thread[500];
};
struct attach_process_report {
int report_code;
uint32_t thread_id;
uint64_t thread_address;
};
struct kprcb_thread_validation_ctx {
uint64_t thread;
bool thread_found_in_pspcidtable;
bool finished;
};
struct open_handle_failure_report {
int report_code;
int is_kernel_handle;
long process_id;
long thread_id;
long access;
char process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
};
struct process_module_validation_report {
int report_code;
uint64_t image_base;
uint32_t image_size;
wchar_t module_path[MODULE_PATH_LEN];
};
enum apc_operation { operation_stackwalk = 0x1 };
// clang-format off
enum ioctl_code
{
RunNmiCallbacks = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS),
ValidateDriverObjects = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS),
NotifyDriverOnProcessLaunch = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS),
QueryForApcCompletion = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS),
PerformVirtualisationCheck = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS),
EnumerateHandleTables = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS),
NotifyDriverOnProcessTermination = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS),
ScanForUnlinkedProcesses = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS),
PerformModuleIntegrityCheck = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS),
ScanFroAttachedThreads = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS),
ValidateProcessLoadedModule = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS),
RequestHardwareInformation = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS),
InitiateApcStackwalkOperation = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS),
ScanForEptHooks = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS),
InitiateDpcStackwalk = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS),
ValidateSystemModules = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS),
InsertIrpIntoIrpQueue = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20021, METHOD_BUFFERED, FILE_ANY_ACCESS),
QueryDeferredReports = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20022, METHOD_BUFFERED, FILE_ANY_ACCESS)
};
// clang-format on
struct event_dispatcher {
bool in_use;
OVERLAPPED overlapped;
void *buffer;
unsigned long buffer_size;
event_dispatcher(void *buffer, unsigned long buffer_size) {
this->in_use = false;
this->overlapped.hEvent = CreateEvent(nullptr, false, false, nullptr);
this->buffer = buffer;
this->buffer_size = buffer_size;
}
};
class kernel_interface {
struct process_load_packet {
unsigned long protected_process_id;
};
struct hv_detection_packet {
unsigned long aperf_msr_timing_check;
unsigned long invd_emulation_check;
};
struct process_module {
void *module_base;
size_t module_size;
wchar_t module_path[MAX_MODULE_PATH];
};
struct apc_operation_init {
int operation_id;
};
HANDLE driver_handle;
LPCWSTR driver_name;
client::message_queue &message_queue;
HANDLE port;
std::mutex lock;
std::vector<event_dispatcher> events;
void initiate_completion_port();
void terminate_completion_port();
event_dispatcher *get_free_event_entry();
void release_event_object(OVERLAPPED *event);
void *get_buffer_from_event_object(OVERLAPPED *event);
void notify_driver_on_process_launch();
void notify_driver_on_process_termination();
void generic_driver_call(ioctl_code ioctl);
unsigned int generic_driver_call_output(ioctl_code ioctl, void *output_buffer,
size_t buffer_size,
unsigned long *bytes_returned);
void generic_driver_call_input(ioctl_code ioctl, void *input_buffer,
size_t buffer_size,
unsigned long *bytes_returned);
void generic_driver_call_apc(apc_operation operation);
public:
kernel_interface(LPCWSTR driver_name, client::message_queue &queue);
~kernel_interface();
void run_completion_port();
void run_nmi_callbacks();
void validate_system_driver_objects();
void detect_system_virtualization();
void enumerate_handle_tables();
void scan_for_unlinked_processes();
void perform_integrity_check();
void scan_for_attached_threads();
void scan_for_ept_hooks();
void perform_dpc_stackwalk();
void validate_system_modules();
void verify_process_module_executable_regions();
void initiate_apc_stackwalk();
void send_pending_irp();
void query_deferred_reports();
};
} // namespace kernel_interface

33
module/main.cpp Normal file
View file

@ -0,0 +1,33 @@
#include <Windows.h>
#include "module.h"
DWORD WINAPI Init(HINSTANCE hinstDLL) { module::run(hinstDLL); }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
DisableThreadLibraryCalls(hModule);
const auto thread =
CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
hModule, 0, nullptr);
if (thread)
CloseHandle(thread);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
{
LOG_INFO("process closing!");
break;
}
}
return TRUE;
}

31
module/module.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "module.h"
#include <Windows.h>
#include "client/message_queue.h"
#include "dispatcher/dispatcher.h"
void module::run(HINSTANCE hinstDLL) {
AllocConsole();
FILE *file;
freopen_s(&file, "CONOUT$", "w", stdout);
freopen_s(&file, "CONIN$", "r", stdin);
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
LPCWSTR driver_name = L"\\\\.\\DonnaAC";
client::message_queue queue(pipe_name);
dispatcher::dispatcher dispatch(driver_name, queue);
dispatch.run();
fclose(stdout);
fclose(stdin);
FreeConsole();
FreeLibraryAndExitThread(hinstDLL, 0);
}
void module::terminate()
{
}

10
module/module.h Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "common.h"
#include <Windows.h>
namespace module {
void run(HINSTANCE hinstDLL);
void terminate();
} // namespace module

167
module/module.vcxproj Normal file
View file

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{3b18467a-4358-45ef-81b1-5c6f9b0b6728}</ProjectGuid>
<RootNamespace>module</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="helper.cpp" />
<ClCompile Include="imports.cpp" />
<ClCompile Include="module.cpp" />
<ClCompile Include="client\message_queue.cpp" />
<ClCompile Include="client\pipe.cpp" />
<ClCompile Include="dispatcher\dispatcher.cpp" />
<ClCompile Include="dispatcher\threadpool.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="kernel_interface\kernel_interface.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="client\message_queue.h" />
<ClInclude Include="client\pipe.h" />
<ClInclude Include="dispatcher\dispatcher.h" />
<ClInclude Include="dispatcher\threadpool.h" />
<ClInclude Include="common.h" />
<ClInclude Include="helper.h" />
<ClInclude Include="imports.h" />
<ClInclude Include="kernel_interface\kernel_interface.h" />
<ClInclude Include="module.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -18,28 +18,28 @@
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="um\umanager.cpp">
<ClCompile Include="kernel_interface\kernel_interface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="km\kmanager.cpp">
<ClCompile Include="dispatcher\dispatcher.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="um\process.cpp">
<ClCompile Include="dispatcher\threadpool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="threadpool.cpp">
<ClCompile Include="client\message_queue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="um\imports.cpp">
<ClCompile Include="client\pipe.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="km\driver.cpp">
<ClCompile Include="module.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="client.cpp">
<ClCompile Include="helper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pipe.cpp">
<ClCompile Include="imports.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@ -47,28 +47,28 @@
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="um\umanager.h">
<ClInclude Include="kernel_interface\kernel_interface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="km\kmanager.h">
<ClInclude Include="dispatcher\dispatcher.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="um\process.h">
<ClInclude Include="dispatcher\threadpool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="threadpool.h">
<ClInclude Include="client\message_queue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="um\imports.h">
<ClInclude Include="client\pipe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="km\driver.h">
<ClInclude Include="module.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="client.h">
<ClInclude Include="helper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pipe.h">
<ClInclude Include="imports.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>

View file

@ -3,81 +3,65 @@
UNICODE_STRING DRIVER_NAME = RTL_CONSTANT_STRING(L"donna-ac-test");
UNICODE_STRING DRIVER_LINK = RTL_CONSTANT_STRING(L"donna-ac-test-link");
#define IOCTL_RUN_NMI_CALLBACKS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_RUN_NMI_CALLBACKS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
NTSTATUS
DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
switch (stack_location->Parameters.DeviceIoControl.IoControlCode)
{
}
switch (stack_location->Parameters.DeviceIoControl.IoControlCode) {}
end:
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
DeviceClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
DeviceClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
NTSTATUS
DeviceCreate(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
DeviceCreate(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) {
UNREFERENCED_PARAMETER(DeviceObject);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
STATIC
VOID
DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
IoDeleteDevice(DriverObject->DeviceObject);
VOID DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
IoDeleteDevice(DriverObject->DeviceObject);
}
extern "C" NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath) {
NTSTATUS status;
extern "C"
NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
status = IoCreateDevice(DriverObject, NULL, &DRIVER_NAME, FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN, FALSE,
&DriverObject->DeviceObject);
status = IoCreateDevice(DriverObject,
NULL,
&DRIVER_NAME,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&DriverObject->DeviceObject);
if (!NT_SUCCESS(status)) {
return STATUS_FAILED_DRIVER_ENTRY;
}
if (!NT_SUCCESS(status))
{
return STATUS_FAILED_DRIVER_ENTRY;
}
status = IoCreateSymbolicLink(&DRIVER_LINK, &DRIVER_NAME);
status = IoCreateSymbolicLink(&DRIVER_LINK, &DRIVER_NAME);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(DriverObject->DeviceObject);
return STATUS_FAILED_DRIVER_ENTRY;
}
if (!NT_SUCCESS(status))
{
IoDeleteDevice(DriverObject->DeviceObject);
return STATUS_FAILED_DRIVER_ENTRY;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
return STATUS_SUCCESS;
}

View file

@ -1,11 +1,7 @@
#include "patch.hpp"
namespace framework {
patch::patch(char* image_name)
{
}
patch::patch(char *image_name) {}
patch::~patch()
{
}
}
patch::~patch() {}
} // namespace framework

View file

@ -1,83 +0,0 @@
#include "client.h"
#include "common.h"
#include <cmath>
#define TEST_STEAM_64_ID 123456789;
global::Client::Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName)
{
this->thread_pool = ThreadPool;
#if NO_SERVER
LOG_INFO("No_Server build used. Not opening named pipe.");
#else
this->pipe = std::make_shared<global::Pipe>(PipeName);
#endif
}
/*
* Request an item from the server
*/
void
global::Client::ServerReceive(PVOID Buffer, SIZE_T Size)
{
this->pipe->ReadPipe(Buffer, Size);
}
/*
* Send an item to the server
*/
void
global::Client::ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId)
{
#if NO_SERVER
return;
#else
mutex.lock();
SIZE_T total_header_size = sizeof(global::headers::CLIENT_SEND_PACKET_HEADER) +
sizeof(global::headers::PIPE_PACKET_HEADER);
if (Size + total_header_size > MAX_CLIENT_SEND_PACKET_SIZE)
{
LOG_ERROR("Packet is too large to send");
mutex.unlock();
return;
}
PVOID send_buffer = malloc(total_header_size + Size);
if (send_buffer == nullptr)
{
mutex.unlock();
return;
}
RtlZeroMemory(send_buffer, total_header_size + Size);
global::headers::PIPE_PACKET_HEADER header = {0};
header.message_type = MESSAGE_TYPE_CLIENT_SEND;
header.steam64_id = TEST_STEAM_64_ID;
memcpy(send_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
global::headers::CLIENT_SEND_PACKET_HEADER header_extension = {0};
header_extension.request_id = RequestId;
header_extension.packet_size = Size + total_header_size;
memcpy(PVOID((UINT64)send_buffer + sizeof(global::headers::PIPE_PACKET_HEADER)),
&header_extension,
sizeof(global::headers::CLIENT_SEND_PACKET_HEADER));
memcpy(PVOID((UINT64)send_buffer + total_header_size), Buffer, Size);
LOG_INFO("Writing to pipe");
this->pipe->WriteToPipe(send_buffer, header_extension.packet_size);
mutex.unlock();
free(send_buffer);
#endif
}

View file

@ -1,237 +0,0 @@
#ifndef REPORT_H
#define REPORT_H
#include <Windows.h>
#include "threadpool.h"
#include "pipe.h"
#include <TlHelp32.h>
#include "common.h"
#define REPORT_BUFFER_SIZE 8192
#define SEND_BUFFER_SIZE 8192
#define MAX_SIGNATURE_SIZE 256
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
#define REPORT_CODE_PROCESS_MODULE_VERIFICATION 10
#define REPORT_CODE_START_ADDRESS_VERIFICATION 20
#define REPORT_PAGE_PROTECTION_VERIFICATION 30
#define REPORT_PATTERN_SCAN_FAILURE 40
#define REPORT_NMI_CALLBACK_FAILURE 50
#define REPORT_MODULE_VALIDATION_FAILURE 60
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
#define REPORT_INVALID_PROCESS_ALLOCATION 80
#define REPORT_HIDDEN_SYSTEM_THREAD 90
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
#define REPORT_APC_STACKWALK 110
#define REPORT_DPC_STACKWALK 120
#define REPORT_DATA_TABLE_ROUTINE 130
#define TEST_STEAM_64_ID 123456789;
enum REPORT_CODES
{
USERMODE_MODULE = 10,
START_ADDRESS = 20,
PAGE_PROTECTION = 30,
PATTERN_SCAN = 40,
NMI_CALLBACK = 50,
SYSTEM_MODULE = 60,
HANDLE_OPERATION = 70
};
#define CLIENT_REQUEST_MODULE_INTEGRITY_CHECK 10
#define CLIENT_SEND_SYSTEM_INFORMATION 10
#define MAX_CLIENT_SEND_PACKET_SIZE 60000
enum SERVER_SEND_CODES
{
MODULE_INTEGRITY_CHECK = 10
};
namespace global {
class Client
{
std::shared_ptr<global::ThreadPool> thread_pool;
std::shared_ptr<global::Pipe> pipe;
std::mutex mutex;
byte report_buffer[REPORT_BUFFER_SIZE];
public:
Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName);
void UpdateSystemInformation(global::headers::SYSTEM_INFORMATION* SystemInformation);
/* lock buffer, attach header, copy report, send to service then clear buffer */
template <typename T>
void ReportViolation(T* Report)
{
#if NO_SERVER
return;
#else
mutex.lock();
global::headers::PIPE_PACKET_HEADER header = {0};
header.message_type = MESSAGE_TYPE_CLIENT_REPORT;
header.steam64_id = TEST_STEAM_64_ID;
memcpy(&this->report_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
memcpy(PVOID((UINT64)this->report_buffer +
sizeof(global::headers::PIPE_PACKET_HEADER)),
Report,
sizeof(T));
this->pipe->WriteToPipe(this->report_buffer,
sizeof(T) + sizeof(global::headers::PIPE_PACKET_HEADER));
RtlZeroMemory(this->report_buffer, REPORT_BUFFER_SIZE);
mutex.unlock();
#endif
}
void ServerReceive(PVOID Buffer, SIZE_T Size);
void ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId);
};
namespace report_structures {
struct PROCESS_MODULES_INTEGRITY_CHECK_FAILURE
{
INT report_code;
UINT64 module_base_address;
UINT64 module_size;
CHAR module_name[256];
};
struct PROCESS_THREAD_START_FAILURE
{
INT report_code;
LONG thread_id;
UINT64 start_address;
};
struct PAGE_PROTECTION_FAILURE
{
INT report_code;
UINT64 page_base_address;
LONG allocation_protection;
LONG allocation_state;
LONG allocation_type;
};
struct PATTERN_SCAN_FAILURE
{
INT report_code;
INT signature_id;
UINT64 address;
};
struct NMI_CALLBACK_FAILURE
{
INT report_code;
INT were_nmis_disabled;
UINT64 kthread_address;
UINT64 invalid_rip;
};
struct MODULE_VALIDATION_FAILURE_HEADER
{
INT module_count;
};
struct MODULE_VALIDATION_FAILURE
{
INT report_code;
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[128];
};
struct REPORT_QUEUE_HEADER
{
INT count;
};
struct OPEN_HANDLE_FAILURE_REPORT
{
INT report_code;
INT is_kernel_handle;
LONG process_id;
LONG thread_id;
LONG desired_access;
CHAR process_name[64];
};
struct INVALID_PROCESS_ALLOCATION_REPORT
{
INT report_code;
CHAR process[4096];
};
/*
* No point copying data from the start address here
* since people can easily change it.
*/
struct HIDDEN_SYSTEM_THREAD_REPORT
{
INT report_code;
INT found_in_kthreadlist;
INT found_in_pspcidtable;
UINT64 thread_address;
LONG thread_id;
CHAR thread[4096];
};
struct ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
};
struct SYSTEM_INFORMATION_REQUEST_RESPONSE
{
INT RequestId;
INT CanUserProceed;
INT reason;
};
struct APC_STACKWALK_REPORT
{
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[4096];
};
struct DPC_STACKWALK_REPORT
{
UINT32 report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[4096];
};
enum TABLE_ID
{
HalDispatch = 0,
HalPrivateDispatch
};
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
struct DATA_TABLE_ROUTINE_REPORT
{
UINT32 report_code;
TABLE_ID id;
UINT64 address;
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
};
}
}
#endif

View file

@ -1,671 +0,0 @@
#include "driver.h"
#include <iostream>
#include "../common.h"
#include <winternl.h>
typedef BOOLEAN(NTAPI* RtlDosPathNameToNtPathName_U)(PCWSTR DosPathName,
PUNICODE_STRING NtPathName,
PCWSTR* NtFileNamePart,
PVOID DirectoryInfo);
using namespace global::report_structures;
kernelmode::Driver::Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface)
{
this->driver_name = DriverName;
this->report_interface = ReportInterface;
this->driver_handle = CreateFileW(DriverName,
GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0);
if (this->driver_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("Failed to open handle to driver with status 0x%x", GetLastError());
return;
}
this->NotifyDriverOnProcessLaunch();
}
kernelmode::Driver::~Driver()
{
this->NotifyDriverOnProcessTermination();
}
VOID
kernelmode::Driver::RunNmiCallbacks()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
NMI_CALLBACK_FAILURE report = {0};
status = DeviceIoControl(this->driver_handle,
IOCTL_RUN_NMI_CALLBACKS,
NULL,
NULL,
&report,
sizeof(NMI_CALLBACK_FAILURE),
&bytes_returned,
(LPOVERLAPPED)NULL);
if (status == NULL)
{
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
return;
}
if (bytes_returned == NULL)
{
LOG_INFO("All threads valid, nmis fine.");
return;
}
/* else, report */
this->report_interface->ReportViolation(&report);
}
/*
* 1. Checks that every device object has a system module to back it
* 2. Checks the IOCTL dispatch routines to ensure they lie within the module
*/
VOID
kernelmode::Driver::VerifySystemModuleDriverObjects()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
PVOID buffer = NULL;
SIZE_T buffer_size = 0;
SIZE_T header_size = 0;
/*
* allocate enough to report 5 invalid driver objects + header. The reason we use a raw
* pointer here is so we can pass the address to DeviceIoControl. You are not able (atleast
* as far as im concerned) to pass a shared ptr to DeviceIoControl.
*/
header_size = sizeof(MODULE_VALIDATION_FAILURE_HEADER);
buffer_size =
sizeof(MODULE_VALIDATION_FAILURE) * MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT +
header_size;
buffer = malloc(buffer_size);
if (!buffer)
return;
status = DeviceIoControl(this->driver_handle,
IOCTL_VALIDATE_DRIVER_OBJECTS,
NULL,
NULL,
buffer,
buffer_size,
&bytes_returned,
NULL);
if (status == NULL)
{
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
free(buffer);
return;
}
if (bytes_returned == NULL)
{
LOG_INFO("All modules valid :)");
free(buffer);
return;
}
/*
* We are splitting up each packet here and passing them on one by one since
* if I am being honest it is just easier in c++ and that way the process
* is streamlined just like all other report packets.
*/
MODULE_VALIDATION_FAILURE_HEADER* header = (MODULE_VALIDATION_FAILURE_HEADER*)buffer;
LOG_INFO("Module count: %lx", header->module_count);
for (int i = 0; i < header->module_count; i++)
{
MODULE_VALIDATION_FAILURE* report =
(MODULE_VALIDATION_FAILURE*)((UINT64)buffer +
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
i * sizeof(MODULE_VALIDATION_FAILURE));
this->report_interface->ReportViolation(report);
}
free(buffer);
}
/*
* HOW THIS WILL WORK:
*
* 1. On driver initiation, ObRegisterCallbacks will be registered
* 2. Each time a process that is not whitelisted tries to open a handle
* to our game we will store the report in an a report queue
* 3. the user mode app will then periodically query the driver asking
* how many pending reports there are
* 4. once the number is received, the app will allocate a buffer large enough
* for all the reports and once again call CompleteQueuedCallbackReports
* 5. This will then retrieve the reports into the buffer and from there
* we can iteratively report them the same way as we do with the system
* modules.
*/
struct REPORT_ID
{
INT report_id;
};
VOID
kernelmode::Driver::QueryReportQueue()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
PVOID buffer = NULL;
LONG buffer_size = 0;
REPORT_ID* report_header = NULL;
SIZE_T total_size = NULL;
OPEN_HANDLE_FAILURE_REPORT handle_report = {0};
ATTACH_PROCESS_REPORT attach_report = {0};
INVALID_PROCESS_ALLOCATION_REPORT allocation_report = {0};
APC_STACKWALK_REPORT apc_report = {0};
HIDDEN_SYSTEM_THREAD_REPORT hidden_report = {0};
/* allocate enough for the largest report buffer * max reports */
buffer_size =
sizeof(APC_STACKWALK_REPORT) * MAX_REPORTS_PER_IRP + sizeof(REPORT_QUEUE_HEADER);
/* this isnt very c++ of us... */
buffer = malloc(buffer_size);
status = DeviceIoControl(this->driver_handle,
IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE,
NULL,
NULL,
buffer,
buffer_size,
&bytes_returned,
NULL);
if (status == NULL)
{
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
free(buffer);
return;
}
REPORT_QUEUE_HEADER* header = (REPORT_QUEUE_HEADER*)buffer;
if (!header || !header->count)
goto end;
for (INT index = 0; index < header->count; index++)
{
report_header =
(REPORT_ID*)((UINT64)buffer + sizeof(REPORT_QUEUE_HEADER) + total_size);
LOG_INFO("Report id: %d", report_header->report_id);
switch (report_header->report_id)
{
case REPORT_ILLEGAL_ATTACH_PROCESS:
ReportTypeFromReportQueue<ATTACH_PROCESS_REPORT>(
buffer, &total_size, &attach_report);
break;
case REPORT_ILLEGAL_HANDLE_OPERATION:
ReportTypeFromReportQueue<OPEN_HANDLE_FAILURE_REPORT>(
buffer, &total_size, &handle_report);
break;
case REPORT_INVALID_PROCESS_ALLOCATION:
ReportTypeFromReportQueue<INVALID_PROCESS_ALLOCATION_REPORT>(
buffer, &total_size, &allocation_report);
break;
case REPORT_APC_STACKWALK:
ReportTypeFromReportQueue<APC_STACKWALK_REPORT>(
buffer, &total_size, &apc_report);
break;
case REPORT_HIDDEN_SYSTEM_THREAD:
ReportTypeFromReportQueue<HIDDEN_SYSTEM_THREAD_REPORT>(
buffer, &total_size, &hidden_report);
break;
case REPORT_DPC_STACKWALK:
ReportTypeFromReportQueue<DPC_STACKWALK_REPORT>(
buffer, &total_size, &hidden_report);
break;
case REPORT_DATA_TABLE_ROUTINE:
ReportTypeFromReportQueue<DATA_TABLE_ROUTINE_REPORT>(
buffer, &total_size, &hidden_report);
break;
default: break;
}
}
end:
free(buffer);
}
VOID
kernelmode::Driver::RunCallbackReportQueue()
{
/*TODO have some volatile flag instead */
this->QueryReportQueue();
}
VOID
kernelmode::Driver::NotifyDriverOnProcessLaunch()
{
BOOLEAN status = FALSE;
kernelmode::DRIVER_INITIATION_INFORMATION information = {0};
information.protected_process_id = GetCurrentProcessId();
status = DeviceIoControl(this->driver_handle,
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH,
&information,
sizeof(kernelmode::DRIVER_INITIATION_INFORMATION),
NULL,
NULL,
NULL,
NULL);
if (status == NULL)
LOG_ERROR("Failed to notify driver on process launch 0x%x", GetLastError());
}
VOID
kernelmode::Driver::DetectSystemVirtualization()
{
BOOLEAN status = FALSE;
HYPERVISOR_DETECTION_REPORT report = {0};
DWORD bytes_returned = 0;
status = DeviceIoControl(this->driver_handle,
IOCTL_PERFORM_VIRTUALIZATION_CHECK,
NULL,
NULL,
&report,
sizeof(HYPERVISOR_DETECTION_REPORT),
&bytes_returned,
NULL);
if (status == NULL)
{
LOG_ERROR("DeviceIoControl failed virtualization detect with status %x",
GetLastError());
return;
}
if (report.aperf_msr_timing_check == TRUE || report.invd_emulation_check == TRUE)
LOG_INFO("HYPERVISOR DETECTED!!!");
/* shutdown the application or smth lmao */
}
VOID
kernelmode::Driver::CheckHandleTableEntries()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = {0};
/*
* Only pass the IOCTL code and nothing else since the reports are bundled
* with the handle ObRegisterCallbacks report queue hence the QueryReportQueue
* function will handle these reports.
*/
status = DeviceIoControl(this->driver_handle,
IOCTL_ENUMERATE_HANDLE_TABLES,
NULL,
NULL,
NULL,
NULL,
&bytes_returned,
NULL);
if (status == NULL)
LOG_ERROR("CheckHandleTableEntries failed with status %x", status);
}
VOID
kernelmode::Driver::RequestModuleExecutableRegions()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
ULONG module_size = 0;
PVOID buffer = NULL;
module_size = this->RequestTotalModuleSize();
if (module_size == NULL)
{
LOG_ERROR("RequestTotalModuleSize failed lolz");
return;
}
LOG_INFO("module size: %lx", module_size);
/*
* allocate a buffer big enough for the entire module not including section headers or
* packet headers, however it should be big enough since executable sections do not
* make up 100% of the image size. Bit hacky but it works.
*/
buffer = malloc(module_size);
if (!buffer)
return;
status = DeviceIoControl(this->driver_handle,
IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS,
NULL,
NULL,
buffer,
module_size,
&bytes_returned,
NULL);
if (status == NULL)
{
LOG_ERROR("failed to retrieve module executable regions lozl %x", GetLastError());
goto end;
}
LOG_INFO("bytes returned: %lx", bytes_returned);
this->report_interface->ServerSend(
buffer, bytes_returned, CLIENT_REQUEST_MODULE_INTEGRITY_CHECK);
end:
free(buffer);
}
VOID
kernelmode::Driver::ScanForUnlinkedProcess()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
INVALID_PROCESS_ALLOCATION_REPORT report = {0};
status = DeviceIoControl(this->driver_handle,
IOCTL_SCAN_FOR_UNLINKED_PROCESS,
NULL,
NULL,
&report,
sizeof(report),
&bytes_returned,
NULL);
if (status == NULL)
{
LOG_ERROR("failed to scan for unlinked processes %x", GetLastError());
return;
}
}
VOID
kernelmode::Driver::PerformIntegrityCheck()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_PERFORM_INTEGRITY_CHECK, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("Failed to perform integrity check with status %x", status);
}
ULONG
kernelmode::Driver::RequestTotalModuleSize()
{
BOOLEAN status = FALSE;
DWORD bytes_returned = 0;
ULONG module_size = 0;
status = DeviceIoControl(this->driver_handle,
IOCTL_REQUEST_TOTAL_MODULE_SIZE,
NULL,
NULL,
&module_size,
sizeof(ULONG),
&bytes_returned,
NULL);
if (status == NULL)
LOG_ERROR("CheckHandleTableEntries failed with status %x", status);
return module_size;
}
VOID
kernelmode::Driver::NotifyDriverOnProcessTermination()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(this->driver_handle,
IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
if (status == NULL)
LOG_ERROR("NotifyDriverOnProcessTermination failed with status %x", status);
}
VOID
kernelmode::Driver::CheckForAttachedThreads()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_DETECT_ATTACHED_THREADS, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("failed to check for attached threads %x", GetLastError());
}
VOID
kernelmode::Driver::CheckForEptHooks()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_CHECK_FOR_EPT_HOOK, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("failed to check for ept hooks %x", GetLastError());
}
VOID
kernelmode::Driver::StackwalkThreadsViaDpc()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_LAUNCH_DPC_STACKWALK, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("failed to stackwalk threads via dpc %x", GetLastError());
}
VOID
kernelmode::Driver::ValidateSystemModules()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_VALIDATE_SYSTEM_MODULES, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("failed to validate system modules %x", GetLastError());
}
VOID
kernelmode::Driver::CheckDriverHeartbeat()
{
}
VOID
kernelmode::Driver::VerifyProcessLoadedModuleExecutableRegions()
{
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
BOOLEAN status = FALSE;
PROCESS_MODULE_INFORMATION module_information = {0};
PROCESS_MODULE_VALIDATION_RESULT validation_result = {0};
DWORD bytes_returned = 0;
RtlDosPathNameToNtPathName_U pRtlDosPathNameToNtPathName_U = NULL;
UNICODE_STRING nt_path_name = {0};
pRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_U)GetProcAddress(
GetModuleHandle(L"ntdll.dll"), "RtlDosPathNameToNtPathName_U");
process_modules_handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
GetCurrentProcessId());
if (process_modules_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
GetLastError());
return;
}
module_entry.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(process_modules_handle, &module_entry))
{
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
return;
}
do
{
module_information.module_base = module_entry.modBaseAddr;
module_information.module_size = module_entry.modBaseSize;
status = (*pRtlDosPathNameToNtPathName_U)(
module_entry.szExePath, &nt_path_name, NULL, NULL);
if (!status)
{
LOG_ERROR("RtlDosPathNameToNtPathName_U failed with no status.");
continue;
}
memcpy(module_information.module_path, nt_path_name.Buffer, MAX_MODULE_PATH);
status = DeviceIoControl(this->driver_handle,
IOCTL_VALIDATE_PROCESS_LOADED_MODULE,
&module_information,
sizeof(module_information),
&validation_result,
sizeof(validation_result),
&bytes_returned,
NULL);
if (status == NULL || bytes_returned == NULL)
{
LOG_ERROR("failed to validate process module with status %x",
GetLastError());
continue;
}
if (validation_result.is_module_valid == FALSE)
{
/*TODO: copy module aswell from an anomaly offset */
PROCESS_MODULES_INTEGRITY_CHECK_FAILURE report;
report.report_code = REPORT_CODE_PROCESS_MODULE_VERIFICATION;
report.module_base_address = (UINT64)module_entry.modBaseAddr;
report.module_size = module_entry.modBaseSize;
std::wstring wstr(module_entry.szModule);
std::string module_name_string = std::string(wstr.begin(), wstr.end());
memcpy(
&report.module_name, &module_name_string, module_name_string.length());
this->report_interface->ReportViolation(&report);
}
else
{
LOG_INFO("Module %S is valid", module_entry.szModule);
}
} while (Module32Next(process_modules_handle, &module_entry));
end:
CloseHandle(process_modules_handle);
}
VOID
kernelmode::Driver::SendClientHardwareInformation()
{
BOOLEAN status = FALSE;
global::headers::SYSTEM_INFORMATION system_information = {0};
DWORD bytes_returned = 0;
status = DeviceIoControl(this->driver_handle,
IOCTL_REQUEST_HARDWARE_INFORMATION,
NULL,
NULL,
&system_information,
sizeof(global::headers::SYSTEM_INFORMATION),
&bytes_returned,
NULL);
if (status == NULL || bytes_returned == NULL)
{
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
return;
}
this->report_interface->ServerSend(&system_information,
sizeof(global::headers::SYSTEM_INFORMATION),
CLIENT_SEND_SYSTEM_INFORMATION);
}
BOOLEAN
kernelmode::Driver::InitiateApcOperation(INT OperationId)
{
BOOLEAN status = FALSE;
APC_OPERATION_INFORMATION operation = {0};
operation.operation_id = OperationId;
status = DeviceIoControl(this->driver_handle,
IOCTL_INITIATE_APC_OPERATION,
&operation,
sizeof(APC_OPERATION_INFORMATION),
NULL,
NULL,
NULL,
NULL);
if (status == NULL)
{
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
return status;
}
}
VOID
kernelmode::Driver::SendIrpForDriverToStore()
{
BOOLEAN status = FALSE;
status = DeviceIoControl(
this->driver_handle, IOCTL_INSERT_IRP_INTO_QUEUE, NULL, NULL, NULL, NULL, NULL, NULL);
if (status == NULL)
LOG_ERROR("failed to insert irp into irp queue %x", GetLastError());
}
VOID
GetKernelStructureOffsets()
{
}

View file

@ -1,133 +0,0 @@
#ifndef DRIVER_H
#define DRIVER_H
#include <Windows.h>
#include "../threadpool.h"
#include "../client.h"
#define IOCTL_RUN_NMI_CALLBACKS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_DRIVER_OBJECTS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ENUMERATE_HANDLE_TABLES \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_INTEGRITY_CHECK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DETECT_ATTACHED_THREADS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_HARDWARE_INFORMATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_INITIATE_APC_OPERATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_CHECK_FOR_EPT_HOOK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_LAUNCH_DPC_STACKWALK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_SYSTEM_MODULES \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_INSERT_IRP_INTO_QUEUE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20021, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define MAX_REPORTS_PER_IRP 20
#define MAX_MODULE_PATH 256
namespace kernelmode {
enum APC_OPERATION_IDS
{
operation_stackwalk = 0x1
};
class Driver
{
HANDLE driver_handle;
LPCWSTR driver_name;
std::shared_ptr<global::Client> report_interface;
ULONG RequestTotalModuleSize();
VOID NotifyDriverOnProcessLaunch();
VOID CheckDriverHeartbeat();
VOID NotifyDriverOnProcessTermination();
// VOID GetKernelStructureOffsets();
template <typename T>
VOID ReportTypeFromReportQueue(CONST PVOID Buffer, PSIZE_T Offset, PVOID Report)
{
Report = (T*)((UINT64)Buffer +
sizeof(global::report_structures::REPORT_QUEUE_HEADER) + *Offset);
this->report_interface->ReportViolation((T*)Report);
*Offset += sizeof(T);
}
public:
Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface);
~Driver();
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID RunCallbackReportQueue();
VOID DetectSystemVirtualization();
VOID QueryReportQueue();
VOID CheckHandleTableEntries();
VOID RequestModuleExecutableRegions();
VOID ScanForUnlinkedProcess();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID VerifyProcessLoadedModuleExecutableRegions();
VOID SendClientHardwareInformation();
VOID CheckForEptHooks();
VOID StackwalkThreadsViaDpc();
VOID ValidateSystemModules();
BOOLEAN InitiateApcOperation(INT OperationId);
VOID SendIrpForDriverToStore();
};
struct DRIVER_INITIATION_INFORMATION
{
ULONG protected_process_id;
};
struct HYPERVISOR_DETECTION_REPORT
{
INT aperf_msr_timing_check;
INT invd_emulation_check;
};
struct PROCESS_MODULE_INFORMATION
{
PVOID module_base;
SIZE_T module_size;
WCHAR module_path[MAX_MODULE_PATH];
};
struct PROCESS_MODULE_VALIDATION_RESULT
{
INT is_module_valid;
};
struct APC_OPERATION_INFORMATION
{
int operation_id;
};
}
#endif

View file

@ -1,118 +0,0 @@
#include "kmanager.h"
kernelmode::KManager::KManager(LPCWSTR DriverName,
std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface)
{
this->driver_interface = std::make_unique<Driver>(DriverName, ReportInterface);
this->thread_pool = ThreadPool;
}
void
kernelmode::KManager::RunNmiCallbacks()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->RunNmiCallbacks(); });
}
void
kernelmode::KManager::VerifySystemModuleDriverObjects()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->VerifySystemModuleDriverObjects(); });
}
void
kernelmode::KManager::MonitorCallbackReports()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->QueryReportQueue(); });
}
void
kernelmode::KManager::DetectSystemVirtualization()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->DetectSystemVirtualization(); });
}
void
kernelmode::KManager::EnumerateHandleTables()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->CheckHandleTableEntries(); });
}
void
kernelmode::KManager::RequestModuleExecutableRegionsForIntegrityCheck()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->RequestModuleExecutableRegions(); });
}
VOID
kernelmode::KManager::ScanPoolsForUnlinkedProcesses()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->ScanForUnlinkedProcess(); });
}
VOID
kernelmode::KManager::PerformIntegrityCheck()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->PerformIntegrityCheck(); });
}
VOID
kernelmode::KManager::CheckForAttachedThreads()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->CheckForAttachedThreads(); });
}
VOID
kernelmode::KManager::ValidateProcessModules()
{
this->thread_pool->QueueJob(
[this]() { this->driver_interface->VerifyProcessLoadedModuleExecutableRegions(); });
}
VOID
kernelmode::KManager::SendClientHardwareInformation()
{
this->driver_interface->SendClientHardwareInformation();
}
VOID
kernelmode::KManager::InitiateApcStackwalkOperation()
{
this->driver_interface->InitiateApcOperation(
kernelmode::APC_OPERATION_IDS::operation_stackwalk);
}
VOID
kernelmode::KManager::CheckForEptHooks()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForEptHooks(); });
}
VOID
kernelmode::KManager::StackwalkThreadsViaDpc()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->StackwalkThreadsViaDpc(); });
}
VOID
kernelmode::KManager::ValidateSystemModules()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->ValidateSystemModules(); });
}
VOID
kernelmode::KManager::InsertIrpIntoIrpQueue()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->SendIrpForDriverToStore(); });
}
VOID
kernelmode::KManager::StartIoCompletionPortThread()
{
}

View file

@ -1,43 +0,0 @@
#ifndef KMANAGER_H
#define KMANAGER_H
#include <windows.h>
#include "..\client.h"
#include "..\threadpool.h"
#include "driver.h"
namespace kernelmode {
class KManager
{
std::unique_ptr<Driver> driver_interface;
std::shared_ptr<global::ThreadPool> thread_pool;
VOID StartIoCompletionPortThread();
public:
KManager(LPCWSTR DriverName,
std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface);
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID MonitorCallbackReports();
VOID DetectSystemVirtualization();
VOID EnumerateHandleTables();
VOID RequestModuleExecutableRegionsForIntegrityCheck();
VOID ScanPoolsForUnlinkedProcesses();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID ValidateProcessModules();
VOID SendClientHardwareInformation();
VOID InitiateApcStackwalkOperation();
VOID CheckForEptHooks();
VOID StackwalkThreadsViaDpc();
VOID ValidateSystemModules();
VOID InsertIrpIntoIrpQueue();
};
}
#endif

View file

@ -1,137 +0,0 @@
#include <iostream>
#include <Windows.h>
#include <string>
#include <WDBGEXTS.H>
#include "common.h"
#include "threadpool.h"
#include "client.h"
#include "../user/um/umanager.h"
#include "../user/km/kmanager.h"
// BOOLEAN IsTestSigningModeEnabled()
//{
// ULONG return_length = 0;
//
// SYSTEM_CODEINTEGRITY_INFORMATION info = { 0 };
// info.Length = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
// info.CodeIntegrityOptions = 0;
//
// NTSTATUS status = NtQuerySystemInformation(
// SystemCodeIntegrityInformation,
// &info,
// sizeof(info),
// &return_length
// );
//
// if (!NT_SUCCESS(status))
// {
// LOG_ERROR("NtQuerySystemInformation failed with status: %lx", status);
// return FALSE;
// }
//
// return info.CodeIntegrityOptions & CODEINTEGRITY_OPTION_TESTSIGN;
// }
DWORD WINAPI
Init(HINSTANCE hinstDLL)
{
AllocConsole();
FILE* file;
freopen_s(&file, "CONOUT$", "w", stdout);
freopen_s(&file, "CONIN$", "r", stdin);
std::this_thread::sleep_for(std::chrono::seconds(1));
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
LPCWSTR driver_name = L"\\\\.\\DonnaAC";
std::shared_ptr<global::ThreadPool> thread_pool = std::make_shared<global::ThreadPool>(4);
std::shared_ptr<global::Client> client_interface =
std::make_shared<global::Client>(thread_pool, pipe_name);
usermode::UManager umanager(thread_pool, client_interface);
kernelmode::KManager kmanager(driver_name, thread_pool, client_interface);
global::headers::SYSTEM_INFORMATION system_information = {0};
kmanager.SendClientHardwareInformation();
global::report_structures::SYSTEM_INFORMATION_REQUEST_RESPONSE response = {0};
// client_interface->ServerReceive( &response, sizeof( response ) );
// std::cout << "RequestID: " << response.RequestId << " CanUserProceed: " <<
// response.CanUserProceed << " Reason: " << response.reason << std::endl;
/*
* Note that this is really just for testing the methods for extended periods of time.
* The "real business logic" would execute the methods with varying degrees of uncertaintity
* but still allow for bias, i.e we don't want NMI callbacks to be running every 10 seconds.
* We also need to take into account the performance penalty that some of these routines
* have, such as the process module validation. At the end of the day an anti cheat that
* imposes a significant performance pentalty on the game its protecting is useless.
*/
srand(time(NULL));
while (!GetAsyncKeyState(VK_DELETE))
{
int seed = (rand() % 11);
std::cout << "Seed: " << seed << std::endl;
switch (seed)
{
case 0: kmanager.EnumerateHandleTables(); break;
case 1: kmanager.PerformIntegrityCheck(); break;
case 2: kmanager.ScanPoolsForUnlinkedProcesses(); break;
case 3: kmanager.VerifySystemModuleDriverObjects(); break;
case 4: kmanager.ValidateProcessModules(); break;
case 5: kmanager.RunNmiCallbacks(); break;
case 6: kmanager.CheckForAttachedThreads(); break;
case 7: kmanager.InitiateApcStackwalkOperation(); break;
case 8: kmanager.CheckForEptHooks(); break;
case 9: kmanager.StackwalkThreadsViaDpc(); break;
case 10: kmanager.ValidateSystemModules(); break;
}
kmanager.MonitorCallbackReports();
std::this_thread::sleep_for(std::chrono::seconds(10));
}
fclose(stdout);
fclose(stdin);
FreeConsole();
FreeLibraryAndExitThread(hinstDLL, 0);
return 0;
}
BOOL WINAPI
DllMain(HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved) // reserved
{
// Perform actions based on the reason for calling.
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
const auto thread = CreateThread(nullptr,
0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
hinstDLL,
0,
nullptr);
if (thread)
CloseHandle(thread);
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}

View file

@ -1,51 +0,0 @@
#include "pipe.h"
#include "common.h"
#include <intrin.h>
global::Pipe::Pipe(LPTSTR PipeName)
{
this->pipe_name = PipeName;
this->pipe_handle = CreateFile(this->pipe_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (this->pipe_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateFile failed with status 0x%x", GetLastError());
return;
}
}
void
global::Pipe::WriteToPipe(PVOID Buffer, SIZE_T Size)
{
DWORD bytes_written = 0;
WriteFile(this->pipe_handle, Buffer, Size, &bytes_written, NULL);
if (bytes_written == 0)
{
LOG_ERROR("WriteFile failed with status code 0x%x", GetLastError());
return;
}
}
void
global::Pipe::ReadPipe(PVOID Buffer, SIZE_T Size)
{
BOOL status = FALSE;
DWORD bytes_read = 0;
status = ReadFile(this->pipe_handle, Buffer, Size, &bytes_read, NULL);
if (status == NULL)
{
LOG_ERROR("ReadFile failed with status code 0x%x", GetLastError());
return;
}
}

View file

@ -1,75 +0,0 @@
#ifndef PIPE_H
#define PIPE_H
#include <Windows.h>
#define MESSAGE_TYPE_CLIENT_REPORT 1
#define MESSAGE_TYPE_CLIENT_SEND 2
#define MESSAGE_TYPE_CLIENT_REQUEST 3
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
namespace global {
class Pipe
{
HANDLE pipe_handle;
LPTSTR pipe_name;
public:
Pipe(LPTSTR PipeName);
void WriteToPipe(PVOID Buffer, SIZE_T Size);
void ReadPipe(PVOID Buffer, SIZE_T Size);
};
namespace headers {
typedef enum _ENVIRONMENT_TYPE
{
NativeWindows = 0,
Vmware,
VirtualBox
} ENVIRONMENT_TYPE;
typedef enum _PROCESSOR_TYPE
{
Unknown = 0,
GenuineIntel,
AuthenticAmd
} PROCESSOR_TYPE;
#define VENDOR_STRING_MAX_LENGTH 256
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];
BOOLEAN virtualised_environment;
ENVIRONMENT_TYPE environment;
PROCESSOR_TYPE processor;
RTL_OSVERSIONINFOW os_information;
};
struct PIPE_PACKET_HEADER
{
INT message_type;
UINT64 steam64_id;
};
struct PIPE_PACKET_REQUEST_EXTENSION_HEADER
{
INT request_id;
};
struct CLIENT_SEND_PACKET_HEADER
{
INT request_id;
LONG packet_size;
};
}
}
#endif

View file

@ -1,103 +0,0 @@
#include "threadpool.h"
/*
* This is the idle loop each thread will be running until a job is ready
* for execution
*/
void
global::ThreadPool::ThreadLoop()
{
while (true)
{
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
/*
* This is equivalent to :
*
* while (!this->jobs.empty() || should_terminate)
* mutex_condition.wait(lock);
*
* we are essentially waiting for a job to be queued up or the terminate
*flag to be set. Another piece of useful information is that the predicate
*is checked under the lock as the precondition for .wait() is that the
*calling thread owns the lock.
*
* Now, when .wait() is run, the lock is unlocked the the executing thread
*is blocked and is added to a list of threads current waiting on the
*predicate. In our case whether there are new jobs available for the
*terminate flag is set. Once the condition variables are true i.e there are
*new jobs or we are terminating, the lock is reacquired by the thread and
*the thread is unblocked.
*/
mutex_condition.wait(
lock, [this] { return !this->jobs.empty() || this->should_terminate; });
if (this->should_terminate)
return;
/* get the first job in the queue*/
job = jobs.front();
jobs.pop();
}
/* run the job */
job();
}
}
global::ThreadPool::ThreadPool(int ThreadCount)
{
this->thread_count = ThreadCount;
this->should_terminate = false;
/* Initiate our threads and store them in our threads vector */
for (int i = 0; i < this->thread_count; i++)
{
this->threads.emplace_back(std::thread(&ThreadPool::ThreadLoop, this));
}
}
void
global::ThreadPool::QueueJob(const std::function<void()>& job)
{
/* push a job into our job queue safely by holding our queue lock */
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->jobs.push(job);
lock.unlock();
mutex_condition.notify_one();
}
void
global::ThreadPool::Stop()
{
/* safely set our termination flag to true */
std::unique_lock<std::mutex> lock(this->queue_mutex);
should_terminate = true;
lock.unlock();
/* unlock all threads waiting on our condition */
mutex_condition.notify_all();
/* join the threads and clear our threads vector */
for (std::thread& thread : threads)
{
thread.join();
}
threads.clear();
}
bool
global::ThreadPool::Busy()
{
/* allows us to wait for when the job queue is empty allowing us to safely call the
* destructor */
std::unique_lock<std::mutex> lock(this->queue_mutex);
bool pool_busy = !jobs.empty();
this->queue_mutex.unlock();
return pool_busy;
}

View file

@ -1,34 +0,0 @@
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <mutex>
#include <vector>
#include <queue>
#include <functional>
namespace global {
/*
* This ThreadPool class is a simple threadpool implementation that will allow us
* to delegate jobs to a set number of threads without the constant need to close
* and open new threads.
*/
class ThreadPool
{
int thread_count;
bool should_terminate;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
void ThreadLoop();
public:
ThreadPool(int ThreadCount);
void QueueJob(const std::function<void()>& job);
void Stop();
bool Busy();
};
}
#endif

View file

@ -1,32 +0,0 @@
#include "imports.h"
#include "../common.h"
usermode::Imports::Imports()
{
NtQueryInformationThread = nullptr;
RtlDosPathNameToNtPathName_U = nullptr;
this->ImportMap["NtQueryInformationThread"] = NtQueryInformationThread;
this->ImportMap["RtlDosPathNameToNtPathName_U"] = RtlDosPathNameToNtPathName_U;
std::map<std::string, void*>::iterator it;
for (it = this->ImportMap.begin(); it != this->ImportMap.end(); it++)
{
HMODULE module_handle = GetModuleHandle(L"ntdll.dll");
if (!module_handle)
{
LOG_ERROR("GetModuleHandle failed with status code 0x%x", GetLastError());
return;
}
it->second = GetProcAddress(module_handle, it->first.c_str());
if (!it->second)
{
LOG_ERROR("GetProcAddress failed with status code 0x%x", GetLastError());
}
}
}

View file

@ -1,26 +0,0 @@
#ifndef IMPORTS_H
#define IMPORTS_H
#include <winternl.h>
#include <Windows.h>
#include <map>
#include <string>
typedef NTSTATUS(WINAPI* pNtQueryInformationThread)(HANDLE, LONG, PVOID, ULONG, PULONG);
typedef BOOLEAN(NTAPI pRtlDosPathNameToNtPathName_U(PCWSTR, PVOID, PCWSTR*, PVOID));
namespace usermode {
class Imports
{
public:
std::map<std::string, void*> ImportMap;
void* NtQueryInformationThread;
void* NtQueryVirtualMemory;
void* RtlDosPathNameToNtPathName_U;
Imports();
};
}
#endif

View file

@ -1,321 +0,0 @@
#include "process.h"
#include "../common.h"
#include "../um/imports.h"
#include "memory.h"
#include "../client.h"
#include <ImageHlp.h>
#include <iostream>
const static char MASK_BYTE = '\x00';
usermode::Process::Process(std::shared_ptr<global::Client> ClientInterface)
{
this->process_handle = GetCurrentProcess();
this->process_id = GetCurrentProcessId();
this->function_imports = std::make_unique<Imports>();
this->client_interface = ClientInterface;
}
void
usermode::Process::ValidateProcessThreads()
{
HANDLE thread_snapshot_handle = INVALID_HANDLE_VALUE;
THREADENTRY32 thread_entry = {0};
NTSTATUS status = 0;
HANDLE thread_handle = INVALID_HANDLE_VALUE;
UINT64 start_address = 0;
bool result = false;
pNtQueryInformationThread NtQueryInfo = (pNtQueryInformationThread)this->function_imports
->ImportMap["NtQueryInformationThread"];
/* th32ProcessId ignored for TH32CS_SNAPTHREAD value */
thread_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (thread_snapshot_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("thread snapshot handle invalid with error 0x%x", GetLastError());
return;
}
thread_entry.dwSize = sizeof(THREADENTRY32);
if (!Thread32First(thread_snapshot_handle, &thread_entry))
{
LOG_ERROR("Thread32First failed with status 0x%x", GetLastError());
CloseHandle(thread_snapshot_handle);
return;
}
do
{
if (thread_entry.th32OwnerProcessID != process_id)
continue;
thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
if (thread_handle == INVALID_HANDLE_VALUE)
continue;
status = NtQueryInfo(thread_handle,
(THREADINFOCLASS)ThreadQuerySetWin32StartAddress,
&start_address,
sizeof(UINT64),
NULL);
if (!NT_SUCCESS(status))
{
LOG_ERROR("NtQueryInfo failed with status code 0x%lx", status);
continue;
}
if (CheckIfAddressLiesWithinValidProcessModule(start_address, &result))
{
if (result == false)
{
global::report_structures::PROCESS_THREAD_START_FAILURE report;
report.report_code = REPORT_CODE_START_ADDRESS_VERIFICATION;
report.start_address = start_address;
report.thread_id = thread_entry.th32ThreadID;
this->client_interface->ReportViolation(&report);
}
}
} while (Thread32Next(thread_snapshot_handle, &thread_entry));
}
/*
* Iterates through a processes modules and confirms whether the address lies within the memory
* region of the module. A simple way to check if a thread is a valid thread, however there are ways
* around this check so it is not a perfect solution.
*/
bool
usermode::Process::CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result)
{
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
process_modules_handle =
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
LOG_INFO("Address: %llx", Address);
if (process_modules_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
GetLastError());
return false;
}
module_entry.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(process_modules_handle, &module_entry))
{
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
CloseHandle(process_modules_handle);
return false;
}
do
{
UINT64 base = (UINT64)module_entry.modBaseAddr;
UINT64 end = base + module_entry.modBaseSize;
if (Address >= base && Address <= end)
{
LOG_INFO("found valid module LOL");
CloseHandle(process_modules_handle);
*Result = true;
return true;
}
} while (Module32Next(process_modules_handle, &module_entry));
CloseHandle(process_modules_handle);
*Result = false;
return true;
}
HANDLE
usermode::Process::GetHandleToProcessGivenName(std::string ProcessName)
{
std::wstring wide_process_name = {0};
std::wstring target_process_name = {0};
HANDLE process_snapshot_handle = INVALID_HANDLE_VALUE;
HANDLE process_handle = INVALID_HANDLE_VALUE;
PROCESSENTRY32 process_entry = {0};
wide_process_name = std::wstring(ProcessName.begin(), ProcessName.end());
process_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (process_snapshot_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("Failed to create snapshot of current running processes error: 0x%x",
GetLastError());
return INVALID_HANDLE_VALUE;
}
process_entry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(process_snapshot_handle, &process_entry))
{
LOG_ERROR("Failed to get the first process using Process32First error: 0x%x",
GetLastError());
CloseHandle(process_snapshot_handle);
return INVALID_HANDLE_VALUE;
}
do
{
process_handle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_entry.th32ProcessID);
/*
* this will generally fail due to a process being an elevated process and denying
* us access so we dont really care if OpenProcess fails in most cases
*/
if (process_handle == NULL)
continue;
target_process_name = std::wstring(process_entry.szExeFile);
if (wide_process_name == target_process_name)
{
LOG_INFO("Found target process");
CloseHandle(process_snapshot_handle);
return process_handle;
}
} while (Process32Next(process_snapshot_handle, &process_entry));
CloseHandle(process_snapshot_handle);
return INVALID_HANDLE_VALUE;
}
bool
usermode::Process::GetProcessBaseAddress(UINT64* Result)
{
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
process_modules_handle =
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
if (process_modules_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
GetLastError());
return false;
}
module_entry.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(process_modules_handle, &module_entry))
{
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
CloseHandle(process_modules_handle);
return false;
}
*Result = (UINT64)module_entry.modBaseAddr;
CloseHandle(process_modules_handle);
return true;
}
void
usermode::Process::ScanProcessMemory()
{
MEMORY_BASIC_INFORMATION memory_info = {0};
UINT64 address = 0;
if (!GetProcessBaseAddress(&address))
{
LOG_ERROR("Failed to get process base address with status 0x%x", GetLastError());
return;
}
while (VirtualQueryEx(
this->process_handle, (PVOID)address, &memory_info, sizeof(MEMORY_BASIC_INFORMATION)))
{
this->CheckPageProtection(&memory_info);
this->PatternScanRegion(address, &memory_info);
address += memory_info.RegionSize;
}
}
void
usermode::Process::PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page)
{
/* todo: stream signatures from server */
// char buf[] = "\x85\xc0\x74\x00\xb9\x00\x00\x00\x00\xcd";
char buf[] =
"\x55\x8B\xEC\xFF\x75\x00\xD9\x45\x00\x51\xD9\x1C\x00\xE8\x00\x00\x00\x00\x5D\xC2\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
std::vector<char> signature = {0};
for (int i = 0; i < 10; i++)
signature.push_back(buf[i]);
/* skip free or reserved pages */
if (Page->State == MEM_RESERVE || Page->State == MEM_FREE)
return;
char* base = (char*)Address;
for (unsigned int i = 0; i < Page->RegionSize; i++)
{
for (unsigned j = 0; j < signature.size(); j++)
{
char current_byte = *(base + i);
char current_sig_byte = signature[j];
/* if we've found the signature, report */
if (j + 1 == signature.size())
{
global::report_structures::PATTERN_SCAN_FAILURE report;
report.report_code = REPORT_PATTERN_SCAN_FAILURE;
report.address = (UINT64)base + i;
report.signature_id =
1; /* this will be taken from the vector in future */
this->client_interface->ReportViolation(&report);
/*
* for now return, however when we stream the signatures we iterate
* over each signature for every page
*/
return;
}
/* else, continue searching */
if (current_byte != current_sig_byte && current_sig_byte != MASK_BYTE)
break;
i++;
}
}
}
void
usermode::Process::CheckPageProtection(MEMORY_BASIC_INFORMATION* Page)
{
/* MEM_IMAGE indicates the pages are mapped into view of an image section */
if (Page->Type == MEM_IMAGE)
return;
if (Page->AllocationProtect & PAGE_EXECUTE || Page->AllocationProtect & PAGE_EXECUTE_READ ||
Page->AllocationProtect & PAGE_EXECUTE_READWRITE ||
Page->AllocationProtect & PAGE_EXECUTE_WRITECOPY)
{
// Not etirely sure about this check, needs to be looked into further.
global::report_structures::PAGE_PROTECTION_FAILURE report;
report.report_code = REPORT_PAGE_PROTECTION_VERIFICATION;
report.page_base_address = (UINT64)Page->AllocationBase;
report.allocation_protection = Page->AllocationProtect;
report.allocation_state = Page->State;
report.allocation_type = Page->Type;
this->client_interface->ReportViolation(&report);
}
}

View file

@ -1,46 +0,0 @@
#ifndef PROCESS_H
#define PROCESS_H
#include <windows.h>
#include <winternl.h>
#include <TlHelp32.h>
#include <string>
#include "../client.h"
#include "../threadpool.h"
#include "../um/imports.h"
#include "../km/kmanager.h"
#define ThreadQuerySetWin32StartAddress 9
namespace usermode {
/*
* This class represents a process and the usermode functions responsible for
* the protection of it. This class represents the protected process and allows
* us to split protection class into methods which can then be easily managed
* by the usermode manager class.
*/
class Process
{
HANDLE process_handle;
DWORD process_id;
std::mutex mutex;
std::unique_ptr<Imports> function_imports;
std::vector<DWORD> in_memory_module_checksums;
std::shared_ptr<global::Client> client_interface;
HANDLE GetHandleToProcessGivenName(std::string ProcessName);
bool CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result);
bool GetProcessBaseAddress(UINT64* Result);
void CheckPageProtection(MEMORY_BASIC_INFORMATION* Page);
void PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page);
public:
Process(std::shared_ptr<global::Client> ClientInterface);
void ValidateProcessThreads();
void ScanProcessMemory();
};
}
#endif

View file

@ -1,39 +0,0 @@
#include "umanager.h"
#include "../common.h"
#include "process.h"
#include "../um/imports.h"
#include <TlHelp32.h>
usermode::UManager::UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface)
{
this->thread_pool = ThreadPool;
this->process = std::make_unique<Process>(ReportInterface);
}
usermode::UManager::~UManager()
{
/* Wait for our jobs to be finished, then safely stop our pool */
// while ( true )
//{
// if ( this->thread_pool->Busy() == FALSE )
// {
// this->thread_pool->Stop();
// break;
// }
// }
}
void
usermode::UManager::ValidateProcessThreads()
{
this->thread_pool->QueueJob([this]() { this->process->ValidateProcessThreads(); });
}
void
usermode::UManager::ValidateProcessMemory()
{
this->thread_pool->QueueJob([this]() { this->process->ScanProcessMemory(); });
}

View file

@ -1,37 +0,0 @@
#ifndef UMANAGER_H
#define UMANAGER_H
#include <string>
#include <winternl.h>
#include <Windows.h>
#include <mutex>
#include <thread>
#include <vector>
#include "..\client.h"
#include "process.h"
namespace usermode {
/*
* The manager class is meant to abstract away the interaction between the Process
* class and the threadpool class to allow a single thread (or multiple) to easily run
* the core business logic of running tasks in a certain order.
*/
class UManager
{
std::unique_ptr<Process> process;
std::shared_ptr<global::ThreadPool> thread_pool;
public:
UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface);
~UManager();
void ValidateProcessThreads();
void ValidateProcessMemory();
void ValidateProcessModules();
};
}
#endif

View file

@ -1,283 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - No Server - Win11|Win32">
<Configuration>Release - No Server - Win11</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - No Server - Win11|x64">
<Configuration>Release - No Server - Win11</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - No Server|Win32">
<Configuration>Release - No Server</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - No Server|x64">
<Configuration>Release - No Server</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{3c8194c7-9f20-4ff8-8c4c-b26c3d053611}</ProjectGuid>
<RootNamespace>user</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="pipe.cpp" />
<ClCompile Include="km\driver.cpp" />
<ClCompile Include="km\kmanager.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="um\imports.cpp" />
<ClCompile Include="um\process.cpp" />
<ClCompile Include="threadpool.cpp" />
<ClCompile Include="um\umanager.cpp" />
<ClCompile Include="client.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pipe.h" />
<ClInclude Include="common.h" />
<ClInclude Include="km\driver.h" />
<ClInclude Include="km\kmanager.h" />
<ClInclude Include="client.h" />
<ClInclude Include="um\imports.h" />
<ClInclude Include="um\process.h" />
<ClInclude Include="threadpool.h" />
<ClInclude Include="um\umanager.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>