mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
Rewrite IO handling (#6)
* csq stuff * oh yea * bugfix * epicc * some formating n dat * bug fix * class changes * e * fix up some of the io stuff * fix io PLEASEEE * fff
This commit is contained in:
parent
44d026bb88
commit
85c6fd6665
64 changed files with 2098 additions and 3275 deletions
133
.clang-format
133
.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
|
||||
...
|
||||
|
|
131
.clang-format-c
Normal file
131
.clang-format-c
Normal file
|
@ -0,0 +1,131 @@
|
|||
Language: Cpp
|
||||
BasedOnStyle: webkit
|
||||
AccessModifierOffset: -4
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
|
||||
AlignConsecutiveMacros: true
|
||||
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
|
||||
AlignTrailingComments: true
|
||||
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
|
||||
AlwaysBreakTemplateDeclarations: true #false
|
||||
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakStringLiterals: false
|
||||
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^begin_wpp|^end_wpp|^FUNC |^USESUFFIX |^USESUFFIX '
|
||||
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
|
||||
DerivePointerAlignment: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 8
|
||||
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
|
||||
MacroBlockBegin: '^BEGIN_MODULE$|^BEGIN_TEST_CLASS$|^BEGIN_TEST_METHOD$'
|
||||
MacroBlockEnd: '^END_MODULE$|^END_TEST_CLASS$|^END_TEST_METHOD$'
|
||||
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None #All
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
Standard: Cpp11
|
||||
StatementMacros: [
|
||||
'EXTERN_C',
|
||||
'PAGED',
|
||||
'PAGEDX',
|
||||
'NONPAGED',
|
||||
'PNPCODE',
|
||||
'INITCODE',
|
||||
'_At_',
|
||||
'_When_',
|
||||
'_Success_',
|
||||
'_Check_return_',
|
||||
'_Must_inspect_result_',
|
||||
'_IRQL_requires_same_',
|
||||
'_IRQL_requires_',
|
||||
'_IRQL_requires_max_',
|
||||
'_IRQL_requires_min_',
|
||||
'_IRQL_saves_',
|
||||
'_IRQL_restores_',
|
||||
'_IRQL_saves_global_',
|
||||
'_IRQL_restores_global_',
|
||||
'_IRQL_raises_',
|
||||
'_IRQL_lowers_',
|
||||
'_Acquires_lock_',
|
||||
'_Releases_lock_',
|
||||
'_Acquires_exclusive_lock_',
|
||||
'_Releases_exclusive_lock_',
|
||||
'_Acquires_shared_lock_',
|
||||
'_Releases_shared_lock_',
|
||||
'_Requires_lock_held_',
|
||||
'_Use_decl_annotations_',
|
||||
'_Guarded_by_',
|
||||
'__drv_preferredFunction',
|
||||
'__drv_allocatesMem',
|
||||
'__drv_freesMem',
|
||||
]
|
||||
|
||||
TabWidth: '8'
|
||||
UseTab: Never
|
68
ac.sln
68
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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <ntifs.h>
|
||||
#include <wdftypes.h>
|
||||
#include "io.h"
|
||||
|
||||
#include "types/types.h"
|
||||
|
||||
/*
|
||||
* For numbers < 32, these are equivalent to 0ul < x.
|
||||
|
@ -39,6 +42,8 @@
|
|||
|
||||
#define STATIC static
|
||||
|
||||
#define MAX_MODULE_PATH 256
|
||||
|
||||
/*
|
||||
* Interlocked intrinsics are only atomic with respect to other InterlockedXxx functions,
|
||||
* so all reads and writes to the THREAD_LIST->active flag must be with Interlocked instrinsics
|
||||
|
@ -169,11 +174,29 @@ typedef struct _OB_CALLBACKS_CONFIG
|
|||
|
||||
} OB_CALLBACKS_CONFIG, *POB_CALLBACKS_CONFIG;
|
||||
|
||||
typedef struct _DEFERRED_REPORT
|
||||
{
|
||||
LIST_ENTRY list_entry;
|
||||
PVOID buffer;
|
||||
UINT32 buffer_size;
|
||||
|
||||
} DEFERRED_REPORT, *PDEFERRED_REPORT;
|
||||
|
||||
typedef struct _DEFERRED_REPORTS_HEAD
|
||||
{
|
||||
LIST_ENTRY head;
|
||||
UINT32 count;
|
||||
KGUARDED_MUTEX lock;
|
||||
|
||||
} DEFERRED_REPORTS_HEAD, *PDEFERRED_REPORTS_HEAD;
|
||||
|
||||
typedef struct _IRP_QUEUE_HEAD
|
||||
{
|
||||
SINGLE_LIST_ENTRY start;
|
||||
volatile INT count;
|
||||
KGUARDED_MUTEX lock;
|
||||
LIST_ENTRY queue;
|
||||
volatile UINT32 count;
|
||||
IO_CSQ csq;
|
||||
KGUARDED_MUTEX lock;
|
||||
DEFERRED_REPORTS_HEAD reports;
|
||||
|
||||
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;
|
||||
|
||||
|
@ -282,15 +305,6 @@ typedef struct _PROCESS_CONFIG
|
|||
#define KPRCB_OFFSET_FROM_GS_BASE 0x180
|
||||
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
|
||||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
#define REPORT_APC_STACKWALK 110
|
||||
#define REPORT_DPC_STACKWALK 120
|
||||
#define REPORT_DATA_TABLE_ROUTINE 130
|
||||
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
||||
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,9 +64,6 @@ GetDriverSymbolicLink();
|
|||
PSYSTEM_INFORMATION
|
||||
GetDriverConfigSystemInformation();
|
||||
|
||||
PREPORT_QUEUE_HEAD
|
||||
GetDriverReportQueue();
|
||||
|
||||
PTHREAD_LIST_HEAD
|
||||
GetThreadList();
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@
|
|||
<ClCompile Include="hv.c" />
|
||||
<ClCompile Include="imports.c" />
|
||||
<ClCompile Include="integrity.c" />
|
||||
<ClCompile Include="ioctl.c" />
|
||||
<ClCompile Include="io.c" />
|
||||
<ClCompile Include="list.c" />
|
||||
<ClCompile Include="modules.c" />
|
||||
<ClCompile Include="pool.c" />
|
||||
|
@ -266,12 +266,13 @@
|
|||
<ClInclude Include="ia32.h" />
|
||||
<ClInclude Include="imports.h" />
|
||||
<ClInclude Include="integrity.h" />
|
||||
<ClInclude Include="ioctl.h" />
|
||||
<ClInclude Include="io.h" />
|
||||
<ClInclude Include="list.h" />
|
||||
<ClInclude Include="modules.h" />
|
||||
<ClInclude Include="pool.h" />
|
||||
<ClInclude Include="queue.h" />
|
||||
<ClInclude Include="thread.h" />
|
||||
<ClInclude Include="types\types.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="arch.asm" />
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
<ClCompile Include="driver.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ioctl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="modules.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -60,6 +57,9 @@
|
|||
<ClCompile Include="list.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="driver.h">
|
||||
|
@ -68,9 +68,6 @@
|
|||
<ClInclude Include="common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ioctl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="modules.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -104,6 +101,12 @@
|
|||
<ClInclude Include="list.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="io.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="types\types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="arch.asm">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <intrin.h>
|
||||
#include "imports.h"
|
||||
#include "common.h"
|
||||
#include "ioctl.h"
|
||||
#include "io.h"
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
# pragma alloc_text(PAGE, PerformVirtualizationDetection)
|
||||
|
|
|
@ -4,13 +4,6 @@
|
|||
#include <ntifs.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef struct _HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
|
||||
} HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
|
||||
|
||||
NTSTATUS
|
||||
PerformVirtualizationDetection(_Inout_ PIRP Irp);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "driver.h"
|
||||
#include "modules.h"
|
||||
#include "callbacks.h"
|
||||
#include "ioctl.h"
|
||||
#include "io.h"
|
||||
#include "imports.h"
|
||||
|
||||
#include <bcrypt.h>
|
||||
|
@ -18,8 +18,6 @@ typedef struct _INTEGRITY_CHECK_HEADER
|
|||
|
||||
} INTEGRITY_CHECK_HEADER, *PINTEGRITY_CHECK_HEADER;
|
||||
|
||||
#define MAX_MODULE_PATH 256
|
||||
|
||||
typedef struct _PROCESS_MODULE_INFORMATION
|
||||
{
|
||||
PVOID module_base;
|
||||
|
@ -933,28 +931,29 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
|
|||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because each module is passed per IRP we don't need to send any reports
|
||||
* to the queue we can simply pass it back to usermode via the same IRP.
|
||||
* We also don't need to send any module information since usermode has everything
|
||||
* needed to file the report.
|
||||
*/
|
||||
validation_result.is_module_valid = CompareHashes(disk_hash, memory_hash, memory_hash_size);
|
||||
|
||||
status = ValidateIrpOutputBuffer(Irp, sizeof(PROCESS_MODULE_VALIDATION_RESULT));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
if (!CompareHashes(disk_hash, memory_hash, memory_hash_size))
|
||||
{
|
||||
DEBUG_ERROR("Failed to validate IRP output buffer");
|
||||
goto end;
|
||||
PPROCESS_MODULE_VALIDATION_REPORT report = ImpExAllocatePool2(
|
||||
POOL_FLAG_NON_PAGED, sizeof(PROCESS_MODULE_VALIDATION_REPORT), REPORT_POOL_TAG);
|
||||
|
||||
if (!report)
|
||||
goto end;
|
||||
|
||||
report->report_code = REPORT_INVALID_PROCESS_MODULE;
|
||||
report->image_base = module_info->module_base;
|
||||
report->image_size = module_info->module_size;
|
||||
RtlCopyMemory(report->module_path, module_info->module_path,
|
||||
sizeof(report->module_path));
|
||||
|
||||
status = IrpQueueCompleteIrp(report, sizeof(PROCESS_MODULE_VALIDATION_REPORT));
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("IrpQueueCompleteIrp failed with status %x", status);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof(PROCESS_MODULE_VALIDATION_RESULT);
|
||||
|
||||
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
|
||||
&validation_result,
|
||||
sizeof(PROCESS_MODULE_VALIDATION_RESULT));
|
||||
|
||||
end:
|
||||
|
||||
if (section_handle)
|
||||
|
|
|
@ -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();
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef IOCTL_H
|
||||
#define IOCTL_H
|
||||
#ifndef IO_H
|
||||
#define IO_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <wdftypes.h>
|
||||
|
@ -27,7 +27,10 @@ ValidateIrpOutputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
|
|||
NTSTATUS
|
||||
ValidateIrpInputBuffer(_In_ PIRP Irp, _In_ ULONG RequiredSize);
|
||||
|
||||
VOID
|
||||
NTSTATUS
|
||||
IrpQueueInitialise();
|
||||
|
||||
NTSTATUS
|
||||
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize);
|
||||
|
||||
#endif
|
108
driver/modules.c
108
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -4,15 +4,6 @@
|
|||
#include <ntifs.h>
|
||||
#include "common.h"
|
||||
|
||||
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 4096
|
||||
|
||||
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
|
||||
|
||||
} INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
|
||||
NTSTATUS
|
||||
FindUnlinkedProcesses();
|
||||
|
||||
|
|
207
driver/queue.c
207
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;
|
||||
}
|
|
@ -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
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,34 +6,6 @@
|
|||
#include "common.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[4096];
|
||||
|
||||
} HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
|
||||
typedef struct _ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT32 thread_id;
|
||||
UINT64 thread_address;
|
||||
|
||||
} ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
|
||||
|
||||
typedef struct _KPRCB_THREAD_VALIDATION_CTX
|
||||
{
|
||||
UINT64 thread;
|
||||
BOOLEAN thread_found_in_pspcidtable;
|
||||
// BOOLEAN thread_found_in_kthreadlist;
|
||||
BOOLEAN finished;
|
||||
|
||||
} KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
|
||||
|
||||
BOOLEAN
|
||||
ValidateThreadsPspCidTableEntry(_In_ PETHREAD Thread);
|
||||
|
||||
|
|
141
driver/types/types.h
Normal file
141
driver/types/types.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
#define REPORT_APC_STACKWALK 110
|
||||
#define REPORT_DPC_STACKWALK 120
|
||||
#define REPORT_DATA_TABLE_ROUTINE 130
|
||||
#define REPORT_INVALID_PROCESS_MODULE 140
|
||||
|
||||
typedef enum _TABLE_ID
|
||||
{
|
||||
HalDispatch = 0,
|
||||
HalPrivateDispatch
|
||||
} TABLE_ID;
|
||||
|
||||
typedef struct _HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
|
||||
} HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
|
||||
|
||||
#define APC_STACKWALK_BUFFER_SIZE 500
|
||||
|
||||
typedef struct _APC_STACKWALK_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
|
||||
} APC_STACKWALK_REPORT, *PAPC_STACKWALK_REPORT;
|
||||
|
||||
typedef struct _DPC_STACKWALK_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
|
||||
} DPC_STACKWALK_REPORT, *PDPC_STACKWALK_REPORT;
|
||||
|
||||
typedef struct _MODULE_VALIDATION_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT report_type;
|
||||
UINT64 driver_base_address;
|
||||
UINT64 driver_size;
|
||||
CHAR driver_name[128];
|
||||
|
||||
} MODULE_VALIDATION_FAILURE, *PMODULE_VALIDATION_FAILURE;
|
||||
|
||||
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
|
||||
|
||||
typedef struct _DATA_TABLE_ROUTINE_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
TABLE_ID id;
|
||||
UINT64 address;
|
||||
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
|
||||
|
||||
} DATA_TABLE_ROUTINE_REPORT, *PDATA_TABLE_ROUTINE_REPORT;
|
||||
|
||||
typedef struct _NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
|
||||
} NMI_CALLBACK_FAILURE, *PNMI_CALLBACK_FAILURE;
|
||||
|
||||
#define REPORT_INVALID_PROCESS_BUFFER_SIZE 500
|
||||
|
||||
typedef struct _INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
|
||||
|
||||
} INVALID_PROCESS_ALLOCATION_REPORT, *PINVALID_PROCESS_ALLOCATION_REPORT;
|
||||
|
||||
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[500];
|
||||
|
||||
} HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
|
||||
typedef struct _ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT32 thread_id;
|
||||
UINT64 thread_address;
|
||||
|
||||
} ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
|
||||
|
||||
typedef struct _KPRCB_THREAD_VALIDATION_CTX
|
||||
{
|
||||
UINT64 thread;
|
||||
BOOLEAN thread_found_in_pspcidtable;
|
||||
// BOOLEAN thread_found_in_kthreadlist;
|
||||
BOOLEAN finished;
|
||||
|
||||
} KPRCB_THREAD_VALIDATION_CTX, *PKPRCB_THREAD_VALIDATION_CTX;
|
||||
|
||||
#define HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH 64
|
||||
|
||||
typedef struct _OPEN_HANDLE_FAILURE_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT is_kernel_handle;
|
||||
LONG process_id;
|
||||
LONG thread_id;
|
||||
LONG access;
|
||||
CHAR process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
|
||||
|
||||
} OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT;
|
||||
|
||||
#define MODULE_PATH_LEN 256
|
||||
|
||||
typedef struct _PROCESS_MODULE_VALIDATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 image_base;
|
||||
UINT32 image_size;
|
||||
WCHAR module_path[MODULE_PATH_LEN];
|
||||
|
||||
} PROCESS_MODULE_VALIDATION_REPORT, *PPROCESS_MODULE_VALIDATION_REPORT;
|
||||
|
||||
#endif
|
29
module/client/message_queue.cpp
Normal file
29
module/client/message_queue.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "message_queue.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define TEST_STEAM_64_ID 123456789;
|
||||
|
||||
client::message_queue::message_queue(LPTSTR PipeName) {
|
||||
#if NO_SERVER
|
||||
LOG_INFO("No_Server build used. Not opening named pipe.");
|
||||
#else
|
||||
this->pipe_interface = std::make_unique<client::pipe>(PipeName);
|
||||
#endif
|
||||
}
|
||||
|
||||
void client::message_queue::dequeue_message(void *Buffer, size_t Size) {
|
||||
#if NO_SERVER
|
||||
return;
|
||||
#else
|
||||
this->pipe_interface->read_pipe(Buffer, Size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void client::message_queue::enqueue_message(void *Buffer, size_t Size) {
|
||||
#if NO_SERVER
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
43
module/client/message_queue.h
Normal file
43
module/client/message_queue.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef REPORT_H
|
||||
#define REPORT_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../dispatcher/threadpool.h"
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#include "pipe.h"
|
||||
|
||||
#define REPORT_BUFFER_SIZE 8192
|
||||
#define SEND_BUFFER_SIZE 8192
|
||||
|
||||
#define MAX_SIGNATURE_SIZE 256
|
||||
|
||||
#define MESSAGE_TYPE_CLIENT_REPORT 1
|
||||
#define MESSAGE_TYPE_CLIENT_SEND 2
|
||||
#define MESSAGE_TYPE_CLIENT_REQUEST 3
|
||||
|
||||
namespace client {
|
||||
|
||||
class message_queue {
|
||||
struct MESSAGE_PACKET_HEADER {
|
||||
int message_type;
|
||||
int request_id;
|
||||
unsigned __int64 steam64_id;
|
||||
};
|
||||
|
||||
std::unique_ptr<client::pipe> pipe_interface;
|
||||
std::mutex lock;
|
||||
|
||||
byte report_buffer[REPORT_BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
message_queue(LPTSTR PipeName);
|
||||
void enqueue_message(void *Buffer, size_t Size);
|
||||
void dequeue_message(void *Buffer, size_t Size);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif
|
40
module/client/pipe.cpp
Normal file
40
module/client/pipe.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "pipe.h"
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
client::pipe::pipe(LPTSTR PipeName) {
|
||||
this->pipe_name = PipeName;
|
||||
this->pipe_handle =
|
||||
CreateFile(this->pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
|
||||
if (this->pipe_handle == INVALID_HANDLE_VALUE) {
|
||||
LOG_ERROR("CreateFile failed with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void client::pipe::write_pipe(PVOID Buffer, SIZE_T Size) {
|
||||
DWORD bytes_written = 0;
|
||||
|
||||
WriteFile(this->pipe_handle, Buffer, Size, &bytes_written, NULL);
|
||||
|
||||
if (bytes_written == 0) {
|
||||
LOG_ERROR("WriteFile failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void client::pipe::read_pipe(PVOID Buffer, SIZE_T Size) {
|
||||
BOOL status = FALSE;
|
||||
DWORD bytes_read = 0;
|
||||
|
||||
status = ReadFile(this->pipe_handle, Buffer, Size, &bytes_read, NULL);
|
||||
|
||||
if (status == NULL) {
|
||||
LOG_ERROR("ReadFile failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
51
module/client/pipe.h
Normal file
51
module/client/pipe.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define MESSAGE_TYPE_CLIENT_REPORT 1
|
||||
#define MESSAGE_TYPE_CLIENT_SEND 2
|
||||
#define MESSAGE_TYPE_CLIENT_REQUEST 3
|
||||
|
||||
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
|
||||
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
|
||||
|
||||
namespace client {
|
||||
class pipe {
|
||||
HANDLE pipe_handle;
|
||||
LPTSTR pipe_name;
|
||||
|
||||
public:
|
||||
pipe(LPTSTR PipeName);
|
||||
|
||||
void write_pipe(PVOID Buffer, SIZE_T Size);
|
||||
void read_pipe(PVOID Buffer, SIZE_T Size);
|
||||
};
|
||||
|
||||
namespace headers {
|
||||
typedef enum _ENVIRONMENT_TYPE {
|
||||
NativeWindows = 0,
|
||||
Vmware,
|
||||
VirtualBox
|
||||
|
||||
} ENVIRONMENT_TYPE;
|
||||
|
||||
typedef enum _PROCESSOR_TYPE {
|
||||
Unknown = 0,
|
||||
GenuineIntel,
|
||||
AuthenticAmd
|
||||
|
||||
} PROCESSOR_TYPE;
|
||||
|
||||
#define VENDOR_STRING_MAX_LENGTH 256
|
||||
struct SYSTEM_INFORMATION {
|
||||
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
|
||||
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
|
||||
CHAR vendor[VENDOR_STRING_MAX_LENGTH];
|
||||
BOOLEAN virtualised_environment;
|
||||
ENVIRONMENT_TYPE environment;
|
||||
PROCESSOR_TYPE processor;
|
||||
RTL_OSVERSIONINFOW os_information;
|
||||
};
|
||||
|
||||
} // namespace headers
|
||||
} // namespace client
|
|
@ -1,11 +1,11 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#define LOG_INFO(fmt, ...) printf("[+] " fmt "\n", ##__VA_ARGS__)
|
||||
#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#define LOG_ERROR(fmt, ...) printf("[-] " fmt "\n", ##__VA_ARGS__)
|
62
module/dispatcher/dispatcher.cpp
Normal file
62
module/dispatcher/dispatcher.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "dispatcher.h"
|
||||
|
||||
#include "../client/message_queue.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
dispatcher::dispatcher::dispatcher(LPCWSTR driver_name,
|
||||
client::message_queue &message_queue)
|
||||
: thread_pool(DISPATCHER_THREAD_COUNT),
|
||||
k_interface(driver_name, message_queue) {}
|
||||
|
||||
void dispatcher::dispatcher::run() {
|
||||
helper::generate_rand_seed();
|
||||
thread_pool.queue_job([this]() { k_interface.run_completion_port(); });
|
||||
while (true) {
|
||||
this->issue_kernel_job();
|
||||
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
void dispatcher::dispatcher::issue_kernel_job() {
|
||||
switch (helper::generate_rand_int(KERNEL_DISPATCH_FUNCTION_COUNT)) {
|
||||
case 0:
|
||||
thread_pool.queue_job([this]() { k_interface.enumerate_handle_tables(); });
|
||||
break;
|
||||
case 1:
|
||||
thread_pool.queue_job([this]() { k_interface.perform_integrity_check(); });
|
||||
break;
|
||||
case 2:
|
||||
thread_pool.queue_job(
|
||||
[this]() { k_interface.scan_for_unlinked_processes(); });
|
||||
break;
|
||||
case 3:
|
||||
thread_pool.queue_job(
|
||||
[this]() { k_interface.verify_process_module_executable_regions(); });
|
||||
break;
|
||||
case 4:
|
||||
thread_pool.queue_job(
|
||||
[this]() { k_interface.validate_system_driver_objects(); });
|
||||
break;
|
||||
case 5:
|
||||
thread_pool.queue_job([this]() { k_interface.run_nmi_callbacks(); });
|
||||
break;
|
||||
case 6:
|
||||
thread_pool.queue_job(
|
||||
[this]() { k_interface.scan_for_attached_threads(); });
|
||||
break;
|
||||
case 7:
|
||||
thread_pool.queue_job([this]() { k_interface.initiate_apc_stackwalk(); });
|
||||
break;
|
||||
case 8:
|
||||
thread_pool.queue_job([this]() { k_interface.scan_for_ept_hooks(); });
|
||||
break;
|
||||
case 9:
|
||||
thread_pool.queue_job([this]() { k_interface.perform_dpc_stackwalk(); });
|
||||
break;
|
||||
case 10:
|
||||
thread_pool.queue_job([this]() { k_interface.validate_system_modules(); });
|
||||
break;
|
||||
}
|
||||
}
|
23
module/dispatcher/dispatcher.h
Normal file
23
module/dispatcher/dispatcher.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "threadpool.h"
|
||||
|
||||
#include "../kernel_interface/kernel_interface.h"
|
||||
|
||||
namespace dispatcher {
|
||||
|
||||
static const int DISPATCH_LOOP_SLEEP_TIME = 10;
|
||||
static const int KERNEL_DISPATCH_FUNCTION_COUNT = 11;
|
||||
static const int DISPATCHER_THREAD_COUNT = 4;
|
||||
|
||||
class dispatcher {
|
||||
thread_pool thread_pool;
|
||||
kernel_interface::kernel_interface k_interface;
|
||||
|
||||
void issue_kernel_job();
|
||||
|
||||
public:
|
||||
dispatcher(LPCWSTR driver_name, client::message_queue &queue);
|
||||
void run();
|
||||
};
|
||||
} // namespace dispatcher
|
92
module/dispatcher/threadpool.cpp
Normal file
92
module/dispatcher/threadpool.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#include "threadpool.h"
|
||||
|
||||
/*
|
||||
* This is the idle loop each thread will be running until a job is ready
|
||||
* for execution
|
||||
*/
|
||||
void dispatcher::thread_pool::wait_for_task() {
|
||||
while (true) {
|
||||
std::function<void()> job;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
/*
|
||||
* This is equivalent to :
|
||||
*
|
||||
* while (!this->jobs.empty() || should_terminate)
|
||||
* mutex_condition.wait(lock);
|
||||
*
|
||||
* we are essentially waiting for a job to be queued up or the terminate
|
||||
*flag to be set. Another piece of useful information is that the
|
||||
*predicate is checked under the lock as the precondition for .wait() is
|
||||
*that the calling thread owns the lock.
|
||||
*
|
||||
* Now, when .wait() is run, the lock is unlocked the the executing thread
|
||||
*is blocked and is added to a list of threads current waiting on the
|
||||
*predicate. In our case whether there are new jobs available for the
|
||||
*terminate flag is set. Once the condition variables are true i.e there
|
||||
*are new jobs or we are terminating, the lock is reacquired by the thread
|
||||
*and the thread is unblocked.
|
||||
*/
|
||||
mutex_condition.wait(lock, [this] {
|
||||
return !this->jobs.empty() || this->should_terminate;
|
||||
});
|
||||
|
||||
if (this->should_terminate)
|
||||
return;
|
||||
|
||||
/* get the first job in the queue*/
|
||||
job = jobs.front();
|
||||
jobs.pop();
|
||||
}
|
||||
/* run the job */
|
||||
job();
|
||||
}
|
||||
}
|
||||
|
||||
dispatcher::thread_pool::thread_pool(int thread_count) {
|
||||
this->thread_count = thread_count;
|
||||
this->should_terminate = false;
|
||||
|
||||
/* Initiate our threads and store them in our threads vector */
|
||||
for (int i = 0; i < this->thread_count; i++) {
|
||||
this->threads.emplace_back(std::thread(&thread_pool::wait_for_task, this));
|
||||
}
|
||||
}
|
||||
|
||||
void dispatcher::thread_pool::queue_job(const std::function<void()> &job) {
|
||||
/* push a job into our job queue safely by holding our queue lock */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
this->jobs.push(job);
|
||||
lock.unlock();
|
||||
|
||||
mutex_condition.notify_one();
|
||||
}
|
||||
|
||||
void dispatcher::thread_pool::terminate() {
|
||||
/* safely set our termination flag to true */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
should_terminate = true;
|
||||
lock.unlock();
|
||||
|
||||
/* unlock all threads waiting on our condition */
|
||||
mutex_condition.notify_all();
|
||||
|
||||
/* join the threads and clear our threads vector */
|
||||
for (std::thread &thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
threads.clear();
|
||||
}
|
||||
|
||||
bool dispatcher::thread_pool::busy_wait() {
|
||||
/* allows us to wait for when the job queue is empty allowing us to safely
|
||||
* call the destructor */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
bool pool_busy = !jobs.empty();
|
||||
this->queue_mutex.unlock();
|
||||
|
||||
return pool_busy;
|
||||
}
|
30
module/dispatcher/threadpool.h
Normal file
30
module/dispatcher/threadpool.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace dispatcher {
|
||||
/*
|
||||
* This ThreadPool class is a simple threadpool implementation that will allow
|
||||
* us to delegate jobs to a set number of threads without the constant need to
|
||||
* close and open new threads.
|
||||
*/
|
||||
class thread_pool {
|
||||
int thread_count;
|
||||
bool should_terminate;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable mutex_condition;
|
||||
std::vector<std::thread> threads;
|
||||
std::queue<std::function<void()>> jobs;
|
||||
|
||||
void wait_for_task();
|
||||
|
||||
public:
|
||||
thread_pool(int thread_count);
|
||||
void queue_job(const std::function<void()> &job);
|
||||
void terminate();
|
||||
bool busy_wait();
|
||||
};
|
||||
} // namespace dispatcher
|
169
module/helper.cpp
Normal file
169
module/helper.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include "helper.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
|
||||
void helper::generate_rand_seed() { srand(time(nullptr)); }
|
||||
|
||||
int helper::generate_rand_int(int max) { return rand() % max; }
|
||||
|
||||
void helper::sleep_thread(int seconds) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(seconds));
|
||||
}
|
||||
|
||||
int helper::get_report_id_from_buffer(void *buffer) {
|
||||
kernel_interface::report_header *header =
|
||||
reinterpret_cast<kernel_interface::report_header *>(buffer);
|
||||
return header->report_id;
|
||||
}
|
||||
|
||||
kernel_interface::report_id helper::get_kernel_report_type(void *buffer) {
|
||||
switch (helper::get_report_id_from_buffer(buffer)) {
|
||||
case kernel_interface::report_id::report_nmi_callback_failure:
|
||||
return kernel_interface::report_id::report_nmi_callback_failure;
|
||||
|
||||
case kernel_interface::report_id::report_module_validation_failure:
|
||||
return kernel_interface::report_id::report_module_validation_failure;
|
||||
|
||||
case kernel_interface::report_id::report_illegal_handle_operation:
|
||||
return kernel_interface::report_id::report_illegal_handle_operation;
|
||||
|
||||
case kernel_interface::report_id::report_invalid_process_allocation:
|
||||
return kernel_interface::report_id::report_invalid_process_allocation;
|
||||
|
||||
case kernel_interface::report_id::report_hidden_system_thread:
|
||||
return kernel_interface::report_id::report_hidden_system_thread;
|
||||
|
||||
case kernel_interface::report_id::report_illegal_attach_process:
|
||||
return kernel_interface::report_id::report_illegal_attach_process;
|
||||
|
||||
case kernel_interface::report_id::report_apc_stackwalk:
|
||||
return kernel_interface::report_id::report_apc_stackwalk;
|
||||
|
||||
case kernel_interface::report_id::report_dpc_stackwalk:
|
||||
return kernel_interface::report_id::report_dpc_stackwalk;
|
||||
|
||||
case kernel_interface::report_id::report_data_table_routine:
|
||||
return kernel_interface::report_id::report_data_table_routine;
|
||||
}
|
||||
}
|
||||
|
||||
void helper::print_kernel_report(void *buffer) {
|
||||
switch (get_kernel_report_type(buffer)) {
|
||||
case kernel_interface::report_id::report_nmi_callback_failure: {
|
||||
kernel_interface::nmi_callback_failure *r1 =
|
||||
reinterpret_cast<kernel_interface::nmi_callback_failure *>(buffer);
|
||||
LOG_INFO("report type: nmi_callback_failure");
|
||||
LOG_INFO("report code: %lx", r1->report_code);
|
||||
LOG_INFO("were_nmis_disabled: %lx", r1->were_nmis_disabled);
|
||||
LOG_INFO("kthread_address: %llx", r1->kthread_address);
|
||||
LOG_INFO("invalid_rip: %llx", r1->invalid_rip);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_invalid_process_allocation: {
|
||||
kernel_interface::invalid_process_allocation_report *r2 =
|
||||
reinterpret_cast<kernel_interface::invalid_process_allocation_report *>(
|
||||
buffer);
|
||||
LOG_INFO("report type: invalid_process_allocation_report");
|
||||
LOG_INFO("report code: %d", r2->report_code);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_hidden_system_thread: {
|
||||
kernel_interface::hidden_system_thread_report *r3 =
|
||||
reinterpret_cast<kernel_interface::hidden_system_thread_report *>(
|
||||
buffer);
|
||||
LOG_INFO("report type: hidden_system_thread_report");
|
||||
LOG_INFO("report code: %lx", r3->report_code);
|
||||
LOG_INFO("found_in_kthreadlist: %lx", r3->found_in_kthreadlist);
|
||||
LOG_INFO("found_in_pspcidtable: %lx", r3->found_in_pspcidtable);
|
||||
LOG_INFO("thread_address: %llx", r3->thread_address);
|
||||
LOG_INFO("thread_id: %lx", r3->thread_id);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_illegal_attach_process: {
|
||||
kernel_interface::attach_process_report *r4 =
|
||||
reinterpret_cast<kernel_interface::attach_process_report *>(buffer);
|
||||
LOG_INFO("report type: attach_process_report");
|
||||
LOG_INFO("report code: %lx", r4->report_code);
|
||||
LOG_INFO("thread_id: %lx", r4->thread_id);
|
||||
LOG_INFO("thread_address: %llx", r4->thread_address);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_illegal_handle_operation: {
|
||||
kernel_interface::open_handle_failure_report *r5 =
|
||||
reinterpret_cast<kernel_interface::open_handle_failure_report *>(
|
||||
buffer);
|
||||
LOG_INFO("report type: open_handle_failure_report");
|
||||
LOG_INFO("report code: %lx", r5->report_code);
|
||||
LOG_INFO("is_kernel_handle: %lx", r5->is_kernel_handle);
|
||||
LOG_INFO("process_id: %lx", r5->process_id);
|
||||
LOG_INFO("thread_id: %lx", r5->thread_id);
|
||||
LOG_INFO("access: %lx", r5->access);
|
||||
LOG_INFO("process_name: %s", r5->process_name);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_invalid_process_module: {
|
||||
kernel_interface::process_module_validation_report *r6 =
|
||||
reinterpret_cast<kernel_interface::process_module_validation_report *>(
|
||||
buffer);
|
||||
LOG_INFO("report type: process_module_validation_report");
|
||||
LOG_INFO("report code: %d", r6->report_code);
|
||||
LOG_INFO("image_base: %llx", r6->image_base);
|
||||
LOG_INFO("image_size: %u", r6->image_size);
|
||||
LOG_INFO("module_path: %ls", r6->module_path);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_apc_stackwalk: {
|
||||
kernel_interface::apc_stackwalk_report *r7 =
|
||||
reinterpret_cast<kernel_interface::apc_stackwalk_report *>(buffer);
|
||||
LOG_INFO("report type: apc_stackwalk_report");
|
||||
LOG_INFO("report code: %d", r7->report_code);
|
||||
LOG_INFO("kthread_address: %llx", r7->kthread_address);
|
||||
LOG_INFO("invalid_rip: %llx", r7->invalid_rip);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_dpc_stackwalk: {
|
||||
kernel_interface::dpc_stackwalk_report *r8 =
|
||||
reinterpret_cast<kernel_interface::dpc_stackwalk_report *>(buffer);
|
||||
LOG_INFO("report type: dpc_stackwalk_report");
|
||||
LOG_INFO("report code: %d", r8->report_code);
|
||||
LOG_INFO("kthread_address: %llx", r8->kthread_address);
|
||||
LOG_INFO("invalid_rip: %llx", r8->invalid_rip);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_data_table_routine: {
|
||||
kernel_interface::data_table_routine_report *r9 =
|
||||
reinterpret_cast<kernel_interface::data_table_routine_report *>(buffer);
|
||||
LOG_INFO("report type: data_table_routine_report");
|
||||
LOG_INFO("report code: %d", r9->report_code);
|
||||
LOG_INFO("id: %d", r9->id);
|
||||
LOG_INFO("address: %llx", r9->address);
|
||||
LOG_INFO("routine: %s", r9->routine);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
case kernel_interface::report_id::report_module_validation_failure: {
|
||||
kernel_interface::module_validation_failure *r10 =
|
||||
reinterpret_cast<kernel_interface::module_validation_failure *>(buffer);
|
||||
LOG_INFO("report type: module_validation_failure");
|
||||
LOG_INFO("report code: %lx", r10->report_code);
|
||||
LOG_INFO("report type: %lx", r10->report_type);
|
||||
LOG_INFO("driver_base_address: %llx", r10->driver_base_address);
|
||||
LOG_INFO("driver_size: %llx", r10->driver_size);
|
||||
LOG_INFO("driver_name: %s", r10->driver_name);
|
||||
LOG_INFO("********************************");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_INFO("Invalid report type.");
|
||||
break;
|
||||
}
|
||||
}
|
12
module/helper.h
Normal file
12
module/helper.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "kernel_interface/kernel_interface.h"
|
||||
|
||||
namespace helper {
|
||||
void generate_rand_seed();
|
||||
int generate_rand_int(int max);
|
||||
void sleep_thread(int seconds);
|
||||
kernel_interface::report_id get_kernel_report_type(void *buffer);
|
||||
int get_report_id_from_buffer(void *buffer);
|
||||
void print_kernel_report(void *buffer);
|
||||
} // namespace helper
|
3
module/imports.cpp
Normal file
3
module/imports.cpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "imports.h"
|
||||
|
||||
bool imports::initialise_imports() { return false; }
|
8
module/imports.h
Normal file
8
module/imports.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
namespace imports
|
||||
{
|
||||
bool initialise_imports();
|
||||
|
||||
|
||||
}
|
290
module/kernel_interface/kernel_interface.cpp
Normal file
290
module/kernel_interface/kernel_interface.cpp
Normal file
|
@ -0,0 +1,290 @@
|
|||
#include "kernel_interface.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../common.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include <TlHelp32.h>
|
||||
#include <winternl.h>
|
||||
|
||||
typedef BOOLEAN(NTAPI *RtlDosPathNameToNtPathName_U)(PCWSTR DosPathName,
|
||||
PUNICODE_STRING NtPathName,
|
||||
PCWSTR *NtFileNamePart,
|
||||
PVOID DirectoryInfo);
|
||||
|
||||
kernel_interface::event_dispatcher *
|
||||
kernel_interface::kernel_interface::get_free_event_entry() {
|
||||
std::lock_guard<std::mutex> lock(this->lock);
|
||||
for (std::vector<event_dispatcher>::iterator it = events.begin();
|
||||
it != events.end(); it++) {
|
||||
if (it->in_use == false) {
|
||||
it->in_use = true;
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::terminate_completion_port() {
|
||||
std::lock_guard<std::mutex> lock(this->lock);
|
||||
for (std::vector<event_dispatcher>::iterator it = events.begin();
|
||||
it != events.end(); it++) {
|
||||
free(it->buffer);
|
||||
CloseHandle(it->overlapped.hEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::run_completion_port() {
|
||||
DWORD bytes = 0;
|
||||
OVERLAPPED *io = nullptr;
|
||||
ULONG_PTR key = 0;
|
||||
while (true) {
|
||||
GetQueuedCompletionStatus(this->port, &bytes, &key, &io, INFINITE);
|
||||
if (io == nullptr)
|
||||
continue;
|
||||
void *buffer = get_buffer_from_event_object(io);
|
||||
helper::print_kernel_report(buffer);
|
||||
release_event_object(io);
|
||||
send_pending_irp();
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::initiate_completion_port() {
|
||||
for (int index = 0; index < EVENT_COUNT; index++) {
|
||||
void *buffer = malloc(MAXIMUM_REPORT_BUFFER_SIZE);
|
||||
this->events.push_back(
|
||||
event_dispatcher(buffer, MAXIMUM_REPORT_BUFFER_SIZE));
|
||||
}
|
||||
this->port = CreateIoCompletionPort(this->driver_handle, nullptr, 0, 0);
|
||||
if (!this->port) {
|
||||
LOG_ERROR("CreateIoCompletePort failed with status %x", GetLastError());
|
||||
return;
|
||||
}
|
||||
for (int index = 0; index < EVENT_COUNT; index++) {
|
||||
send_pending_irp();
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::release_event_object(
|
||||
OVERLAPPED *event) {
|
||||
std::lock_guard<std::mutex> lock(this->lock);
|
||||
for (std::vector<event_dispatcher>::iterator it = events.begin();
|
||||
it != events.end(); it++) {
|
||||
if (&it->overlapped == event) {
|
||||
/* simply zero our the buffer, no need to free and realloc */
|
||||
memset(it->buffer, 0, it->buffer_size);
|
||||
it->in_use = false;
|
||||
ResetEvent(it->overlapped.hEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *kernel_interface::kernel_interface::get_buffer_from_event_object(
|
||||
OVERLAPPED *event) {
|
||||
std::lock_guard<std::mutex> lock(this->lock);
|
||||
for (std::vector<event_dispatcher>::iterator it = events.begin();
|
||||
it != events.end(); it++) {
|
||||
if (&it->overlapped == event) {
|
||||
return it->buffer;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
kernel_interface::kernel_interface::kernel_interface(
|
||||
LPCWSTR driver_name, client::message_queue &queue)
|
||||
: message_queue(queue) {
|
||||
this->driver_name = driver_name;
|
||||
this->port = INVALID_HANDLE_VALUE;
|
||||
this->driver_handle = CreateFileW(
|
||||
driver_name, GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE, 0, 0,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
if (this->driver_handle == INVALID_HANDLE_VALUE) {
|
||||
LOG_ERROR("Failed to open handle to driver with status 0x%x",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
this->notify_driver_on_process_launch();
|
||||
this->initiate_completion_port();
|
||||
}
|
||||
|
||||
kernel_interface::kernel_interface::~kernel_interface() {
|
||||
this->terminate_completion_port();
|
||||
this->notify_driver_on_process_termination();
|
||||
}
|
||||
|
||||
unsigned int kernel_interface::kernel_interface::generic_driver_call_output(
|
||||
ioctl_code ioctl, void *output_buffer, size_t buffer_size,
|
||||
unsigned long *bytes_returned) {
|
||||
return DeviceIoControl(this->driver_handle, ioctl, nullptr, 0, output_buffer,
|
||||
buffer_size, bytes_returned, nullptr);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::generic_driver_call_input(
|
||||
ioctl_code ioctl, void *input_buffer, size_t buffer_size,
|
||||
unsigned long *bytes_returned) {
|
||||
if (!DeviceIoControl(this->driver_handle, ioctl, input_buffer, buffer_size,
|
||||
nullptr, 0, bytes_returned, nullptr))
|
||||
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::generic_driver_call_apc(
|
||||
apc_operation operation) {
|
||||
apc_operation_init init = {0};
|
||||
init.operation_id = operation;
|
||||
this->generic_driver_call_input(ioctl_code::InitiateApcStackwalkOperation,
|
||||
&init, sizeof(init), nullptr);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::notify_driver_on_process_launch() {
|
||||
unsigned long bytes_returned = 0;
|
||||
process_load_packet packet = {0};
|
||||
packet.protected_process_id = GetCurrentProcessId();
|
||||
generic_driver_call_input(ioctl_code::NotifyDriverOnProcessLaunch, &packet,
|
||||
sizeof(packet), &bytes_returned);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::detect_system_virtualization() {
|
||||
unsigned int status = 0;
|
||||
unsigned long bytes_returned = 0;
|
||||
hv_detection_packet packet = {0};
|
||||
status = generic_driver_call_output(ioctl_code::PerformVirtualisationCheck,
|
||||
&packet, sizeof(packet), &bytes_returned);
|
||||
if (!status) {
|
||||
LOG_ERROR("Failed virtualization detection with status %x", GetLastError());
|
||||
return;
|
||||
}
|
||||
if (packet.aperf_msr_timing_check == true ||
|
||||
packet.invd_emulation_check == true)
|
||||
LOG_INFO("HYPERVISOR DETECTED!!!");
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::generic_driver_call(ioctl_code ioctl) {
|
||||
if (!DeviceIoControl(this->driver_handle, ioctl, nullptr, 0, nullptr, 0,
|
||||
nullptr, nullptr))
|
||||
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::run_nmi_callbacks() {
|
||||
this->generic_driver_call(ioctl_code::RunNmiCallbacks);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::validate_system_driver_objects() {
|
||||
this->generic_driver_call(ioctl_code::ValidateDriverObjects);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::enumerate_handle_tables() {
|
||||
this->generic_driver_call(ioctl_code::EnumerateHandleTables);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::scan_for_unlinked_processes() {
|
||||
this->generic_driver_call(ioctl_code::ScanForUnlinkedProcesses);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::perform_integrity_check() {
|
||||
this->generic_driver_call(ioctl_code::PerformModuleIntegrityCheck);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::
|
||||
notify_driver_on_process_termination() {
|
||||
this->generic_driver_call(ioctl_code::NotifyDriverOnProcessTermination);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::scan_for_attached_threads() {
|
||||
this->generic_driver_call(ioctl_code::ScanFroAttachedThreads);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::scan_for_ept_hooks() {
|
||||
this->generic_driver_call(ioctl_code::ScanForEptHooks);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::perform_dpc_stackwalk() {
|
||||
this->generic_driver_call(ioctl_code::InitiateDpcStackwalk);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::validate_system_modules() {
|
||||
this->generic_driver_call(ioctl_code::ValidateSystemModules);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::
|
||||
verify_process_module_executable_regions() {
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
MODULEENTRY32 module_entry = {0};
|
||||
BOOLEAN status = FALSE;
|
||||
process_module module = {0};
|
||||
unsigned long bytes_returned = 0;
|
||||
RtlDosPathNameToNtPathName_U pRtlDosPathNameToNtPathName_U = NULL;
|
||||
UNICODE_STRING nt_path_name = {0};
|
||||
pRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_U)GetProcAddress(
|
||||
GetModuleHandle(L"ntdll.dll"), "RtlDosPathNameToNtPathName_U");
|
||||
handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
|
||||
GetCurrentProcessId());
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with "
|
||||
"status 0x%x",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
module_entry.dwSize = sizeof(MODULEENTRY32);
|
||||
if (!Module32First(handle, &module_entry)) {
|
||||
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
do {
|
||||
module.module_base = module_entry.modBaseAddr;
|
||||
module.module_size = module_entry.modBaseSize;
|
||||
status = (*pRtlDosPathNameToNtPathName_U)(module_entry.szExePath,
|
||||
&nt_path_name, NULL, NULL);
|
||||
if (!status) {
|
||||
LOG_ERROR("RtlDosPathNameToNtPathName_U failed with no status.");
|
||||
continue;
|
||||
}
|
||||
memcpy(module.module_path, nt_path_name.Buffer, MAX_MODULE_PATH);
|
||||
this->generic_driver_call_input(ioctl_code::ValidateProcessLoadedModule,
|
||||
&module, sizeof(module), &bytes_returned);
|
||||
} while (Module32Next(handle, &module_entry));
|
||||
end:
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::initiate_apc_stackwalk() {
|
||||
this->generic_driver_call_apc(apc_operation::operation_stackwalk);
|
||||
}
|
||||
|
||||
void kernel_interface::kernel_interface::send_pending_irp() {
|
||||
DWORD status = 0;
|
||||
event_dispatcher *event = get_free_event_entry();
|
||||
if (!event) {
|
||||
LOG_ERROR("All event objects in use.");
|
||||
return;
|
||||
}
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, ioctl_code::InsertIrpIntoIrpQueue, NULL, NULL,
|
||||
event->buffer, event->buffer_size, NULL, &event->overlapped);
|
||||
/*
|
||||
* im not sure why this returns a status of ERROR_INVALID_FUNCTION when we use
|
||||
* the inserted irp to complete a deferred irp - even though that procedure
|
||||
* should return STATUS_SUCCESS? Weird.. Anyhow it works.
|
||||
*/
|
||||
if (status == ERROR_IO_PENDING || status == ERROR_SUCCESS ||
|
||||
status == ERROR_INVALID_FUNCTION)
|
||||
return;
|
||||
LOG_ERROR("failed to insert irp into irp queue %x", status);
|
||||
}
|
||||
|
||||
//void kernel_interface::kernel_interface::query_deferred_reports() {
|
||||
// unsigned long bytes_returned = 0;
|
||||
// void *buffer = malloc(MAXIMUM_REPORT_BUFFER_SIZE);
|
||||
// if (!buffer)
|
||||
// return;
|
||||
// for (int i = 0; i < QUERY_DEFERRED_REPORT_COUNT; i++) {
|
||||
// unsigned int status =
|
||||
// generic_driver_call_output(ioctl_code::QueryDeferredReports, buffer,
|
||||
// MAXIMUM_REPORT_BUFFER_SIZE, &bytes_returned);
|
||||
// if (status && bytes_returned > 0)
|
||||
// helper::print_kernel_report(buffer);
|
||||
// memset(buffer, 0, MAXIMUM_REPORT_BUFFER_SIZE);
|
||||
// }
|
||||
// free(buffer);
|
||||
//}
|
221
module/kernel_interface/kernel_interface.h
Normal file
221
module/kernel_interface/kernel_interface.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../client/message_queue.h"
|
||||
|
||||
namespace kernel_interface {
|
||||
|
||||
static constexpr int EVENT_COUNT = 5;
|
||||
static constexpr int MAX_MODULE_PATH = 256;
|
||||
static constexpr int MAXIMUM_REPORT_BUFFER_SIZE = 1000;
|
||||
static constexpr int QUERY_DEFERRED_REPORT_COUNT = 10;
|
||||
|
||||
enum report_id {
|
||||
report_nmi_callback_failure = 50,
|
||||
report_module_validation_failure = 60,
|
||||
report_illegal_handle_operation = 70,
|
||||
report_invalid_process_allocation = 80,
|
||||
report_hidden_system_thread = 90,
|
||||
report_illegal_attach_process = 100,
|
||||
report_apc_stackwalk = 110,
|
||||
report_dpc_stackwalk = 120,
|
||||
report_data_table_routine = 130,
|
||||
report_invalid_process_module = 140
|
||||
};
|
||||
|
||||
struct report_header {
|
||||
int report_id;
|
||||
};
|
||||
|
||||
constexpr int APC_STACKWALK_BUFFER_SIZE = 500;
|
||||
constexpr int DATA_TABLE_ROUTINE_BUF_SIZE = 256;
|
||||
constexpr int REPORT_INVALID_PROCESS_BUFFER_SIZE = 500;
|
||||
constexpr int HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH = 64;
|
||||
constexpr int MODULE_PATH_LEN = 256;
|
||||
|
||||
struct apc_stackwalk_report {
|
||||
int report_code;
|
||||
uint64_t kthread_address;
|
||||
uint64_t invalid_rip;
|
||||
char driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
struct dpc_stackwalk_report {
|
||||
uint32_t report_code;
|
||||
uint64_t kthread_address;
|
||||
uint64_t invalid_rip;
|
||||
char driver[APC_STACKWALK_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
struct module_validation_failure {
|
||||
int report_code;
|
||||
int report_type;
|
||||
uint64_t driver_base_address;
|
||||
uint64_t driver_size;
|
||||
char driver_name[128];
|
||||
};
|
||||
|
||||
enum table_id { hal_dispatch = 0, hal_private_dispatch };
|
||||
|
||||
struct data_table_routine_report {
|
||||
uint32_t report_code;
|
||||
table_id id;
|
||||
uint64_t address;
|
||||
char routine[DATA_TABLE_ROUTINE_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct nmi_callback_failure {
|
||||
int report_code;
|
||||
int were_nmis_disabled;
|
||||
uint64_t kthread_address;
|
||||
uint64_t invalid_rip;
|
||||
};
|
||||
|
||||
struct invalid_process_allocation_report {
|
||||
int report_code;
|
||||
char process[REPORT_INVALID_PROCESS_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
struct hidden_system_thread_report {
|
||||
int report_code;
|
||||
int found_in_kthreadlist;
|
||||
int found_in_pspcidtable;
|
||||
uint64_t thread_address;
|
||||
long thread_id;
|
||||
char thread[500];
|
||||
};
|
||||
|
||||
struct attach_process_report {
|
||||
int report_code;
|
||||
uint32_t thread_id;
|
||||
uint64_t thread_address;
|
||||
};
|
||||
|
||||
struct kprcb_thread_validation_ctx {
|
||||
uint64_t thread;
|
||||
bool thread_found_in_pspcidtable;
|
||||
bool finished;
|
||||
};
|
||||
|
||||
struct open_handle_failure_report {
|
||||
int report_code;
|
||||
int is_kernel_handle;
|
||||
long process_id;
|
||||
long thread_id;
|
||||
long access;
|
||||
char process_name[HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH];
|
||||
};
|
||||
|
||||
struct process_module_validation_report {
|
||||
int report_code;
|
||||
uint64_t image_base;
|
||||
uint32_t image_size;
|
||||
wchar_t module_path[MODULE_PATH_LEN];
|
||||
};
|
||||
|
||||
enum apc_operation { operation_stackwalk = 0x1 };
|
||||
|
||||
// clang-format off
|
||||
enum ioctl_code
|
||||
{
|
||||
RunNmiCallbacks = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ValidateDriverObjects = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
NotifyDriverOnProcessLaunch = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
QueryForApcCompletion = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
PerformVirtualisationCheck = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
EnumerateHandleTables = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
NotifyDriverOnProcessTermination = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ScanForUnlinkedProcesses = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
PerformModuleIntegrityCheck = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ScanFroAttachedThreads = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ValidateProcessLoadedModule = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
RequestHardwareInformation = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
InitiateApcStackwalkOperation = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ScanForEptHooks = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
InitiateDpcStackwalk = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
ValidateSystemModules = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
InsertIrpIntoIrpQueue = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20021, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||
QueryDeferredReports = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20022, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
struct event_dispatcher {
|
||||
bool in_use;
|
||||
OVERLAPPED overlapped;
|
||||
void *buffer;
|
||||
unsigned long buffer_size;
|
||||
|
||||
event_dispatcher(void *buffer, unsigned long buffer_size) {
|
||||
this->in_use = false;
|
||||
this->overlapped.hEvent = CreateEvent(nullptr, false, false, nullptr);
|
||||
this->buffer = buffer;
|
||||
this->buffer_size = buffer_size;
|
||||
}
|
||||
};
|
||||
|
||||
class kernel_interface {
|
||||
struct process_load_packet {
|
||||
unsigned long protected_process_id;
|
||||
};
|
||||
|
||||
struct hv_detection_packet {
|
||||
unsigned long aperf_msr_timing_check;
|
||||
unsigned long invd_emulation_check;
|
||||
};
|
||||
|
||||
struct process_module {
|
||||
void *module_base;
|
||||
size_t module_size;
|
||||
wchar_t module_path[MAX_MODULE_PATH];
|
||||
};
|
||||
|
||||
struct apc_operation_init {
|
||||
int operation_id;
|
||||
};
|
||||
|
||||
HANDLE driver_handle;
|
||||
LPCWSTR driver_name;
|
||||
client::message_queue &message_queue;
|
||||
HANDLE port;
|
||||
std::mutex lock;
|
||||
std::vector<event_dispatcher> events;
|
||||
|
||||
void initiate_completion_port();
|
||||
void terminate_completion_port();
|
||||
event_dispatcher *get_free_event_entry();
|
||||
void release_event_object(OVERLAPPED *event);
|
||||
void *get_buffer_from_event_object(OVERLAPPED *event);
|
||||
|
||||
void notify_driver_on_process_launch();
|
||||
void notify_driver_on_process_termination();
|
||||
void generic_driver_call(ioctl_code ioctl);
|
||||
unsigned int generic_driver_call_output(ioctl_code ioctl, void *output_buffer,
|
||||
size_t buffer_size,
|
||||
unsigned long *bytes_returned);
|
||||
void generic_driver_call_input(ioctl_code ioctl, void *input_buffer,
|
||||
size_t buffer_size,
|
||||
unsigned long *bytes_returned);
|
||||
void generic_driver_call_apc(apc_operation operation);
|
||||
|
||||
public:
|
||||
kernel_interface(LPCWSTR driver_name, client::message_queue &queue);
|
||||
~kernel_interface();
|
||||
|
||||
void run_completion_port();
|
||||
void run_nmi_callbacks();
|
||||
void validate_system_driver_objects();
|
||||
void detect_system_virtualization();
|
||||
void enumerate_handle_tables();
|
||||
void scan_for_unlinked_processes();
|
||||
void perform_integrity_check();
|
||||
void scan_for_attached_threads();
|
||||
void scan_for_ept_hooks();
|
||||
void perform_dpc_stackwalk();
|
||||
void validate_system_modules();
|
||||
void verify_process_module_executable_regions();
|
||||
void initiate_apc_stackwalk();
|
||||
void send_pending_irp();
|
||||
void query_deferred_reports();
|
||||
};
|
||||
} // namespace kernel_interface
|
33
module/main.cpp
Normal file
33
module/main.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <Windows.h>
|
||||
|
||||
#include "module.h"
|
||||
|
||||
DWORD WINAPI Init(HINSTANCE hinstDLL) { module::run(hinstDLL); }
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
const auto thread =
|
||||
CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
|
||||
hModule, 0, nullptr);
|
||||
|
||||
if (thread)
|
||||
CloseHandle(thread);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
{
|
||||
LOG_INFO("process closing!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
31
module/module.cpp
Normal file
31
module/module.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "module.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "client/message_queue.h"
|
||||
#include "dispatcher/dispatcher.h"
|
||||
|
||||
void module::run(HINSTANCE hinstDLL) {
|
||||
AllocConsole();
|
||||
FILE *file;
|
||||
freopen_s(&file, "CONOUT$", "w", stdout);
|
||||
freopen_s(&file, "CONIN$", "r", stdin);
|
||||
|
||||
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
|
||||
LPCWSTR driver_name = L"\\\\.\\DonnaAC";
|
||||
|
||||
client::message_queue queue(pipe_name);
|
||||
dispatcher::dispatcher dispatch(driver_name, queue);
|
||||
dispatch.run();
|
||||
|
||||
fclose(stdout);
|
||||
fclose(stdin);
|
||||
FreeConsole();
|
||||
|
||||
FreeLibraryAndExitThread(hinstDLL, 0);
|
||||
}
|
||||
|
||||
void module::terminate()
|
||||
{
|
||||
|
||||
}
|
10
module/module.h
Normal file
10
module/module.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace module {
|
||||
void run(HINSTANCE hinstDLL);
|
||||
void terminate();
|
||||
} // namespace module
|
167
module/module.vcxproj
Normal file
167
module/module.vcxproj
Normal file
|
@ -0,0 +1,167 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{3b18467a-4358-45ef-81b1-5c6f9b0b6728}</ProjectGuid>
|
||||
<RootNamespace>module</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;MODULE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="helper.cpp" />
|
||||
<ClCompile Include="imports.cpp" />
|
||||
<ClCompile Include="module.cpp" />
|
||||
<ClCompile Include="client\message_queue.cpp" />
|
||||
<ClCompile Include="client\pipe.cpp" />
|
||||
<ClCompile Include="dispatcher\dispatcher.cpp" />
|
||||
<ClCompile Include="dispatcher\threadpool.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="kernel_interface\kernel_interface.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="client\message_queue.h" />
|
||||
<ClInclude Include="client\pipe.h" />
|
||||
<ClInclude Include="dispatcher\dispatcher.h" />
|
||||
<ClInclude Include="dispatcher\threadpool.h" />
|
||||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="helper.h" />
|
||||
<ClInclude Include="imports.h" />
|
||||
<ClInclude Include="kernel_interface\kernel_interface.h" />
|
||||
<ClInclude Include="module.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -18,28 +18,28 @@
|
|||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="um\umanager.cpp">
|
||||
<ClCompile Include="kernel_interface\kernel_interface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="km\kmanager.cpp">
|
||||
<ClCompile Include="dispatcher\dispatcher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="um\process.cpp">
|
||||
<ClCompile Include="dispatcher\threadpool.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="threadpool.cpp">
|
||||
<ClCompile Include="client\message_queue.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="um\imports.cpp">
|
||||
<ClCompile Include="client\pipe.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="km\driver.cpp">
|
||||
<ClCompile Include="module.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="client.cpp">
|
||||
<ClCompile Include="helper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pipe.cpp">
|
||||
<ClCompile Include="imports.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -47,28 +47,28 @@
|
|||
<ClInclude Include="common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="um\umanager.h">
|
||||
<ClInclude Include="kernel_interface\kernel_interface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="km\kmanager.h">
|
||||
<ClInclude Include="dispatcher\dispatcher.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="um\process.h">
|
||||
<ClInclude Include="dispatcher\threadpool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="threadpool.h">
|
||||
<ClInclude Include="client\message_queue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="um\imports.h">
|
||||
<ClInclude Include="client\pipe.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="km\driver.h">
|
||||
<ClInclude Include="module.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="client.h">
|
||||
<ClInclude Include="helper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pipe.h">
|
||||
<ClInclude Include="imports.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
|
@ -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;
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
#include "patch.hpp"
|
||||
|
||||
namespace framework {
|
||||
patch::patch(char* image_name)
|
||||
{
|
||||
}
|
||||
patch::patch(char *image_name) {}
|
||||
|
||||
patch::~patch()
|
||||
{
|
||||
}
|
||||
}
|
||||
patch::~patch() {}
|
||||
} // namespace framework
|
|
@ -1,83 +0,0 @@
|
|||
#include "client.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define TEST_STEAM_64_ID 123456789;
|
||||
|
||||
global::Client::Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName)
|
||||
{
|
||||
this->thread_pool = ThreadPool;
|
||||
#if NO_SERVER
|
||||
LOG_INFO("No_Server build used. Not opening named pipe.");
|
||||
#else
|
||||
this->pipe = std::make_shared<global::Pipe>(PipeName);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Request an item from the server
|
||||
*/
|
||||
void
|
||||
global::Client::ServerReceive(PVOID Buffer, SIZE_T Size)
|
||||
{
|
||||
this->pipe->ReadPipe(Buffer, Size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send an item to the server
|
||||
*/
|
||||
void
|
||||
global::Client::ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId)
|
||||
{
|
||||
#if NO_SERVER
|
||||
return;
|
||||
#else
|
||||
mutex.lock();
|
||||
|
||||
SIZE_T total_header_size = sizeof(global::headers::CLIENT_SEND_PACKET_HEADER) +
|
||||
sizeof(global::headers::PIPE_PACKET_HEADER);
|
||||
|
||||
if (Size + total_header_size > MAX_CLIENT_SEND_PACKET_SIZE)
|
||||
{
|
||||
LOG_ERROR("Packet is too large to send");
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
PVOID send_buffer = malloc(total_header_size + Size);
|
||||
|
||||
if (send_buffer == nullptr)
|
||||
{
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
RtlZeroMemory(send_buffer, total_header_size + Size);
|
||||
|
||||
global::headers::PIPE_PACKET_HEADER header = {0};
|
||||
header.message_type = MESSAGE_TYPE_CLIENT_SEND;
|
||||
header.steam64_id = TEST_STEAM_64_ID;
|
||||
|
||||
memcpy(send_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
|
||||
|
||||
global::headers::CLIENT_SEND_PACKET_HEADER header_extension = {0};
|
||||
header_extension.request_id = RequestId;
|
||||
header_extension.packet_size = Size + total_header_size;
|
||||
|
||||
memcpy(PVOID((UINT64)send_buffer + sizeof(global::headers::PIPE_PACKET_HEADER)),
|
||||
&header_extension,
|
||||
sizeof(global::headers::CLIENT_SEND_PACKET_HEADER));
|
||||
|
||||
memcpy(PVOID((UINT64)send_buffer + total_header_size), Buffer, Size);
|
||||
|
||||
LOG_INFO("Writing to pipe");
|
||||
|
||||
this->pipe->WriteToPipe(send_buffer, header_extension.packet_size);
|
||||
|
||||
mutex.unlock();
|
||||
free(send_buffer);
|
||||
#endif
|
||||
|
||||
}
|
237
user/client.h
237
user/client.h
|
@ -1,237 +0,0 @@
|
|||
#ifndef REPORT_H
|
||||
#define REPORT_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "threadpool.h"
|
||||
#include "pipe.h"
|
||||
#include <TlHelp32.h>
|
||||
#include "common.h"
|
||||
|
||||
#define REPORT_BUFFER_SIZE 8192
|
||||
#define SEND_BUFFER_SIZE 8192
|
||||
|
||||
#define MAX_SIGNATURE_SIZE 256
|
||||
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
|
||||
|
||||
#define REPORT_CODE_PROCESS_MODULE_VERIFICATION 10
|
||||
#define REPORT_CODE_START_ADDRESS_VERIFICATION 20
|
||||
#define REPORT_PAGE_PROTECTION_VERIFICATION 30
|
||||
#define REPORT_PATTERN_SCAN_FAILURE 40
|
||||
#define REPORT_NMI_CALLBACK_FAILURE 50
|
||||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
#define REPORT_APC_STACKWALK 110
|
||||
#define REPORT_DPC_STACKWALK 120
|
||||
#define REPORT_DATA_TABLE_ROUTINE 130
|
||||
|
||||
#define TEST_STEAM_64_ID 123456789;
|
||||
|
||||
enum REPORT_CODES
|
||||
{
|
||||
USERMODE_MODULE = 10,
|
||||
START_ADDRESS = 20,
|
||||
PAGE_PROTECTION = 30,
|
||||
PATTERN_SCAN = 40,
|
||||
NMI_CALLBACK = 50,
|
||||
SYSTEM_MODULE = 60,
|
||||
HANDLE_OPERATION = 70
|
||||
};
|
||||
|
||||
#define CLIENT_REQUEST_MODULE_INTEGRITY_CHECK 10
|
||||
|
||||
#define CLIENT_SEND_SYSTEM_INFORMATION 10
|
||||
|
||||
#define MAX_CLIENT_SEND_PACKET_SIZE 60000
|
||||
|
||||
enum SERVER_SEND_CODES
|
||||
{
|
||||
MODULE_INTEGRITY_CHECK = 10
|
||||
};
|
||||
|
||||
namespace global {
|
||||
class Client
|
||||
{
|
||||
std::shared_ptr<global::ThreadPool> thread_pool;
|
||||
std::shared_ptr<global::Pipe> pipe;
|
||||
std::mutex mutex;
|
||||
|
||||
byte report_buffer[REPORT_BUFFER_SIZE];
|
||||
|
||||
public:
|
||||
Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName);
|
||||
|
||||
void UpdateSystemInformation(global::headers::SYSTEM_INFORMATION* SystemInformation);
|
||||
|
||||
/* lock buffer, attach header, copy report, send to service then clear buffer */
|
||||
template <typename T>
|
||||
void ReportViolation(T* Report)
|
||||
{
|
||||
#if NO_SERVER
|
||||
return;
|
||||
#else
|
||||
mutex.lock();
|
||||
|
||||
global::headers::PIPE_PACKET_HEADER header = {0};
|
||||
header.message_type = MESSAGE_TYPE_CLIENT_REPORT;
|
||||
header.steam64_id = TEST_STEAM_64_ID;
|
||||
memcpy(&this->report_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
|
||||
|
||||
memcpy(PVOID((UINT64)this->report_buffer +
|
||||
sizeof(global::headers::PIPE_PACKET_HEADER)),
|
||||
Report,
|
||||
sizeof(T));
|
||||
this->pipe->WriteToPipe(this->report_buffer,
|
||||
sizeof(T) + sizeof(global::headers::PIPE_PACKET_HEADER));
|
||||
RtlZeroMemory(this->report_buffer, REPORT_BUFFER_SIZE);
|
||||
|
||||
mutex.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ServerReceive(PVOID Buffer, SIZE_T Size);
|
||||
void ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId);
|
||||
};
|
||||
|
||||
namespace report_structures {
|
||||
struct PROCESS_MODULES_INTEGRITY_CHECK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 module_base_address;
|
||||
UINT64 module_size;
|
||||
CHAR module_name[256];
|
||||
};
|
||||
|
||||
struct PROCESS_THREAD_START_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
LONG thread_id;
|
||||
UINT64 start_address;
|
||||
};
|
||||
|
||||
struct PAGE_PROTECTION_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 page_base_address;
|
||||
LONG allocation_protection;
|
||||
LONG allocation_state;
|
||||
LONG allocation_type;
|
||||
};
|
||||
|
||||
struct PATTERN_SCAN_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT signature_id;
|
||||
UINT64 address;
|
||||
};
|
||||
|
||||
struct NMI_CALLBACK_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT were_nmis_disabled;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
};
|
||||
|
||||
struct MODULE_VALIDATION_FAILURE_HEADER
|
||||
{
|
||||
INT module_count;
|
||||
};
|
||||
|
||||
struct MODULE_VALIDATION_FAILURE
|
||||
{
|
||||
INT report_code;
|
||||
INT report_type;
|
||||
UINT64 driver_base_address;
|
||||
UINT64 driver_size;
|
||||
CHAR driver_name[128];
|
||||
};
|
||||
|
||||
struct REPORT_QUEUE_HEADER
|
||||
{
|
||||
INT count;
|
||||
};
|
||||
|
||||
struct OPEN_HANDLE_FAILURE_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT is_kernel_handle;
|
||||
LONG process_id;
|
||||
LONG thread_id;
|
||||
LONG desired_access;
|
||||
CHAR process_name[64];
|
||||
};
|
||||
|
||||
struct INVALID_PROCESS_ALLOCATION_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
CHAR process[4096];
|
||||
};
|
||||
|
||||
/*
|
||||
* No point copying data from the start address here
|
||||
* since people can easily change it.
|
||||
*/
|
||||
struct HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[4096];
|
||||
};
|
||||
|
||||
struct ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT32 thread_id;
|
||||
UINT64 thread_address;
|
||||
};
|
||||
|
||||
struct SYSTEM_INFORMATION_REQUEST_RESPONSE
|
||||
{
|
||||
INT RequestId;
|
||||
INT CanUserProceed;
|
||||
INT reason;
|
||||
};
|
||||
|
||||
struct APC_STACKWALK_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[4096];
|
||||
};
|
||||
|
||||
struct DPC_STACKWALK_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
UINT64 kthread_address;
|
||||
UINT64 invalid_rip;
|
||||
CHAR driver[4096];
|
||||
};
|
||||
|
||||
enum TABLE_ID
|
||||
{
|
||||
HalDispatch = 0,
|
||||
HalPrivateDispatch
|
||||
};
|
||||
|
||||
#define DATA_TABLE_ROUTINE_BUF_SIZE 256
|
||||
|
||||
struct DATA_TABLE_ROUTINE_REPORT
|
||||
{
|
||||
UINT32 report_code;
|
||||
TABLE_ID id;
|
||||
UINT64 address;
|
||||
CHAR routine[DATA_TABLE_ROUTINE_BUF_SIZE];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,671 +0,0 @@
|
|||
#include "driver.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../common.h"
|
||||
#include <winternl.h>
|
||||
|
||||
typedef BOOLEAN(NTAPI* RtlDosPathNameToNtPathName_U)(PCWSTR DosPathName,
|
||||
PUNICODE_STRING NtPathName,
|
||||
PCWSTR* NtFileNamePart,
|
||||
PVOID DirectoryInfo);
|
||||
|
||||
using namespace global::report_structures;
|
||||
|
||||
kernelmode::Driver::Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface)
|
||||
{
|
||||
this->driver_name = DriverName;
|
||||
this->report_interface = ReportInterface;
|
||||
this->driver_handle = CreateFileW(DriverName,
|
||||
GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE,
|
||||
0,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
0);
|
||||
|
||||
if (this->driver_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("Failed to open handle to driver with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
this->NotifyDriverOnProcessLaunch();
|
||||
}
|
||||
|
||||
kernelmode::Driver::~Driver()
|
||||
{
|
||||
this->NotifyDriverOnProcessTermination();
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::RunNmiCallbacks()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
NMI_CALLBACK_FAILURE report = {0};
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_RUN_NMI_CALLBACKS,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof(NMI_CALLBACK_FAILURE),
|
||||
&bytes_returned,
|
||||
(LPOVERLAPPED)NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_returned == NULL)
|
||||
{
|
||||
LOG_INFO("All threads valid, nmis fine.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* else, report */
|
||||
this->report_interface->ReportViolation(&report);
|
||||
}
|
||||
|
||||
/*
|
||||
* 1. Checks that every device object has a system module to back it
|
||||
* 2. Checks the IOCTL dispatch routines to ensure they lie within the module
|
||||
*/
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::VerifySystemModuleDriverObjects()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
PVOID buffer = NULL;
|
||||
SIZE_T buffer_size = 0;
|
||||
SIZE_T header_size = 0;
|
||||
|
||||
/*
|
||||
* allocate enough to report 5 invalid driver objects + header. The reason we use a raw
|
||||
* pointer here is so we can pass the address to DeviceIoControl. You are not able (atleast
|
||||
* as far as im concerned) to pass a shared ptr to DeviceIoControl.
|
||||
*/
|
||||
header_size = sizeof(MODULE_VALIDATION_FAILURE_HEADER);
|
||||
|
||||
buffer_size =
|
||||
sizeof(MODULE_VALIDATION_FAILURE) * MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT +
|
||||
header_size;
|
||||
|
||||
buffer = malloc(buffer_size);
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_VALIDATE_DRIVER_OBJECTS,
|
||||
NULL,
|
||||
NULL,
|
||||
buffer,
|
||||
buffer_size,
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_returned == NULL)
|
||||
{
|
||||
LOG_INFO("All modules valid :)");
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are splitting up each packet here and passing them on one by one since
|
||||
* if I am being honest it is just easier in c++ and that way the process
|
||||
* is streamlined just like all other report packets.
|
||||
*/
|
||||
MODULE_VALIDATION_FAILURE_HEADER* header = (MODULE_VALIDATION_FAILURE_HEADER*)buffer;
|
||||
|
||||
LOG_INFO("Module count: %lx", header->module_count);
|
||||
|
||||
for (int i = 0; i < header->module_count; i++)
|
||||
{
|
||||
MODULE_VALIDATION_FAILURE* report =
|
||||
(MODULE_VALIDATION_FAILURE*)((UINT64)buffer +
|
||||
sizeof(MODULE_VALIDATION_FAILURE_HEADER) +
|
||||
i * sizeof(MODULE_VALIDATION_FAILURE));
|
||||
|
||||
this->report_interface->ReportViolation(report);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* HOW THIS WILL WORK:
|
||||
*
|
||||
* 1. On driver initiation, ObRegisterCallbacks will be registered
|
||||
* 2. Each time a process that is not whitelisted tries to open a handle
|
||||
* to our game we will store the report in an a report queue
|
||||
* 3. the user mode app will then periodically query the driver asking
|
||||
* how many pending reports there are
|
||||
* 4. once the number is received, the app will allocate a buffer large enough
|
||||
* for all the reports and once again call CompleteQueuedCallbackReports
|
||||
* 5. This will then retrieve the reports into the buffer and from there
|
||||
* we can iteratively report them the same way as we do with the system
|
||||
* modules.
|
||||
*/
|
||||
|
||||
struct REPORT_ID
|
||||
{
|
||||
INT report_id;
|
||||
};
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::QueryReportQueue()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
PVOID buffer = NULL;
|
||||
LONG buffer_size = 0;
|
||||
REPORT_ID* report_header = NULL;
|
||||
SIZE_T total_size = NULL;
|
||||
OPEN_HANDLE_FAILURE_REPORT handle_report = {0};
|
||||
ATTACH_PROCESS_REPORT attach_report = {0};
|
||||
INVALID_PROCESS_ALLOCATION_REPORT allocation_report = {0};
|
||||
APC_STACKWALK_REPORT apc_report = {0};
|
||||
HIDDEN_SYSTEM_THREAD_REPORT hidden_report = {0};
|
||||
|
||||
/* allocate enough for the largest report buffer * max reports */
|
||||
buffer_size =
|
||||
sizeof(APC_STACKWALK_REPORT) * MAX_REPORTS_PER_IRP + sizeof(REPORT_QUEUE_HEADER);
|
||||
|
||||
/* this isnt very c++ of us... */
|
||||
buffer = malloc(buffer_size);
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE,
|
||||
NULL,
|
||||
NULL,
|
||||
buffer,
|
||||
buffer_size,
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed with status code 0x%x", GetLastError());
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
REPORT_QUEUE_HEADER* header = (REPORT_QUEUE_HEADER*)buffer;
|
||||
|
||||
if (!header || !header->count)
|
||||
goto end;
|
||||
|
||||
for (INT index = 0; index < header->count; index++)
|
||||
{
|
||||
report_header =
|
||||
(REPORT_ID*)((UINT64)buffer + sizeof(REPORT_QUEUE_HEADER) + total_size);
|
||||
|
||||
LOG_INFO("Report id: %d", report_header->report_id);
|
||||
|
||||
switch (report_header->report_id)
|
||||
{
|
||||
case REPORT_ILLEGAL_ATTACH_PROCESS:
|
||||
ReportTypeFromReportQueue<ATTACH_PROCESS_REPORT>(
|
||||
buffer, &total_size, &attach_report);
|
||||
break;
|
||||
case REPORT_ILLEGAL_HANDLE_OPERATION:
|
||||
ReportTypeFromReportQueue<OPEN_HANDLE_FAILURE_REPORT>(
|
||||
buffer, &total_size, &handle_report);
|
||||
break;
|
||||
case REPORT_INVALID_PROCESS_ALLOCATION:
|
||||
ReportTypeFromReportQueue<INVALID_PROCESS_ALLOCATION_REPORT>(
|
||||
buffer, &total_size, &allocation_report);
|
||||
break;
|
||||
case REPORT_APC_STACKWALK:
|
||||
ReportTypeFromReportQueue<APC_STACKWALK_REPORT>(
|
||||
buffer, &total_size, &apc_report);
|
||||
break;
|
||||
case REPORT_HIDDEN_SYSTEM_THREAD:
|
||||
ReportTypeFromReportQueue<HIDDEN_SYSTEM_THREAD_REPORT>(
|
||||
buffer, &total_size, &hidden_report);
|
||||
break;
|
||||
case REPORT_DPC_STACKWALK:
|
||||
ReportTypeFromReportQueue<DPC_STACKWALK_REPORT>(
|
||||
buffer, &total_size, &hidden_report);
|
||||
break;
|
||||
case REPORT_DATA_TABLE_ROUTINE:
|
||||
ReportTypeFromReportQueue<DATA_TABLE_ROUTINE_REPORT>(
|
||||
buffer, &total_size, &hidden_report);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::RunCallbackReportQueue()
|
||||
{
|
||||
/*TODO have some volatile flag instead */
|
||||
this->QueryReportQueue();
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::NotifyDriverOnProcessLaunch()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
kernelmode::DRIVER_INITIATION_INFORMATION information = {0};
|
||||
information.protected_process_id = GetCurrentProcessId();
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH,
|
||||
&information,
|
||||
sizeof(kernelmode::DRIVER_INITIATION_INFORMATION),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("Failed to notify driver on process launch 0x%x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::DetectSystemVirtualization()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
HYPERVISOR_DETECTION_REPORT report = {0};
|
||||
DWORD bytes_returned = 0;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_PERFORM_VIRTUALIZATION_CHECK,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof(HYPERVISOR_DETECTION_REPORT),
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed virtualization detect with status %x",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (report.aperf_msr_timing_check == TRUE || report.invd_emulation_check == TRUE)
|
||||
LOG_INFO("HYPERVISOR DETECTED!!!");
|
||||
|
||||
/* shutdown the application or smth lmao */
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::CheckHandleTableEntries()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = {0};
|
||||
|
||||
/*
|
||||
* Only pass the IOCTL code and nothing else since the reports are bundled
|
||||
* with the handle ObRegisterCallbacks report queue hence the QueryReportQueue
|
||||
* function will handle these reports.
|
||||
*/
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_ENUMERATE_HANDLE_TABLES,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("CheckHandleTableEntries failed with status %x", status);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::RequestModuleExecutableRegions()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
ULONG module_size = 0;
|
||||
PVOID buffer = NULL;
|
||||
|
||||
module_size = this->RequestTotalModuleSize();
|
||||
|
||||
if (module_size == NULL)
|
||||
{
|
||||
LOG_ERROR("RequestTotalModuleSize failed lolz");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("module size: %lx", module_size);
|
||||
|
||||
/*
|
||||
* allocate a buffer big enough for the entire module not including section headers or
|
||||
* packet headers, however it should be big enough since executable sections do not
|
||||
* make up 100% of the image size. Bit hacky but it works.
|
||||
*/
|
||||
buffer = malloc(module_size);
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS,
|
||||
NULL,
|
||||
NULL,
|
||||
buffer,
|
||||
module_size,
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("failed to retrieve module executable regions lozl %x", GetLastError());
|
||||
goto end;
|
||||
}
|
||||
|
||||
LOG_INFO("bytes returned: %lx", bytes_returned);
|
||||
|
||||
this->report_interface->ServerSend(
|
||||
buffer, bytes_returned, CLIENT_REQUEST_MODULE_INTEGRITY_CHECK);
|
||||
|
||||
end:
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::ScanForUnlinkedProcess()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
INVALID_PROCESS_ALLOCATION_REPORT report = {0};
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_SCAN_FOR_UNLINKED_PROCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof(report),
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("failed to scan for unlinked processes %x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::PerformIntegrityCheck()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_PERFORM_INTEGRITY_CHECK, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("Failed to perform integrity check with status %x", status);
|
||||
}
|
||||
|
||||
ULONG
|
||||
kernelmode::Driver::RequestTotalModuleSize()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
DWORD bytes_returned = 0;
|
||||
ULONG module_size = 0;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_REQUEST_TOTAL_MODULE_SIZE,
|
||||
NULL,
|
||||
NULL,
|
||||
&module_size,
|
||||
sizeof(ULONG),
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("CheckHandleTableEntries failed with status %x", status);
|
||||
|
||||
return module_size;
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::NotifyDriverOnProcessTermination()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("NotifyDriverOnProcessTermination failed with status %x", status);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::CheckForAttachedThreads()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_DETECT_ATTACHED_THREADS, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("failed to check for attached threads %x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::CheckForEptHooks()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_CHECK_FOR_EPT_HOOK, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("failed to check for ept hooks %x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::StackwalkThreadsViaDpc()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_LAUNCH_DPC_STACKWALK, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("failed to stackwalk threads via dpc %x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::ValidateSystemModules()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_VALIDATE_SYSTEM_MODULES, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("failed to validate system modules %x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::CheckDriverHeartbeat()
|
||||
{
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::VerifyProcessLoadedModuleExecutableRegions()
|
||||
{
|
||||
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
|
||||
MODULEENTRY32 module_entry = {0};
|
||||
BOOLEAN status = FALSE;
|
||||
PROCESS_MODULE_INFORMATION module_information = {0};
|
||||
PROCESS_MODULE_VALIDATION_RESULT validation_result = {0};
|
||||
DWORD bytes_returned = 0;
|
||||
RtlDosPathNameToNtPathName_U pRtlDosPathNameToNtPathName_U = NULL;
|
||||
UNICODE_STRING nt_path_name = {0};
|
||||
|
||||
pRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_U)GetProcAddress(
|
||||
GetModuleHandle(L"ntdll.dll"), "RtlDosPathNameToNtPathName_U");
|
||||
|
||||
process_modules_handle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
|
||||
GetCurrentProcessId());
|
||||
|
||||
if (process_modules_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
module_entry.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
if (!Module32First(process_modules_handle, &module_entry))
|
||||
{
|
||||
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
module_information.module_base = module_entry.modBaseAddr;
|
||||
module_information.module_size = module_entry.modBaseSize;
|
||||
|
||||
status = (*pRtlDosPathNameToNtPathName_U)(
|
||||
module_entry.szExePath, &nt_path_name, NULL, NULL);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
LOG_ERROR("RtlDosPathNameToNtPathName_U failed with no status.");
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(module_information.module_path, nt_path_name.Buffer, MAX_MODULE_PATH);
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_VALIDATE_PROCESS_LOADED_MODULE,
|
||||
&module_information,
|
||||
sizeof(module_information),
|
||||
&validation_result,
|
||||
sizeof(validation_result),
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL || bytes_returned == NULL)
|
||||
{
|
||||
LOG_ERROR("failed to validate process module with status %x",
|
||||
GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (validation_result.is_module_valid == FALSE)
|
||||
{
|
||||
/*TODO: copy module aswell from an anomaly offset */
|
||||
PROCESS_MODULES_INTEGRITY_CHECK_FAILURE report;
|
||||
report.report_code = REPORT_CODE_PROCESS_MODULE_VERIFICATION;
|
||||
report.module_base_address = (UINT64)module_entry.modBaseAddr;
|
||||
report.module_size = module_entry.modBaseSize;
|
||||
std::wstring wstr(module_entry.szModule);
|
||||
std::string module_name_string = std::string(wstr.begin(), wstr.end());
|
||||
memcpy(
|
||||
&report.module_name, &module_name_string, module_name_string.length());
|
||||
this->report_interface->ReportViolation(&report);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO("Module %S is valid", module_entry.szModule);
|
||||
}
|
||||
|
||||
} while (Module32Next(process_modules_handle, &module_entry));
|
||||
|
||||
end:
|
||||
CloseHandle(process_modules_handle);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::SendClientHardwareInformation()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
global::headers::SYSTEM_INFORMATION system_information = {0};
|
||||
DWORD bytes_returned = 0;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_REQUEST_HARDWARE_INFORMATION,
|
||||
NULL,
|
||||
NULL,
|
||||
&system_information,
|
||||
sizeof(global::headers::SYSTEM_INFORMATION),
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
|
||||
if (status == NULL || bytes_returned == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
this->report_interface->ServerSend(&system_information,
|
||||
sizeof(global::headers::SYSTEM_INFORMATION),
|
||||
CLIENT_SEND_SYSTEM_INFORMATION);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
kernelmode::Driver::InitiateApcOperation(INT OperationId)
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
APC_OPERATION_INFORMATION operation = {0};
|
||||
|
||||
operation.operation_id = OperationId;
|
||||
|
||||
status = DeviceIoControl(this->driver_handle,
|
||||
IOCTL_INITIATE_APC_OPERATION,
|
||||
&operation,
|
||||
sizeof(APC_OPERATION_INFORMATION),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("DeviceIoControl failed with status %x", GetLastError());
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::Driver::SendIrpForDriverToStore()
|
||||
{
|
||||
BOOLEAN status = FALSE;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle, IOCTL_INSERT_IRP_INTO_QUEUE, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
LOG_ERROR("failed to insert irp into irp queue %x", GetLastError());
|
||||
}
|
||||
|
||||
VOID
|
||||
GetKernelStructureOffsets()
|
||||
{
|
||||
}
|
133
user/km/driver.h
133
user/km/driver.h
|
@ -1,133 +0,0 @@
|
|||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../threadpool.h"
|
||||
#include "../client.h"
|
||||
|
||||
#define IOCTL_RUN_NMI_CALLBACKS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_DRIVER_OBJECTS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_ENUMERATE_HANDLE_TABLES \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_INTEGRITY_CHECK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_DETECT_ATTACHED_THREADS \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_REQUEST_HARDWARE_INFORMATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_INITIATE_APC_OPERATION \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_CHECK_FOR_EPT_HOOK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_LAUNCH_DPC_STACKWALK \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_SYSTEM_MODULES \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_INSERT_IRP_INTO_QUEUE \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20021, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define MAX_REPORTS_PER_IRP 20
|
||||
|
||||
#define MAX_MODULE_PATH 256
|
||||
|
||||
namespace kernelmode {
|
||||
enum APC_OPERATION_IDS
|
||||
{
|
||||
operation_stackwalk = 0x1
|
||||
};
|
||||
|
||||
class Driver
|
||||
{
|
||||
HANDLE driver_handle;
|
||||
LPCWSTR driver_name;
|
||||
std::shared_ptr<global::Client> report_interface;
|
||||
|
||||
ULONG RequestTotalModuleSize();
|
||||
VOID NotifyDriverOnProcessLaunch();
|
||||
VOID CheckDriverHeartbeat();
|
||||
VOID NotifyDriverOnProcessTermination();
|
||||
// VOID GetKernelStructureOffsets();
|
||||
|
||||
template <typename T>
|
||||
VOID ReportTypeFromReportQueue(CONST PVOID Buffer, PSIZE_T Offset, PVOID Report)
|
||||
{
|
||||
Report = (T*)((UINT64)Buffer +
|
||||
sizeof(global::report_structures::REPORT_QUEUE_HEADER) + *Offset);
|
||||
|
||||
this->report_interface->ReportViolation((T*)Report);
|
||||
|
||||
*Offset += sizeof(T);
|
||||
}
|
||||
|
||||
public:
|
||||
Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface);
|
||||
~Driver();
|
||||
|
||||
VOID RunNmiCallbacks();
|
||||
VOID VerifySystemModuleDriverObjects();
|
||||
VOID RunCallbackReportQueue();
|
||||
VOID DetectSystemVirtualization();
|
||||
VOID QueryReportQueue();
|
||||
VOID CheckHandleTableEntries();
|
||||
VOID RequestModuleExecutableRegions();
|
||||
VOID ScanForUnlinkedProcess();
|
||||
VOID PerformIntegrityCheck();
|
||||
VOID CheckForAttachedThreads();
|
||||
VOID VerifyProcessLoadedModuleExecutableRegions();
|
||||
VOID SendClientHardwareInformation();
|
||||
VOID CheckForEptHooks();
|
||||
VOID StackwalkThreadsViaDpc();
|
||||
VOID ValidateSystemModules();
|
||||
BOOLEAN InitiateApcOperation(INT OperationId);
|
||||
VOID SendIrpForDriverToStore();
|
||||
};
|
||||
|
||||
struct DRIVER_INITIATION_INFORMATION
|
||||
{
|
||||
ULONG protected_process_id;
|
||||
};
|
||||
|
||||
struct HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
};
|
||||
|
||||
struct PROCESS_MODULE_INFORMATION
|
||||
{
|
||||
PVOID module_base;
|
||||
SIZE_T module_size;
|
||||
WCHAR module_path[MAX_MODULE_PATH];
|
||||
};
|
||||
|
||||
struct PROCESS_MODULE_VALIDATION_RESULT
|
||||
{
|
||||
INT is_module_valid;
|
||||
};
|
||||
|
||||
struct APC_OPERATION_INFORMATION
|
||||
{
|
||||
int operation_id;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,118 +0,0 @@
|
|||
#include "kmanager.h"
|
||||
|
||||
kernelmode::KManager::KManager(LPCWSTR DriverName,
|
||||
std::shared_ptr<global::ThreadPool> ThreadPool,
|
||||
std::shared_ptr<global::Client> ReportInterface)
|
||||
{
|
||||
this->driver_interface = std::make_unique<Driver>(DriverName, ReportInterface);
|
||||
this->thread_pool = ThreadPool;
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::RunNmiCallbacks()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->RunNmiCallbacks(); });
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::VerifySystemModuleDriverObjects()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->VerifySystemModuleDriverObjects(); });
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::MonitorCallbackReports()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->QueryReportQueue(); });
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::DetectSystemVirtualization()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->DetectSystemVirtualization(); });
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::EnumerateHandleTables()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->CheckHandleTableEntries(); });
|
||||
}
|
||||
|
||||
void
|
||||
kernelmode::KManager::RequestModuleExecutableRegionsForIntegrityCheck()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->RequestModuleExecutableRegions(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::ScanPoolsForUnlinkedProcesses()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->ScanForUnlinkedProcess(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::PerformIntegrityCheck()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->PerformIntegrityCheck(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::CheckForAttachedThreads()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->CheckForAttachedThreads(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::ValidateProcessModules()
|
||||
{
|
||||
this->thread_pool->QueueJob(
|
||||
[this]() { this->driver_interface->VerifyProcessLoadedModuleExecutableRegions(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::SendClientHardwareInformation()
|
||||
{
|
||||
this->driver_interface->SendClientHardwareInformation();
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::InitiateApcStackwalkOperation()
|
||||
{
|
||||
this->driver_interface->InitiateApcOperation(
|
||||
kernelmode::APC_OPERATION_IDS::operation_stackwalk);
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::CheckForEptHooks()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForEptHooks(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::StackwalkThreadsViaDpc()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->StackwalkThreadsViaDpc(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::ValidateSystemModules()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->ValidateSystemModules(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::InsertIrpIntoIrpQueue()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->driver_interface->SendIrpForDriverToStore(); });
|
||||
}
|
||||
|
||||
VOID
|
||||
kernelmode::KManager::StartIoCompletionPortThread()
|
||||
{
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
#ifndef KMANAGER_H
|
||||
#define KMANAGER_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "..\client.h"
|
||||
#include "..\threadpool.h"
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
namespace kernelmode {
|
||||
class KManager
|
||||
{
|
||||
std::unique_ptr<Driver> driver_interface;
|
||||
std::shared_ptr<global::ThreadPool> thread_pool;
|
||||
|
||||
VOID StartIoCompletionPortThread();
|
||||
|
||||
public:
|
||||
KManager(LPCWSTR DriverName,
|
||||
std::shared_ptr<global::ThreadPool> ThreadPool,
|
||||
std::shared_ptr<global::Client> ReportInterface);
|
||||
|
||||
VOID RunNmiCallbacks();
|
||||
VOID VerifySystemModuleDriverObjects();
|
||||
VOID MonitorCallbackReports();
|
||||
VOID DetectSystemVirtualization();
|
||||
VOID EnumerateHandleTables();
|
||||
VOID RequestModuleExecutableRegionsForIntegrityCheck();
|
||||
VOID ScanPoolsForUnlinkedProcesses();
|
||||
VOID PerformIntegrityCheck();
|
||||
VOID CheckForAttachedThreads();
|
||||
VOID ValidateProcessModules();
|
||||
VOID SendClientHardwareInformation();
|
||||
VOID InitiateApcStackwalkOperation();
|
||||
VOID CheckForEptHooks();
|
||||
VOID StackwalkThreadsViaDpc();
|
||||
VOID ValidateSystemModules();
|
||||
VOID InsertIrpIntoIrpQueue();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
137
user/main.cpp
137
user/main.cpp
|
@ -1,137 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <WDBGEXTS.H>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "threadpool.h"
|
||||
#include "client.h"
|
||||
|
||||
#include "../user/um/umanager.h"
|
||||
#include "../user/km/kmanager.h"
|
||||
|
||||
// BOOLEAN IsTestSigningModeEnabled()
|
||||
//{
|
||||
// ULONG return_length = 0;
|
||||
//
|
||||
// SYSTEM_CODEINTEGRITY_INFORMATION info = { 0 };
|
||||
// info.Length = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
|
||||
// info.CodeIntegrityOptions = 0;
|
||||
//
|
||||
// NTSTATUS status = NtQuerySystemInformation(
|
||||
// SystemCodeIntegrityInformation,
|
||||
// &info,
|
||||
// sizeof(info),
|
||||
// &return_length
|
||||
// );
|
||||
//
|
||||
// if (!NT_SUCCESS(status))
|
||||
// {
|
||||
// LOG_ERROR("NtQuerySystemInformation failed with status: %lx", status);
|
||||
// return FALSE;
|
||||
// }
|
||||
//
|
||||
// return info.CodeIntegrityOptions & CODEINTEGRITY_OPTION_TESTSIGN;
|
||||
// }
|
||||
|
||||
DWORD WINAPI
|
||||
Init(HINSTANCE hinstDLL)
|
||||
{
|
||||
AllocConsole();
|
||||
FILE* file;
|
||||
freopen_s(&file, "CONOUT$", "w", stdout);
|
||||
freopen_s(&file, "CONIN$", "r", stdin);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
|
||||
LPCWSTR driver_name = L"\\\\.\\DonnaAC";
|
||||
|
||||
std::shared_ptr<global::ThreadPool> thread_pool = std::make_shared<global::ThreadPool>(4);
|
||||
std::shared_ptr<global::Client> client_interface =
|
||||
std::make_shared<global::Client>(thread_pool, pipe_name);
|
||||
|
||||
usermode::UManager umanager(thread_pool, client_interface);
|
||||
kernelmode::KManager kmanager(driver_name, thread_pool, client_interface);
|
||||
|
||||
global::headers::SYSTEM_INFORMATION system_information = {0};
|
||||
kmanager.SendClientHardwareInformation();
|
||||
|
||||
global::report_structures::SYSTEM_INFORMATION_REQUEST_RESPONSE response = {0};
|
||||
|
||||
// client_interface->ServerReceive( &response, sizeof( response ) );
|
||||
|
||||
// std::cout << "RequestID: " << response.RequestId << " CanUserProceed: " <<
|
||||
// response.CanUserProceed << " Reason: " << response.reason << std::endl;
|
||||
|
||||
/*
|
||||
* Note that this is really just for testing the methods for extended periods of time.
|
||||
* The "real business logic" would execute the methods with varying degrees of uncertaintity
|
||||
* but still allow for bias, i.e we don't want NMI callbacks to be running every 10 seconds.
|
||||
* We also need to take into account the performance penalty that some of these routines
|
||||
* have, such as the process module validation. At the end of the day an anti cheat that
|
||||
* imposes a significant performance pentalty on the game its protecting is useless.
|
||||
*/
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
while (!GetAsyncKeyState(VK_DELETE))
|
||||
{
|
||||
int seed = (rand() % 11);
|
||||
|
||||
std::cout << "Seed: " << seed << std::endl;
|
||||
|
||||
switch (seed)
|
||||
{
|
||||
case 0: kmanager.EnumerateHandleTables(); break;
|
||||
case 1: kmanager.PerformIntegrityCheck(); break;
|
||||
case 2: kmanager.ScanPoolsForUnlinkedProcesses(); break;
|
||||
case 3: kmanager.VerifySystemModuleDriverObjects(); break;
|
||||
case 4: kmanager.ValidateProcessModules(); break;
|
||||
case 5: kmanager.RunNmiCallbacks(); break;
|
||||
case 6: kmanager.CheckForAttachedThreads(); break;
|
||||
case 7: kmanager.InitiateApcStackwalkOperation(); break;
|
||||
case 8: kmanager.CheckForEptHooks(); break;
|
||||
case 9: kmanager.StackwalkThreadsViaDpc(); break;
|
||||
case 10: kmanager.ValidateSystemModules(); break;
|
||||
}
|
||||
|
||||
kmanager.MonitorCallbackReports();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
|
||||
fclose(stdout);
|
||||
fclose(stdin);
|
||||
FreeConsole();
|
||||
|
||||
FreeLibraryAndExitThread(hinstDLL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain(HINSTANCE hinstDLL, // handle to DLL module
|
||||
DWORD fdwReason, // reason for calling function
|
||||
LPVOID lpvReserved) // reserved
|
||||
{
|
||||
// Perform actions based on the reason for calling.
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
|
||||
const auto thread = CreateThread(nullptr,
|
||||
0,
|
||||
reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
|
||||
hinstDLL,
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
if (thread)
|
||||
CloseHandle(thread);
|
||||
|
||||
break;
|
||||
}
|
||||
return TRUE; // Successful DLL_PROCESS_ATTACH.
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#include "pipe.h"
|
||||
|
||||
#include "common.h"
|
||||
#include <intrin.h>
|
||||
|
||||
global::Pipe::Pipe(LPTSTR PipeName)
|
||||
{
|
||||
this->pipe_name = PipeName;
|
||||
this->pipe_handle = CreateFile(this->pipe_name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if (this->pipe_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("CreateFile failed with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
global::Pipe::WriteToPipe(PVOID Buffer, SIZE_T Size)
|
||||
{
|
||||
DWORD bytes_written = 0;
|
||||
|
||||
WriteFile(this->pipe_handle, Buffer, Size, &bytes_written, NULL);
|
||||
|
||||
if (bytes_written == 0)
|
||||
{
|
||||
LOG_ERROR("WriteFile failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
global::Pipe::ReadPipe(PVOID Buffer, SIZE_T Size)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
DWORD bytes_read = 0;
|
||||
|
||||
status = ReadFile(this->pipe_handle, Buffer, Size, &bytes_read, NULL);
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
LOG_ERROR("ReadFile failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
75
user/pipe.h
75
user/pipe.h
|
@ -1,75 +0,0 @@
|
|||
#ifndef PIPE_H
|
||||
#define PIPE_H
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define MESSAGE_TYPE_CLIENT_REPORT 1
|
||||
#define MESSAGE_TYPE_CLIENT_SEND 2
|
||||
#define MESSAGE_TYPE_CLIENT_REQUEST 3
|
||||
|
||||
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
|
||||
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
|
||||
|
||||
namespace global {
|
||||
class Pipe
|
||||
{
|
||||
HANDLE pipe_handle;
|
||||
LPTSTR pipe_name;
|
||||
|
||||
public:
|
||||
Pipe(LPTSTR PipeName);
|
||||
|
||||
void WriteToPipe(PVOID Buffer, SIZE_T Size);
|
||||
void ReadPipe(PVOID Buffer, SIZE_T Size);
|
||||
};
|
||||
|
||||
namespace headers {
|
||||
typedef enum _ENVIRONMENT_TYPE
|
||||
{
|
||||
NativeWindows = 0,
|
||||
Vmware,
|
||||
VirtualBox
|
||||
|
||||
} ENVIRONMENT_TYPE;
|
||||
|
||||
typedef enum _PROCESSOR_TYPE
|
||||
{
|
||||
Unknown = 0,
|
||||
GenuineIntel,
|
||||
AuthenticAmd
|
||||
|
||||
} PROCESSOR_TYPE;
|
||||
|
||||
#define VENDOR_STRING_MAX_LENGTH 256
|
||||
struct SYSTEM_INFORMATION
|
||||
{
|
||||
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
|
||||
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
|
||||
CHAR vendor[VENDOR_STRING_MAX_LENGTH];
|
||||
BOOLEAN virtualised_environment;
|
||||
ENVIRONMENT_TYPE environment;
|
||||
PROCESSOR_TYPE processor;
|
||||
RTL_OSVERSIONINFOW os_information;
|
||||
};
|
||||
|
||||
struct PIPE_PACKET_HEADER
|
||||
{
|
||||
INT message_type;
|
||||
UINT64 steam64_id;
|
||||
};
|
||||
|
||||
struct PIPE_PACKET_REQUEST_EXTENSION_HEADER
|
||||
{
|
||||
INT request_id;
|
||||
};
|
||||
|
||||
struct CLIENT_SEND_PACKET_HEADER
|
||||
{
|
||||
INT request_id;
|
||||
LONG packet_size;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,103 +0,0 @@
|
|||
#include "threadpool.h"
|
||||
|
||||
/*
|
||||
* This is the idle loop each thread will be running until a job is ready
|
||||
* for execution
|
||||
*/
|
||||
void
|
||||
global::ThreadPool::ThreadLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
std::function<void()> job;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
/*
|
||||
* This is equivalent to :
|
||||
*
|
||||
* while (!this->jobs.empty() || should_terminate)
|
||||
* mutex_condition.wait(lock);
|
||||
*
|
||||
* we are essentially waiting for a job to be queued up or the terminate
|
||||
*flag to be set. Another piece of useful information is that the predicate
|
||||
*is checked under the lock as the precondition for .wait() is that the
|
||||
*calling thread owns the lock.
|
||||
*
|
||||
* Now, when .wait() is run, the lock is unlocked the the executing thread
|
||||
*is blocked and is added to a list of threads current waiting on the
|
||||
*predicate. In our case whether there are new jobs available for the
|
||||
*terminate flag is set. Once the condition variables are true i.e there are
|
||||
*new jobs or we are terminating, the lock is reacquired by the thread and
|
||||
*the thread is unblocked.
|
||||
*/
|
||||
mutex_condition.wait(
|
||||
lock, [this] { return !this->jobs.empty() || this->should_terminate; });
|
||||
|
||||
if (this->should_terminate)
|
||||
return;
|
||||
|
||||
/* get the first job in the queue*/
|
||||
job = jobs.front();
|
||||
jobs.pop();
|
||||
}
|
||||
/* run the job */
|
||||
job();
|
||||
}
|
||||
}
|
||||
|
||||
global::ThreadPool::ThreadPool(int ThreadCount)
|
||||
{
|
||||
this->thread_count = ThreadCount;
|
||||
this->should_terminate = false;
|
||||
|
||||
/* Initiate our threads and store them in our threads vector */
|
||||
for (int i = 0; i < this->thread_count; i++)
|
||||
{
|
||||
this->threads.emplace_back(std::thread(&ThreadPool::ThreadLoop, this));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
global::ThreadPool::QueueJob(const std::function<void()>& job)
|
||||
{
|
||||
/* push a job into our job queue safely by holding our queue lock */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
this->jobs.push(job);
|
||||
lock.unlock();
|
||||
|
||||
mutex_condition.notify_one();
|
||||
}
|
||||
|
||||
void
|
||||
global::ThreadPool::Stop()
|
||||
{
|
||||
/* safely set our termination flag to true */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
should_terminate = true;
|
||||
lock.unlock();
|
||||
|
||||
/* unlock all threads waiting on our condition */
|
||||
mutex_condition.notify_all();
|
||||
|
||||
/* join the threads and clear our threads vector */
|
||||
for (std::thread& thread : threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
threads.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
global::ThreadPool::Busy()
|
||||
{
|
||||
/* allows us to wait for when the job queue is empty allowing us to safely call the
|
||||
* destructor */
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
|
||||
bool pool_busy = !jobs.empty();
|
||||
this->queue_mutex.unlock();
|
||||
|
||||
return pool_busy;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef THREADPOOL_H
|
||||
#define THREADPOOL_H
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
|
||||
namespace global {
|
||||
/*
|
||||
* This ThreadPool class is a simple threadpool implementation that will allow us
|
||||
* to delegate jobs to a set number of threads without the constant need to close
|
||||
* and open new threads.
|
||||
*/
|
||||
class ThreadPool
|
||||
{
|
||||
int thread_count;
|
||||
bool should_terminate;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable mutex_condition;
|
||||
std::vector<std::thread> threads;
|
||||
std::queue<std::function<void()>> jobs;
|
||||
|
||||
void ThreadLoop();
|
||||
|
||||
public:
|
||||
ThreadPool(int ThreadCount);
|
||||
void QueueJob(const std::function<void()>& job);
|
||||
void Stop();
|
||||
bool Busy();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,32 +0,0 @@
|
|||
#include "imports.h"
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
usermode::Imports::Imports()
|
||||
{
|
||||
NtQueryInformationThread = nullptr;
|
||||
RtlDosPathNameToNtPathName_U = nullptr;
|
||||
|
||||
this->ImportMap["NtQueryInformationThread"] = NtQueryInformationThread;
|
||||
this->ImportMap["RtlDosPathNameToNtPathName_U"] = RtlDosPathNameToNtPathName_U;
|
||||
|
||||
std::map<std::string, void*>::iterator it;
|
||||
|
||||
for (it = this->ImportMap.begin(); it != this->ImportMap.end(); it++)
|
||||
{
|
||||
HMODULE module_handle = GetModuleHandle(L"ntdll.dll");
|
||||
|
||||
if (!module_handle)
|
||||
{
|
||||
LOG_ERROR("GetModuleHandle failed with status code 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
it->second = GetProcAddress(module_handle, it->first.c_str());
|
||||
|
||||
if (!it->second)
|
||||
{
|
||||
LOG_ERROR("GetProcAddress failed with status code 0x%x", GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef IMPORTS_H
|
||||
#define IMPORTS_H
|
||||
|
||||
#include <winternl.h>
|
||||
#include <Windows.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
typedef NTSTATUS(WINAPI* pNtQueryInformationThread)(HANDLE, LONG, PVOID, ULONG, PULONG);
|
||||
typedef BOOLEAN(NTAPI pRtlDosPathNameToNtPathName_U(PCWSTR, PVOID, PCWSTR*, PVOID));
|
||||
|
||||
namespace usermode {
|
||||
class Imports
|
||||
{
|
||||
public:
|
||||
std::map<std::string, void*> ImportMap;
|
||||
|
||||
void* NtQueryInformationThread;
|
||||
void* NtQueryVirtualMemory;
|
||||
void* RtlDosPathNameToNtPathName_U;
|
||||
|
||||
Imports();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,321 +0,0 @@
|
|||
#include "process.h"
|
||||
|
||||
#include "../common.h"
|
||||
#include "../um/imports.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "../client.h"
|
||||
|
||||
#include <ImageHlp.h>
|
||||
#include <iostream>
|
||||
|
||||
const static char MASK_BYTE = '\x00';
|
||||
|
||||
usermode::Process::Process(std::shared_ptr<global::Client> ClientInterface)
|
||||
{
|
||||
this->process_handle = GetCurrentProcess();
|
||||
this->process_id = GetCurrentProcessId();
|
||||
this->function_imports = std::make_unique<Imports>();
|
||||
this->client_interface = ClientInterface;
|
||||
}
|
||||
|
||||
void
|
||||
usermode::Process::ValidateProcessThreads()
|
||||
{
|
||||
HANDLE thread_snapshot_handle = INVALID_HANDLE_VALUE;
|
||||
THREADENTRY32 thread_entry = {0};
|
||||
NTSTATUS status = 0;
|
||||
HANDLE thread_handle = INVALID_HANDLE_VALUE;
|
||||
UINT64 start_address = 0;
|
||||
bool result = false;
|
||||
|
||||
pNtQueryInformationThread NtQueryInfo = (pNtQueryInformationThread)this->function_imports
|
||||
->ImportMap["NtQueryInformationThread"];
|
||||
|
||||
/* th32ProcessId ignored for TH32CS_SNAPTHREAD value */
|
||||
thread_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
|
||||
if (thread_snapshot_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("thread snapshot handle invalid with error 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
thread_entry.dwSize = sizeof(THREADENTRY32);
|
||||
|
||||
if (!Thread32First(thread_snapshot_handle, &thread_entry))
|
||||
{
|
||||
LOG_ERROR("Thread32First failed with status 0x%x", GetLastError());
|
||||
CloseHandle(thread_snapshot_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (thread_entry.th32OwnerProcessID != process_id)
|
||||
continue;
|
||||
|
||||
thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
|
||||
|
||||
if (thread_handle == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
|
||||
status = NtQueryInfo(thread_handle,
|
||||
(THREADINFOCLASS)ThreadQuerySetWin32StartAddress,
|
||||
&start_address,
|
||||
sizeof(UINT64),
|
||||
NULL);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
LOG_ERROR("NtQueryInfo failed with status code 0x%lx", status);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CheckIfAddressLiesWithinValidProcessModule(start_address, &result))
|
||||
{
|
||||
if (result == false)
|
||||
{
|
||||
global::report_structures::PROCESS_THREAD_START_FAILURE report;
|
||||
report.report_code = REPORT_CODE_START_ADDRESS_VERIFICATION;
|
||||
report.start_address = start_address;
|
||||
report.thread_id = thread_entry.th32ThreadID;
|
||||
this->client_interface->ReportViolation(&report);
|
||||
}
|
||||
}
|
||||
|
||||
} while (Thread32Next(thread_snapshot_handle, &thread_entry));
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterates through a processes modules and confirms whether the address lies within the memory
|
||||
* region of the module. A simple way to check if a thread is a valid thread, however there are ways
|
||||
* around this check so it is not a perfect solution.
|
||||
*/
|
||||
bool
|
||||
usermode::Process::CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result)
|
||||
{
|
||||
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
|
||||
MODULEENTRY32 module_entry = {0};
|
||||
|
||||
process_modules_handle =
|
||||
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
|
||||
|
||||
LOG_INFO("Address: %llx", Address);
|
||||
|
||||
if (process_modules_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
module_entry.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
if (!Module32First(process_modules_handle, &module_entry))
|
||||
{
|
||||
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
|
||||
CloseHandle(process_modules_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
UINT64 base = (UINT64)module_entry.modBaseAddr;
|
||||
UINT64 end = base + module_entry.modBaseSize;
|
||||
|
||||
if (Address >= base && Address <= end)
|
||||
{
|
||||
LOG_INFO("found valid module LOL");
|
||||
CloseHandle(process_modules_handle);
|
||||
*Result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
} while (Module32Next(process_modules_handle, &module_entry));
|
||||
|
||||
CloseHandle(process_modules_handle);
|
||||
*Result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
usermode::Process::GetHandleToProcessGivenName(std::string ProcessName)
|
||||
{
|
||||
std::wstring wide_process_name = {0};
|
||||
std::wstring target_process_name = {0};
|
||||
HANDLE process_snapshot_handle = INVALID_HANDLE_VALUE;
|
||||
HANDLE process_handle = INVALID_HANDLE_VALUE;
|
||||
PROCESSENTRY32 process_entry = {0};
|
||||
|
||||
wide_process_name = std::wstring(ProcessName.begin(), ProcessName.end());
|
||||
process_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
|
||||
if (process_snapshot_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("Failed to create snapshot of current running processes error: 0x%x",
|
||||
GetLastError());
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
process_entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(process_snapshot_handle, &process_entry))
|
||||
{
|
||||
LOG_ERROR("Failed to get the first process using Process32First error: 0x%x",
|
||||
GetLastError());
|
||||
CloseHandle(process_snapshot_handle);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
process_handle =
|
||||
OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_entry.th32ProcessID);
|
||||
|
||||
/*
|
||||
* this will generally fail due to a process being an elevated process and denying
|
||||
* us access so we dont really care if OpenProcess fails in most cases
|
||||
*/
|
||||
if (process_handle == NULL)
|
||||
continue;
|
||||
|
||||
target_process_name = std::wstring(process_entry.szExeFile);
|
||||
|
||||
if (wide_process_name == target_process_name)
|
||||
{
|
||||
LOG_INFO("Found target process");
|
||||
CloseHandle(process_snapshot_handle);
|
||||
return process_handle;
|
||||
}
|
||||
|
||||
} while (Process32Next(process_snapshot_handle, &process_entry));
|
||||
|
||||
CloseHandle(process_snapshot_handle);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
bool
|
||||
usermode::Process::GetProcessBaseAddress(UINT64* Result)
|
||||
{
|
||||
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
|
||||
MODULEENTRY32 module_entry = {0};
|
||||
|
||||
process_modules_handle =
|
||||
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
|
||||
|
||||
if (process_modules_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
module_entry.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
if (!Module32First(process_modules_handle, &module_entry))
|
||||
{
|
||||
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
|
||||
CloseHandle(process_modules_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
*Result = (UINT64)module_entry.modBaseAddr;
|
||||
CloseHandle(process_modules_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
usermode::Process::ScanProcessMemory()
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION memory_info = {0};
|
||||
UINT64 address = 0;
|
||||
|
||||
if (!GetProcessBaseAddress(&address))
|
||||
{
|
||||
LOG_ERROR("Failed to get process base address with status 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
while (VirtualQueryEx(
|
||||
this->process_handle, (PVOID)address, &memory_info, sizeof(MEMORY_BASIC_INFORMATION)))
|
||||
{
|
||||
this->CheckPageProtection(&memory_info);
|
||||
this->PatternScanRegion(address, &memory_info);
|
||||
|
||||
address += memory_info.RegionSize;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usermode::Process::PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page)
|
||||
{
|
||||
/* todo: stream signatures from server */
|
||||
// char buf[] = "\x85\xc0\x74\x00\xb9\x00\x00\x00\x00\xcd";
|
||||
char buf[] =
|
||||
"\x55\x8B\xEC\xFF\x75\x00\xD9\x45\x00\x51\xD9\x1C\x00\xE8\x00\x00\x00\x00\x5D\xC2\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
|
||||
std::vector<char> signature = {0};
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
signature.push_back(buf[i]);
|
||||
|
||||
/* skip free or reserved pages */
|
||||
if (Page->State == MEM_RESERVE || Page->State == MEM_FREE)
|
||||
return;
|
||||
|
||||
char* base = (char*)Address;
|
||||
|
||||
for (unsigned int i = 0; i < Page->RegionSize; i++)
|
||||
{
|
||||
for (unsigned j = 0; j < signature.size(); j++)
|
||||
{
|
||||
char current_byte = *(base + i);
|
||||
char current_sig_byte = signature[j];
|
||||
|
||||
/* if we've found the signature, report */
|
||||
if (j + 1 == signature.size())
|
||||
{
|
||||
global::report_structures::PATTERN_SCAN_FAILURE report;
|
||||
report.report_code = REPORT_PATTERN_SCAN_FAILURE;
|
||||
report.address = (UINT64)base + i;
|
||||
report.signature_id =
|
||||
1; /* this will be taken from the vector in future */
|
||||
this->client_interface->ReportViolation(&report);
|
||||
|
||||
/*
|
||||
* for now return, however when we stream the signatures we iterate
|
||||
* over each signature for every page
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* else, continue searching */
|
||||
if (current_byte != current_sig_byte && current_sig_byte != MASK_BYTE)
|
||||
break;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usermode::Process::CheckPageProtection(MEMORY_BASIC_INFORMATION* Page)
|
||||
{
|
||||
/* MEM_IMAGE indicates the pages are mapped into view of an image section */
|
||||
if (Page->Type == MEM_IMAGE)
|
||||
return;
|
||||
|
||||
if (Page->AllocationProtect & PAGE_EXECUTE || Page->AllocationProtect & PAGE_EXECUTE_READ ||
|
||||
Page->AllocationProtect & PAGE_EXECUTE_READWRITE ||
|
||||
Page->AllocationProtect & PAGE_EXECUTE_WRITECOPY)
|
||||
{
|
||||
// Not etirely sure about this check, needs to be looked into further.
|
||||
global::report_structures::PAGE_PROTECTION_FAILURE report;
|
||||
report.report_code = REPORT_PAGE_PROTECTION_VERIFICATION;
|
||||
report.page_base_address = (UINT64)Page->AllocationBase;
|
||||
report.allocation_protection = Page->AllocationProtect;
|
||||
report.allocation_state = Page->State;
|
||||
report.allocation_type = Page->Type;
|
||||
this->client_interface->ReportViolation(&report);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef PROCESS_H
|
||||
#define PROCESS_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <string>
|
||||
|
||||
#include "../client.h"
|
||||
#include "../threadpool.h"
|
||||
#include "../um/imports.h"
|
||||
#include "../km/kmanager.h"
|
||||
|
||||
#define ThreadQuerySetWin32StartAddress 9
|
||||
|
||||
namespace usermode {
|
||||
/*
|
||||
* This class represents a process and the usermode functions responsible for
|
||||
* the protection of it. This class represents the protected process and allows
|
||||
* us to split protection class into methods which can then be easily managed
|
||||
* by the usermode manager class.
|
||||
*/
|
||||
class Process
|
||||
{
|
||||
HANDLE process_handle;
|
||||
DWORD process_id;
|
||||
std::mutex mutex;
|
||||
std::unique_ptr<Imports> function_imports;
|
||||
std::vector<DWORD> in_memory_module_checksums;
|
||||
std::shared_ptr<global::Client> client_interface;
|
||||
|
||||
HANDLE GetHandleToProcessGivenName(std::string ProcessName);
|
||||
bool CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result);
|
||||
bool GetProcessBaseAddress(UINT64* Result);
|
||||
void CheckPageProtection(MEMORY_BASIC_INFORMATION* Page);
|
||||
void PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page);
|
||||
|
||||
public:
|
||||
Process(std::shared_ptr<global::Client> ClientInterface);
|
||||
|
||||
void ValidateProcessThreads();
|
||||
void ScanProcessMemory();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||
#include "umanager.h"
|
||||
|
||||
#include "../common.h"
|
||||
#include "process.h"
|
||||
#include "../um/imports.h"
|
||||
|
||||
#include <TlHelp32.h>
|
||||
|
||||
usermode::UManager::UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
|
||||
std::shared_ptr<global::Client> ReportInterface)
|
||||
{
|
||||
this->thread_pool = ThreadPool;
|
||||
this->process = std::make_unique<Process>(ReportInterface);
|
||||
}
|
||||
|
||||
usermode::UManager::~UManager()
|
||||
{
|
||||
/* Wait for our jobs to be finished, then safely stop our pool */
|
||||
// while ( true )
|
||||
//{
|
||||
// if ( this->thread_pool->Busy() == FALSE )
|
||||
// {
|
||||
// this->thread_pool->Stop();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
usermode::UManager::ValidateProcessThreads()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->process->ValidateProcessThreads(); });
|
||||
}
|
||||
|
||||
void
|
||||
usermode::UManager::ValidateProcessMemory()
|
||||
{
|
||||
this->thread_pool->QueueJob([this]() { this->process->ScanProcessMemory(); });
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef UMANAGER_H
|
||||
#define UMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <winternl.h>
|
||||
#include <Windows.h>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "..\client.h"
|
||||
|
||||
#include "process.h"
|
||||
|
||||
namespace usermode {
|
||||
/*
|
||||
* The manager class is meant to abstract away the interaction between the Process
|
||||
* class and the threadpool class to allow a single thread (or multiple) to easily run
|
||||
* the core business logic of running tasks in a certain order.
|
||||
*/
|
||||
class UManager
|
||||
{
|
||||
std::unique_ptr<Process> process;
|
||||
std::shared_ptr<global::ThreadPool> thread_pool;
|
||||
|
||||
public:
|
||||
UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
|
||||
std::shared_ptr<global::Client> ReportInterface);
|
||||
~UManager();
|
||||
|
||||
void ValidateProcessThreads();
|
||||
void ValidateProcessMemory();
|
||||
void ValidateProcessModules();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,283 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - No Server - Win11|Win32">
|
||||
<Configuration>Release - No Server - Win11</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - No Server - Win11|x64">
|
||||
<Configuration>Release - No Server - Win11</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - No Server|Win32">
|
||||
<Configuration>Release - No Server</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release - No Server|x64">
|
||||
<Configuration>Release - No Server</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{3c8194c7-9f20-4ff8-8c4c-b26c3d053611}</ProjectGuid>
|
||||
<RootNamespace>user</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - No Server - Win11|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NO_SERVER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>Imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>C:\Users\lachuie\source\repos\ac\x64\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pipe.cpp" />
|
||||
<ClCompile Include="km\driver.cpp" />
|
||||
<ClCompile Include="km\kmanager.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="um\imports.cpp" />
|
||||
<ClCompile Include="um\process.cpp" />
|
||||
<ClCompile Include="threadpool.cpp" />
|
||||
<ClCompile Include="um\umanager.cpp" />
|
||||
<ClCompile Include="client.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pipe.h" />
|
||||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="km\driver.h" />
|
||||
<ClInclude Include="km\kmanager.h" />
|
||||
<ClInclude Include="client.h" />
|
||||
<ClInclude Include="um\imports.h" />
|
||||
<ClInclude Include="um\process.h" />
|
||||
<ClInclude Include="threadpool.h" />
|
||||
<ClInclude Include="um\umanager.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
Loading…
Reference in a new issue