diff --git a/.clang-format b/.clang-format index 5ff9eec..55f2377 100644 --- a/.clang-format +++ b/.clang-format @@ -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 \ No newline at end of file +... diff --git a/.clang-format-c b/.clang-format-c new file mode 100644 index 0000000..5ff9eec --- /dev/null +++ b/.clang-format-c @@ -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 \ No newline at end of file diff --git a/ac.sln b/ac.sln index 712eb97..0dc9d84 100644 --- a/ac.sln +++ b/ac.sln @@ -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 diff --git a/driver/callbacks.c b/driver/callbacks.c index 520e385..88145ce 100644 --- a/driver/callbacks.c +++ b/driver/callbacks.c @@ -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) { diff --git a/driver/callbacks.h b/driver/callbacks.h index 09e4285..7697270 100644 --- a/driver/callbacks.h +++ b/driver/callbacks.h @@ -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 diff --git a/driver/common.h b/driver/common.h index 1897056..8487807 100644 --- a/driver/common.h +++ b/driver/common.h @@ -3,6 +3,9 @@ #include #include +#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 diff --git a/driver/driver.c b/driver/driver.c index ca6d64d..949eeb0 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -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; } diff --git a/driver/driver.h b/driver/driver.h index ebc32de..bb437d5 100644 --- a/driver/driver.h +++ b/driver/driver.h @@ -64,9 +64,6 @@ GetDriverSymbolicLink(); PSYSTEM_INFORMATION GetDriverConfigSystemInformation(); -PREPORT_QUEUE_HEAD -GetDriverReportQueue(); - PTHREAD_LIST_HEAD GetThreadList(); diff --git a/driver/driver.vcxproj b/driver/driver.vcxproj index c5424be..949328c 100644 --- a/driver/driver.vcxproj +++ b/driver/driver.vcxproj @@ -250,7 +250,7 @@ - + @@ -266,12 +266,13 @@ - + + diff --git a/driver/driver.vcxproj.filters b/driver/driver.vcxproj.filters index 254e5e4..9535707 100644 --- a/driver/driver.vcxproj.filters +++ b/driver/driver.vcxproj.filters @@ -27,9 +27,6 @@ Source Files - - Source Files - Source Files @@ -60,6 +57,9 @@ Source Files + + Source Files + @@ -68,9 +68,6 @@ Header Files - - Header Files - Header Files @@ -104,6 +101,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/driver/hv.c b/driver/hv.c index da9fec8..4100ab8 100644 --- a/driver/hv.c +++ b/driver/hv.c @@ -3,7 +3,7 @@ #include #include "imports.h" #include "common.h" -#include "ioctl.h" +#include "io.h" #ifdef ALLOC_PRAGMA # pragma alloc_text(PAGE, PerformVirtualizationDetection) diff --git a/driver/hv.h b/driver/hv.h index 0c9879b..7b04b7c 100644 --- a/driver/hv.h +++ b/driver/hv.h @@ -4,13 +4,6 @@ #include #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); diff --git a/driver/integrity.c b/driver/integrity.c index fc89d78..62a6b3a 100644 --- a/driver/integrity.c +++ b/driver/integrity.c @@ -4,7 +4,7 @@ #include "driver.h" #include "modules.h" #include "callbacks.h" -#include "ioctl.h" +#include "io.h" #include "imports.h" #include @@ -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) diff --git a/driver/ioctl.c b/driver/io.c similarity index 66% rename from driver/ioctl.c rename to driver/io.c index 2ac618a..34dea71 100644 --- a/driver/ioctl.c +++ b/driver/io.c @@ -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(); diff --git a/driver/ioctl.h b/driver/io.h similarity index 85% rename from driver/ioctl.h rename to driver/io.h index 6073a73..0d31a4d 100644 --- a/driver/ioctl.h +++ b/driver/io.h @@ -1,5 +1,5 @@ -#ifndef IOCTL_H -#define IOCTL_H +#ifndef IO_H +#define IO_H #include #include @@ -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 \ No newline at end of file diff --git a/driver/modules.c b/driver/modules.c index 47f4698..c8ee739 100644 --- a/driver/modules.c +++ b/driver/modules.c @@ -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 diff --git a/driver/modules.h b/driver/modules.h index da70492..e284111 100644 --- a/driver/modules.h +++ b/driver/modules.h @@ -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); diff --git a/driver/pool.c b/driver/pool.c index 2f2cc0e..d2e5cf0 100644 --- a/driver/pool.c +++ b/driver/pool.c @@ -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: diff --git a/driver/pool.h b/driver/pool.h index 8ff152f..f439976 100644 --- a/driver/pool.h +++ b/driver/pool.h @@ -4,15 +4,6 @@ #include #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(); diff --git a/driver/queue.c b/driver/queue.c index 2a394b6..7057923 100644 --- a/driver/queue.c +++ b/driver/queue.c @@ -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; } \ No newline at end of file diff --git a/driver/queue.h b/driver/queue.h index 01290f4..4c42dcb 100644 --- a/driver/queue.h +++ b/driver/queue.h @@ -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 \ No newline at end of file diff --git a/driver/thread.c b/driver/thread.c index 54001af..b79a279 100644 --- a/driver/thread.c +++ b/driver/thread.c @@ -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."); } } diff --git a/driver/thread.h b/driver/thread.h index 85bac00..09237f5 100644 --- a/driver/thread.h +++ b/driver/thread.h @@ -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); diff --git a/driver/types/types.h b/driver/types/types.h new file mode 100644 index 0000000..70ad4e5 --- /dev/null +++ b/driver/types/types.h @@ -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 \ No newline at end of file diff --git a/module/client/message_queue.cpp b/module/client/message_queue.cpp new file mode 100644 index 0000000..da236de --- /dev/null +++ b/module/client/message_queue.cpp @@ -0,0 +1,29 @@ +#include "message_queue.h" + +#include + +#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(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 +} diff --git a/module/client/message_queue.h b/module/client/message_queue.h new file mode 100644 index 0000000..31686b1 --- /dev/null +++ b/module/client/message_queue.h @@ -0,0 +1,43 @@ +#ifndef REPORT_H +#define REPORT_H + +#include + +#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 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 diff --git a/module/client/pipe.cpp b/module/client/pipe.cpp new file mode 100644 index 0000000..0958b8e --- /dev/null +++ b/module/client/pipe.cpp @@ -0,0 +1,40 @@ +#include "pipe.h" + +#include "../common.h" + +#include + +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; + } +} diff --git a/module/client/pipe.h b/module/client/pipe.h new file mode 100644 index 0000000..f9f5949 --- /dev/null +++ b/module/client/pipe.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#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 \ No newline at end of file diff --git a/user/common.h b/module/common.h similarity index 63% rename from user/common.h rename to module/common.h index a7ea334..411a2a9 100644 --- a/user/common.h +++ b/module/common.h @@ -1,11 +1,11 @@ -#ifndef COMMON_H -#define COMMON_H +#pragma once #include +#include +#include +#include +#include + #define LOG_INFO(fmt, ...) printf("[+] " fmt "\n", ##__VA_ARGS__) -#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__) - - - -#endif \ No newline at end of file +#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__) \ No newline at end of file diff --git a/module/dispatcher/dispatcher.cpp b/module/dispatcher/dispatcher.cpp new file mode 100644 index 0000000..d81fe63 --- /dev/null +++ b/module/dispatcher/dispatcher.cpp @@ -0,0 +1,62 @@ +#include "dispatcher.h" + +#include "../client/message_queue.h" +#include "../helper.h" + +#include + +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; + } +} \ No newline at end of file diff --git a/module/dispatcher/dispatcher.h b/module/dispatcher/dispatcher.h new file mode 100644 index 0000000..053cbed --- /dev/null +++ b/module/dispatcher/dispatcher.h @@ -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 \ No newline at end of file diff --git a/module/dispatcher/threadpool.cpp b/module/dispatcher/threadpool.cpp new file mode 100644 index 0000000..2b36acd --- /dev/null +++ b/module/dispatcher/threadpool.cpp @@ -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 job; + { + std::unique_lock 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 &job) { + /* push a job into our job queue safely by holding our queue lock */ + std::unique_lock 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 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 lock(this->queue_mutex); + + bool pool_busy = !jobs.empty(); + this->queue_mutex.unlock(); + + return pool_busy; +} diff --git a/module/dispatcher/threadpool.h b/module/dispatcher/threadpool.h new file mode 100644 index 0000000..bb99ac5 --- /dev/null +++ b/module/dispatcher/threadpool.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include + +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 threads; + std::queue> jobs; + + void wait_for_task(); + +public: + thread_pool(int thread_count); + void queue_job(const std::function &job); + void terminate(); + bool busy_wait(); +}; +} // namespace dispatcher \ No newline at end of file diff --git a/module/helper.cpp b/module/helper.cpp new file mode 100644 index 0000000..520eb0b --- /dev/null +++ b/module/helper.cpp @@ -0,0 +1,169 @@ +#include "helper.h" + +#include +#include + +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(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(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( + 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( + 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(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( + 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( + 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(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(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(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(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; + } +} \ No newline at end of file diff --git a/module/helper.h b/module/helper.h new file mode 100644 index 0000000..cf46b82 --- /dev/null +++ b/module/helper.h @@ -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 \ No newline at end of file diff --git a/module/imports.cpp b/module/imports.cpp new file mode 100644 index 0000000..636dfa5 --- /dev/null +++ b/module/imports.cpp @@ -0,0 +1,3 @@ +#include "imports.h" + +bool imports::initialise_imports() { return false; } \ No newline at end of file diff --git a/module/imports.h b/module/imports.h new file mode 100644 index 0000000..03fc9bd --- /dev/null +++ b/module/imports.h @@ -0,0 +1,8 @@ +#pragma once + +namespace imports +{ +bool initialise_imports(); + + +} \ No newline at end of file diff --git a/module/kernel_interface/kernel_interface.cpp b/module/kernel_interface/kernel_interface.cpp new file mode 100644 index 0000000..4249250 --- /dev/null +++ b/module/kernel_interface/kernel_interface.cpp @@ -0,0 +1,290 @@ +#include "kernel_interface.h" + +#include + +#include "../common.h" +#include "../helper.h" + +#include +#include + +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 lock(this->lock); + for (std::vector::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 lock(this->lock); + for (std::vector::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 lock(this->lock); + for (std::vector::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 lock(this->lock); + for (std::vector::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); +//} diff --git a/module/kernel_interface/kernel_interface.h b/module/kernel_interface/kernel_interface.h new file mode 100644 index 0000000..3708b2a --- /dev/null +++ b/module/kernel_interface/kernel_interface.h @@ -0,0 +1,221 @@ +#pragma once + +#include + +#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 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 \ No newline at end of file diff --git a/module/main.cpp b/module/main.cpp new file mode 100644 index 0000000..f6b53e5 --- /dev/null +++ b/module/main.cpp @@ -0,0 +1,33 @@ +#include + +#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(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; +} diff --git a/module/module.cpp b/module/module.cpp new file mode 100644 index 0000000..6cf73a3 --- /dev/null +++ b/module/module.cpp @@ -0,0 +1,31 @@ +#include "module.h" + +#include + +#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() +{ + +} \ No newline at end of file diff --git a/module/module.h b/module/module.h new file mode 100644 index 0000000..1c2419a --- /dev/null +++ b/module/module.h @@ -0,0 +1,10 @@ +#pragma once + +#include "common.h" + +#include + +namespace module { +void run(HINSTANCE hinstDLL); +void terminate(); +} // namespace module \ No newline at end of file diff --git a/module/module.vcxproj b/module/module.vcxproj new file mode 100644 index 0000000..d0d4f39 --- /dev/null +++ b/module/module.vcxproj @@ -0,0 +1,167 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {3b18467a-4358-45ef-81b1-5c6f9b0b6728} + module + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + stdcpp20 + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/user/user.vcxproj.filters b/module/module.vcxproj.filters similarity index 72% rename from user/user.vcxproj.filters rename to module/module.vcxproj.filters index e9a5415..e29fad4 100644 --- a/user/user.vcxproj.filters +++ b/module/module.vcxproj.filters @@ -18,28 +18,28 @@ Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files @@ -47,28 +47,28 @@ Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files diff --git a/test/driver/main.cpp b/test/driver/main.cpp index a2558ee..c44af6e 100644 --- a/test/driver/main.cpp +++ b/test/driver/main.cpp @@ -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; } \ No newline at end of file diff --git a/test/driver/patch.cpp b/test/driver/patch.cpp index 1697021..3fd4134 100644 --- a/test/driver/patch.cpp +++ b/test/driver/patch.cpp @@ -1,11 +1,7 @@ #include "patch.hpp" namespace framework { -patch::patch(char* image_name) -{ -} +patch::patch(char *image_name) {} -patch::~patch() -{ -} -} \ No newline at end of file +patch::~patch() {} +} // namespace framework \ No newline at end of file diff --git a/user/client.cpp b/user/client.cpp deleted file mode 100644 index 47f1db1..0000000 --- a/user/client.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "client.h" - -#include "common.h" - -#include - -#define TEST_STEAM_64_ID 123456789; - -global::Client::Client(std::shared_ptr 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(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 - -} diff --git a/user/client.h b/user/client.h deleted file mode 100644 index 4bc9337..0000000 --- a/user/client.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef REPORT_H -#define REPORT_H - -#include - -#include "threadpool.h" -#include "pipe.h" -#include -#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 thread_pool; - std::shared_ptr pipe; - std::mutex mutex; - - byte report_buffer[REPORT_BUFFER_SIZE]; - - public: - Client(std::shared_ptr ThreadPool, LPTSTR PipeName); - - void UpdateSystemInformation(global::headers::SYSTEM_INFORMATION* SystemInformation); - - /* lock buffer, attach header, copy report, send to service then clear buffer */ - template - 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 diff --git a/user/km/driver.cpp b/user/km/driver.cpp deleted file mode 100644 index 7d38c10..0000000 --- a/user/km/driver.cpp +++ /dev/null @@ -1,671 +0,0 @@ -#include "driver.h" - -#include - -#include "../common.h" -#include - -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 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( - buffer, &total_size, &attach_report); - break; - case REPORT_ILLEGAL_HANDLE_OPERATION: - ReportTypeFromReportQueue( - buffer, &total_size, &handle_report); - break; - case REPORT_INVALID_PROCESS_ALLOCATION: - ReportTypeFromReportQueue( - buffer, &total_size, &allocation_report); - break; - case REPORT_APC_STACKWALK: - ReportTypeFromReportQueue( - buffer, &total_size, &apc_report); - break; - case REPORT_HIDDEN_SYSTEM_THREAD: - ReportTypeFromReportQueue( - buffer, &total_size, &hidden_report); - break; - case REPORT_DPC_STACKWALK: - ReportTypeFromReportQueue( - buffer, &total_size, &hidden_report); - break; - case REPORT_DATA_TABLE_ROUTINE: - ReportTypeFromReportQueue( - 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() -{ -} diff --git a/user/km/driver.h b/user/km/driver.h deleted file mode 100644 index 28b13b5..0000000 --- a/user/km/driver.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef DRIVER_H -#define DRIVER_H - -#include - -#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 report_interface; - - ULONG RequestTotalModuleSize(); - VOID NotifyDriverOnProcessLaunch(); - VOID CheckDriverHeartbeat(); - VOID NotifyDriverOnProcessTermination(); - // VOID GetKernelStructureOffsets(); - - template - 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 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 diff --git a/user/km/kmanager.cpp b/user/km/kmanager.cpp deleted file mode 100644 index d4365d5..0000000 --- a/user/km/kmanager.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "kmanager.h" - -kernelmode::KManager::KManager(LPCWSTR DriverName, - std::shared_ptr ThreadPool, - std::shared_ptr ReportInterface) -{ - this->driver_interface = std::make_unique(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() -{ - -} \ No newline at end of file diff --git a/user/km/kmanager.h b/user/km/kmanager.h deleted file mode 100644 index b8865c7..0000000 --- a/user/km/kmanager.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef KMANAGER_H -#define KMANAGER_H - -#include - -#include "..\client.h" -#include "..\threadpool.h" - -#include "driver.h" - -namespace kernelmode { -class KManager -{ - std::unique_ptr driver_interface; - std::shared_ptr thread_pool; - - VOID StartIoCompletionPortThread(); - - public: - KManager(LPCWSTR DriverName, - std::shared_ptr ThreadPool, - std::shared_ptr 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 \ No newline at end of file diff --git a/user/main.cpp b/user/main.cpp deleted file mode 100644 index b5bc245..0000000 --- a/user/main.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include -#include - -#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 thread_pool = std::make_shared(4); - std::shared_ptr client_interface = - std::make_shared(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(Init), - hinstDLL, - 0, - nullptr); - - if (thread) - CloseHandle(thread); - - break; - } - return TRUE; // Successful DLL_PROCESS_ATTACH. -} \ No newline at end of file diff --git a/user/pipe.cpp b/user/pipe.cpp deleted file mode 100644 index 6145444..0000000 --- a/user/pipe.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "pipe.h" - -#include "common.h" -#include - -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; - } -} diff --git a/user/pipe.h b/user/pipe.h deleted file mode 100644 index 3b47621..0000000 --- a/user/pipe.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef PIPE_H -#define PIPE_H - -#include - -#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 \ No newline at end of file diff --git a/user/threadpool.cpp b/user/threadpool.cpp deleted file mode 100644 index 6412d34..0000000 --- a/user/threadpool.cpp +++ /dev/null @@ -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 job; - { - std::unique_lock 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& job) -{ - /* push a job into our job queue safely by holding our queue lock */ - std::unique_lock 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 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 lock(this->queue_mutex); - - bool pool_busy = !jobs.empty(); - this->queue_mutex.unlock(); - - return pool_busy; -} diff --git a/user/threadpool.h b/user/threadpool.h deleted file mode 100644 index f88b256..0000000 --- a/user/threadpool.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef THREADPOOL_H -#define THREADPOOL_H - -#include -#include -#include -#include - -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 threads; - std::queue> jobs; - - void ThreadLoop(); - - public: - ThreadPool(int ThreadCount); - void QueueJob(const std::function& job); - void Stop(); - bool Busy(); -}; -} - -#endif \ No newline at end of file diff --git a/user/um/imports.cpp b/user/um/imports.cpp deleted file mode 100644 index c216b4b..0000000 --- a/user/um/imports.cpp +++ /dev/null @@ -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::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()); - } - } -} diff --git a/user/um/imports.h b/user/um/imports.h deleted file mode 100644 index 59322f3..0000000 --- a/user/um/imports.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef IMPORTS_H -#define IMPORTS_H - -#include -#include -#include -#include - -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 ImportMap; - - void* NtQueryInformationThread; - void* NtQueryVirtualMemory; - void* RtlDosPathNameToNtPathName_U; - - Imports(); -}; -} - -#endif \ No newline at end of file diff --git a/user/um/process.cpp b/user/um/process.cpp deleted file mode 100644 index e9d4f1c..0000000 --- a/user/um/process.cpp +++ /dev/null @@ -1,321 +0,0 @@ -#include "process.h" - -#include "../common.h" -#include "../um/imports.h" -#include "memory.h" - -#include "../client.h" - -#include -#include - -const static char MASK_BYTE = '\x00'; - -usermode::Process::Process(std::shared_ptr ClientInterface) -{ - this->process_handle = GetCurrentProcess(); - this->process_id = GetCurrentProcessId(); - this->function_imports = std::make_unique(); - 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 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); - } -} \ No newline at end of file diff --git a/user/um/process.h b/user/um/process.h deleted file mode 100644 index f13e794..0000000 --- a/user/um/process.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef PROCESS_H -#define PROCESS_H - -#include -#include -#include -#include - -#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 function_imports; - std::vector in_memory_module_checksums; - std::shared_ptr 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 ClientInterface); - - void ValidateProcessThreads(); - void ScanProcessMemory(); -}; -} - -#endif \ No newline at end of file diff --git a/user/um/umanager.cpp b/user/um/umanager.cpp deleted file mode 100644 index 5064dc5..0000000 --- a/user/um/umanager.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "umanager.h" - -#include "../common.h" -#include "process.h" -#include "../um/imports.h" - -#include - -usermode::UManager::UManager(std::shared_ptr ThreadPool, - std::shared_ptr ReportInterface) -{ - this->thread_pool = ThreadPool; - this->process = std::make_unique(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(); }); -} diff --git a/user/um/umanager.h b/user/um/umanager.h deleted file mode 100644 index 9f3bbe7..0000000 --- a/user/um/umanager.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef UMANAGER_H -#define UMANAGER_H - -#include -#include -#include -#include -#include -#include - -#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; - std::shared_ptr thread_pool; - - public: - UManager(std::shared_ptr ThreadPool, - std::shared_ptr ReportInterface); - ~UManager(); - - void ValidateProcessThreads(); - void ValidateProcessMemory(); - void ValidateProcessModules(); -}; -} - -#endif \ No newline at end of file diff --git a/user/user.vcxproj b/user/user.vcxproj deleted file mode 100644 index 7e8f42f..0000000 --- a/user/user.vcxproj +++ /dev/null @@ -1,283 +0,0 @@ - - - - - Debug - Win32 - - - Release - No Server - Win11 - Win32 - - - Release - No Server - Win11 - x64 - - - Release - No Server - Win32 - - - Release - No Server - x64 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {3c8194c7-9f20-4ff8-8c4c-b26c3d053611} - user - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - Application - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - Imagehlp.lib;%(AdditionalDependencies) - C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp20 - - - Console - true - true - true - Imagehlp.lib;%(AdditionalDependencies) - C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions) - true - - - Console - true - true - true - Imagehlp.lib;%(AdditionalDependencies) - C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions) - true - - - Console - true - true - true - Imagehlp.lib;%(AdditionalDependencies) - C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file