├── .gitattributes ├── Client ├── Client.cpp ├── Client.vcxproj ├── Client.vcxproj.filters ├── Define │ ├── IA32.h │ └── VAD.h ├── Driver │ ├── CommunicationType.h │ ├── Driver.cpp │ └── Driver.h ├── Inject.cpp ├── Inject.h ├── Library │ └── skCrypter.h └── Utils │ ├── Hijack.cpp │ ├── Hijack.h │ ├── MemoryUtils.cpp │ └── MemoryUtils.h ├── Driver ├── API.cpp ├── API.h ├── Communication │ ├── Communication.cpp │ ├── Communication.h │ └── CommunicationType.h ├── Define │ ├── CRT.h │ ├── IA32.h │ ├── NT.h │ └── Patterns.h ├── Driver.inf ├── Driver.vcxproj ├── Driver.vcxproj.filters ├── Hide │ ├── Hide.cpp │ └── Hide.h ├── Library │ └── skCrypter.h ├── Main.cpp └── Utils │ ├── MemoryUtils.cpp │ └── MemoryUtils.h ├── Images ├── BehindThreadStack.PNG ├── NoSpoofing.PNG ├── PteSpoofing.PNG ├── RemoveVadNode.PNG └── VadSpoofing.PNG └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Client/Client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Driver/Driver.h" 4 | #include "Library/skCrypter.h" 5 | #include "Inject.h" 6 | 7 | INT main( 8 | INT Argc, 9 | CHAR* Argv[] 10 | ) { 11 | if (Argc < 6) { 12 | printf("Usage: Client.exe \n"); 13 | printf(":\n"); 14 | printf(" 0 - Do not spoof page protection\n"); 15 | printf(" 1 - Spoof page protection via PTE manipulation\n"); 16 | printf(" 2 - Spoof page protection via VAD manipulation\n"); 17 | printf("\n:\n"); 18 | printf(" 0 - Do not remove VAD node\n"); 19 | printf(" 1 - Remove VAD node\n"); 20 | printf("\n:\n"); 21 | printf(" 0 - Randomly allocate memory\n"); 22 | printf(" 1 - Allocate memory behind thread stack"); 23 | return 1; 24 | } 25 | 26 | if (!NT_SUCCESS(Driver::Initialize())) { 27 | auto Text = skCrypt("Driver is not loaded\n"); 28 | printf(Text); 29 | Text.clear(); 30 | Sleep(2000); 31 | return 1; 32 | } 33 | Inject::Map(Argv[1], Argv[2], Argv[3], Argv[4], Argv[5]); 34 | 35 | return 0; 36 | } -------------------------------------------------------------------------------- /Client/Client.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {f9dc8bc2-af1c-431a-a7f8-905486dfa96f} 25 | Client 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level3 88 | true 89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Console 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | true 101 | true 102 | true 103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | true 105 | 106 | 107 | Console 108 | true 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | true 117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 118 | true 119 | stdcpp17 120 | stdc17 121 | 122 | 123 | Console 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | true 132 | true 133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 134 | true 135 | 136 | 137 | Console 138 | true 139 | true 140 | true 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /Client/Client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {abbf069c-d7d2-44dc-83ad-8639f89fca54} 10 | 11 | 12 | {5508f314-9915-40b0-9930-85a47a103c4f} 13 | 14 | 15 | {36b51166-6e6c-4bb5-a397-f44796c51e6a} 16 | 17 | 18 | {06ee8f1e-c9cf-4684-aa17-12d0d666bdde} 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files\Driver 30 | 31 | 32 | Source Files\Utils 33 | 34 | 35 | Source Files\Utils 36 | 37 | 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files\Define 44 | 45 | 46 | Source Files\Define 47 | 48 | 49 | Source Files\Driver 50 | 51 | 52 | Source Files\Driver 53 | 54 | 55 | Source Files\Library 56 | 57 | 58 | Source Files\Utils 59 | 60 | 61 | Source Files\Utils 62 | 63 | 64 | -------------------------------------------------------------------------------- /Client/Define/VAD.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef struct _RTL_BALANCED_NODE { 5 | union { 6 | struct _RTL_BALANCED_NODE* Children[2]; 7 | struct { 8 | struct _RTL_BALANCED_NODE* Left; 9 | struct _RTL_BALANCED_NODE* Right; 10 | } DUMMYSTRUCTNAME; 11 | } DUMMYUNIONNAME; 12 | 13 | #define RTL_BALANCED_NODE_RESERVED_PARENT_MASK 3 14 | 15 | union { 16 | UCHAR Red : 1; 17 | UCHAR Balance : 2; 18 | ULONG_PTR ParentValue; 19 | } DUMMYUNIONNAME2; 20 | } RTL_BALANCED_NODE, * PRTL_BALANCED_NODE; 21 | 22 | typedef struct _MM_AVL_NODE // Size=24 23 | { 24 | struct _MM_AVL_NODE* LeftChild; // Size=8 Offset=0 25 | struct _MM_AVL_NODE* RightChild; // Size=8 Offset=8 26 | 27 | union ___unnamed1666 // Size=8 28 | { 29 | struct 30 | { 31 | __int64 Balance : 2; // Size=8 Offset=0 BitOffset=0 BitCount=2 32 | }; 33 | struct _MM_AVL_NODE* Parent; // Size=8 Offset=0 34 | } u1; 35 | } MM_AVL_NODE, * PMM_AVL_NODE, * PMMADDRESS_NODE; 36 | 37 | typedef struct _RTL_AVL_TREE // Size=8 38 | { 39 | PMM_AVL_NODE BalancedRoot; 40 | void* NodeHint; 41 | unsigned __int64 NumberGenericTableElements; 42 | } RTL_AVL_TREE, * PRTL_AVL_TREE, MM_AVL_TABLE, * PMM_AVL_TABLE; 43 | 44 | union _EX_PUSH_LOCK // Size=8 45 | { 46 | struct 47 | { 48 | unsigned __int64 Locked : 1; // Size=8 Offset=0 BitOffset=0 BitCount=1 49 | unsigned __int64 Waiting : 1; // Size=8 Offset=0 BitOffset=1 BitCount=1 50 | unsigned __int64 Waking : 1; // Size=8 Offset=0 BitOffset=2 BitCount=1 51 | unsigned __int64 MultipleShared : 1; // Size=8 Offset=0 BitOffset=3 BitCount=1 52 | unsigned __int64 Shared : 60; // Size=8 Offset=0 BitOffset=4 BitCount=60 53 | }; 54 | unsigned __int64 Value; // Size=8 Offset=0 55 | void* Ptr; // Size=8 Offset=0 56 | }; 57 | 58 | typedef struct _MMVAD_FLAGS { 59 | ULONG Lock : 1; //0x0 60 | ULONG LockContended : 1; //0x0 61 | ULONG DeleteInProgress : 1; //0x0 62 | ULONG NoChange : 1; //0x0 63 | ULONG VadType : 3; //0x0 64 | ULONG Protection : 5; //0x0 65 | ULONG PreferredNode : 6; //0x0 66 | ULONG PageSize : 2; //0x0 67 | ULONG PrivateMemory : 1; //0x0 68 | } MMVAD_FLAGS, * PMMVAD_FLAGS; 69 | 70 | struct _MMVAD_FLAGS1 // Size=4 71 | { 72 | unsigned long CommitCharge : 31; // Size=4 Offset=0 BitOffset=0 BitCount=31 73 | unsigned long MemCommit : 1; // Size=4 Offset=0 BitOffset=31 BitCount=1 74 | }; 75 | 76 | struct _MMVAD_FLAGS2 // Size=4 77 | { 78 | unsigned long FileOffset : 24; // Size=4 Offset=0 BitOffset=0 BitCount=24 79 | unsigned long Large : 1; // Size=4 Offset=0 BitOffset=24 BitCount=1 80 | unsigned long TrimBehind : 1; // Size=4 Offset=0 BitOffset=25 BitCount=1 81 | unsigned long Inherit : 1; // Size=4 Offset=0 BitOffset=26 BitCount=1 82 | unsigned long CopyOnWrite : 1; // Size=4 Offset=0 BitOffset=27 BitCount=1 83 | unsigned long NoValidationNeeded : 1; // Size=4 Offset=0 BitOffset=28 BitCount=1 84 | unsigned long Spare : 3; // Size=4 Offset=0 BitOffset=29 BitCount=3 85 | }; 86 | 87 | struct _MI_VAD_SEQUENTIAL_INFO // Size=8 88 | { 89 | unsigned __int64 Length : 12; // Size=8 Offset=0 BitOffset=0 BitCount=12 90 | unsigned __int64 Vpn : 52; // Size=8 Offset=0 BitOffset=12 BitCount=52 91 | }; 92 | 93 | union ___unnamed1951 // Size=4 94 | { 95 | unsigned long LongFlags; // Size=4 Offset=0 96 | struct _MMVAD_FLAGS VadFlags; // Size=4 Offset=0 97 | }; 98 | 99 | union ___unnamed1952 // Size=4 100 | { 101 | unsigned long LongFlags1; // Size=4 Offset=0 102 | struct _MMVAD_FLAGS1 VadFlags1; // Size=4 Offset=0 103 | }; 104 | 105 | union ___unnamed2047 // Size=4 106 | { 107 | unsigned long LongFlags2; // Size=4 Offset=0 108 | struct _MMVAD_FLAGS2 VadFlags2; // Size=4 Offset=0 109 | }; 110 | 111 | union ___unnamed2048 // Size=8 112 | { 113 | struct _MI_VAD_SEQUENTIAL_INFO SequentialVa; // Size=8 Offset=0 114 | struct _MMEXTEND_INFO* ExtendedInfo; // Size=8 Offset=0 115 | }; 116 | 117 | typedef struct _MMVAD_SHORT 118 | { 119 | union 120 | { 121 | struct 122 | { 123 | struct _MMVAD_SHORT* NextVad; //0x0 124 | VOID* ExtraCreateInfo; //0x8 125 | }; 126 | struct _RTL_BALANCED_NODE VadNode; //0x0 127 | }; 128 | ULONG StartingVpn; //0x18 129 | ULONG EndingVpn; //0x1c 130 | UCHAR StartingVpnHigh; //0x20 131 | UCHAR EndingVpnHigh; //0x21 132 | UCHAR CommitChargeHigh; //0x22 133 | UCHAR SpareNT64VadUChar; //0x23 134 | LONG ReferenceCount; //0x24 135 | union _EX_PUSH_LOCK PushLock; //0x28 136 | union ___unnamed1951 u; // Size=4 Offset=48 137 | union ___unnamed1952 u1; // Size=4 Offset=52 //0x34 138 | struct _MI_VAD_EVENT_BLOCK* EventList; //0x38 139 | } MMVAD_SHORT, * PMMVAD_SHORT; 140 | 141 | typedef struct _MMVAD // Size=128 142 | { 143 | struct _MMVAD_SHORT Core; // Size=64 Offset=0 144 | union ___unnamed2047 u2; // Size=4 Offset=64 145 | unsigned long pad0; // Size=4 Offset=68 146 | struct _SUBSECTION* Subsection; // Size=8 Offset=72 147 | struct _MMPTE* FirstPrototypePte; // Size=8 Offset=80 148 | struct _MMPTE* LastContiguousPte; // Size=8 Offset=88 149 | struct _LIST_ENTRY ViewLinks; // Size=16 Offset=96 150 | struct _EPROCESS* VadsProcess; // Size=8 Offset=112 151 | union ___unnamed2048 u4; // Size=8 Offset=120 152 | struct _FILE_OBJECT* FileObject; // Size=8 Offset=128 153 | } MMVAD, * PMMVAD; 154 | -------------------------------------------------------------------------------- /Client/Driver/CommunicationType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "../Define/IA32.h" 4 | #include "../Define/VAD.h" 5 | 6 | CONST ULONG DATA_UNIQUE = 0x8392; 7 | 8 | typedef struct _READ_MEMORY { 9 | HANDLE ProcessId; 10 | DWORD64 Address; 11 | ULONG Size; 12 | PVOID pOut; 13 | } READ_MEMORY, * PREAD_MEMORY; 14 | 15 | typedef struct _WRITE_MEMORY { 16 | HANDLE ProcessId; 17 | DWORD64 Address; 18 | ULONG Size; 19 | PVOID pSrc; 20 | } WRITE_MEMORY, * PWRITE_MEMORY; 21 | 22 | typedef struct _PROTECT_MEMORY { 23 | HANDLE ProcessId; 24 | PVOID Address; 25 | DWORD Size; 26 | PVOID InOutProtect; 27 | } PROTECT_MEMORY, * PPROTECT_MEMORY; 28 | 29 | typedef struct _ALLOC_MEMORY { 30 | HANDLE ProcessId; 31 | PVOID pOut; 32 | DWORD Size; 33 | DWORD Protect; 34 | } ALLOC_MEMORY, * PALLOC_MEMORY; 35 | 36 | typedef struct _FREE_MEMORY { 37 | HANDLE ProcessId; 38 | PVOID Address; 39 | } FREE_MEMORY, * PFREE_MEMORY; 40 | 41 | typedef struct _GET_PTE { 42 | HANDLE ProcessId; 43 | PVOID Address; 44 | PVOID pOut; 45 | } GET_PTE, * PGET_PTE; 46 | 47 | typedef struct _SET_PTE { 48 | HANDLE ProcessId; 49 | PVOID Address; 50 | PTE_64 Pte; 51 | } SET_PTE, * PSET_PTE; 52 | 53 | typedef struct _QUERY_VIRTUAL_MEMORY { 54 | HANDLE ProcessId; 55 | PVOID Address; 56 | PVOID pOut; 57 | } QUERY_VIRTUAL_MEMORY, * PQUERY_VIRTUAL_MEMORY; 58 | 59 | typedef struct _GET_VAD_FLAGS { 60 | HANDLE ProcessId; 61 | PVOID Address; 62 | PVOID pOut; 63 | } GET_VAD_FLAGS, * PGET_VAD_FLAGS; 64 | 65 | typedef struct _SET_VAD_FLAGS { 66 | HANDLE ProcessId; 67 | PVOID Address; 68 | MMVAD_FLAGS VADFlags; 69 | } SET_VAD_FLAGS, * PSET_VAD_FLAGS; 70 | 71 | typedef struct _REMOVE_VAD { 72 | HANDLE ProcessId; 73 | PVOID Address; 74 | } REMOVE_VAD, * PREMOVE_VAD; 75 | 76 | typedef struct _ALLOCATE_VAD { 77 | HANDLE ProcessId; 78 | PVOID Address; 79 | ULONGLONG Size; 80 | ULONG Protection; 81 | } ALLOCATE_VAD, * PALLOCATE_VAD; 82 | 83 | typedef enum _REQUEST_TYPE { 84 | REQUEST_READ_MEMORY, 85 | REQUEST_WRITE_MEMORY, 86 | REQUEST_PROTECT_MEMORY, 87 | REQUEST_ALLOC_MEMORY, 88 | REQUEST_FREE_MEMORY, 89 | REQUEST_GET_PTE, 90 | REQUEST_SET_PTE, 91 | REQUEST_QUERY_VIRTUAL_MEMORY, 92 | REQUEST_GET_VAD_FLAGS, 93 | REQUEST_SET_VAD_FLAGS, 94 | REQUEST_REMOVE_VAD_NODE, 95 | REQUEST_ALLOC_VAD 96 | } REQUEST_TYPE; 97 | 98 | typedef struct _REQUEST_DATA { 99 | DWORD Unique; 100 | REQUEST_TYPE Type; 101 | PVOID Arguments; 102 | } REQUEST_DATA, * PREQUEST_DATA; 103 | -------------------------------------------------------------------------------- /Client/Driver/Driver.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Driver.h" 4 | #include "../Library/skCrypter.h" 5 | 6 | PVOID(NTAPI* NtConvertBetweenAuxiliaryCounterAndPerformanceCounter)(PVOID, PVOID, PVOID, PVOID); 7 | 8 | NTSTATUS 9 | Driver::Initialize() { 10 | auto Module = LoadLibrary(skCrypt(L"ntdll.dll")); 11 | if (!Module) { 12 | return STATUS_UNSUCCESSFUL; 13 | } 14 | 15 | *reinterpret_cast(&NtConvertBetweenAuxiliaryCounterAndPerformanceCounter) = GetProcAddress(Module, skCrypt("NtConvertBetweenAuxiliaryCounterAndPerformanceCounter")); 16 | if (!NtConvertBetweenAuxiliaryCounterAndPerformanceCounter) { 17 | return STATUS_UNSUCCESSFUL; 18 | } 19 | 20 | return STATUS_SUCCESS; 21 | } 22 | 23 | NTSTATUS 24 | SendRequest( 25 | REQUEST_TYPE Type, 26 | PVOID Args, 27 | SIZE_T ArgsSize 28 | ) { 29 | REQUEST_DATA Request = { 0 }; 30 | Request.Unique = DATA_UNIQUE; 31 | Request.Type = Type; 32 | Request.Arguments = Args; 33 | 34 | auto RequestPtr = &Request; 35 | 36 | auto Status = 0ULL; 37 | NtConvertBetweenAuxiliaryCounterAndPerformanceCounter(0, &RequestPtr, &Status, 0); 38 | return static_cast(Status); 39 | } 40 | 41 | NTSTATUS 42 | Driver::API::ReadMemory( 43 | IN CONST HANDLE Pid, 44 | IN CONST PVOID Address, 45 | IN CONST ULONG Size, 46 | OUT CONST PVOID pOut 47 | ) { 48 | READ_MEMORY Message; 49 | Message.ProcessId = Pid; 50 | Message.Address = (DWORD64)Address; 51 | Message.Size = Size; 52 | Message.pOut = pOut; 53 | 54 | return SendRequest(REQUEST_TYPE::REQUEST_READ_MEMORY, &Message, sizeof(Message)); 55 | } 56 | 57 | NTSTATUS 58 | Driver::API::WriteMemory( 59 | IN CONST HANDLE Pid, 60 | IN CONST DWORD64 Ptr, 61 | IN CONST ULONG Size, 62 | IN CONST PVOID pSrc 63 | ) { 64 | WRITE_MEMORY Message; 65 | Message.ProcessId = Pid; 66 | Message.Address = Ptr; 67 | Message.Size = Size; 68 | Message.pSrc = pSrc; 69 | 70 | return SendRequest(REQUEST_TYPE::REQUEST_WRITE_MEMORY, &Message, sizeof(Message)); 71 | } 72 | 73 | NTSTATUS 74 | Driver::API::ProtectMemory( 75 | IN CONST HANDLE ProcessId, 76 | IN CONST PVOID Address, 77 | IN CONST DWORD Size, 78 | IN OUT CONST PVOID pInOutProtect 79 | ) { 80 | PROTECT_MEMORY Message; 81 | Message.ProcessId = ProcessId; 82 | Message.Address = Address; 83 | Message.Size = Size; 84 | Message.InOutProtect = pInOutProtect; 85 | 86 | return SendRequest(REQUEST_TYPE::REQUEST_PROTECT_MEMORY, &Message, sizeof(Message)); 87 | } 88 | 89 | NTSTATUS 90 | Driver::API::AllocMemory( 91 | IN CONST HANDLE ProcessId, 92 | OUT CONST PVOID pOut, 93 | IN CONST DWORD Size, 94 | IN CONST DWORD Protect 95 | ) { 96 | ALLOC_MEMORY Message; 97 | Message.ProcessId = ProcessId; 98 | Message.pOut = pOut; 99 | Message.Size = Size; 100 | Message.Protect = Protect; 101 | 102 | return SendRequest(REQUEST_TYPE::REQUEST_ALLOC_MEMORY, &Message, sizeof(Message)); 103 | } 104 | 105 | NTSTATUS 106 | Driver::API::FreeMemory( 107 | IN CONST HANDLE ProcessId, 108 | IN CONST PVOID Address 109 | ) { 110 | FREE_MEMORY Message; 111 | Message.ProcessId = ProcessId; 112 | Message.Address = Address; 113 | 114 | return SendRequest(REQUEST_TYPE::REQUEST_FREE_MEMORY, &Message, sizeof(Message)); 115 | } 116 | 117 | NTSTATUS 118 | Driver::API::GetPte( 119 | IN CONST HANDLE ProcessId, 120 | IN CONST PVOID Address, 121 | OUT CONST PVOID pOut 122 | ) { 123 | GET_PTE Message; 124 | Message.ProcessId = ProcessId; 125 | Message.Address = Address; 126 | Message.pOut = pOut; 127 | 128 | return SendRequest(REQUEST_TYPE::REQUEST_GET_PTE, &Message, sizeof(Message)); 129 | } 130 | 131 | NTSTATUS 132 | Driver::API::SetPte( 133 | IN CONST HANDLE ProcessId, 134 | IN CONST PVOID Address, 135 | IN CONST PTE_64 Pte 136 | ) { 137 | SET_PTE Message; 138 | Message.ProcessId = ProcessId; 139 | Message.Address = Address; 140 | Message.Pte = Pte; 141 | 142 | return SendRequest(REQUEST_TYPE::REQUEST_SET_PTE, &Message, sizeof(Message)); 143 | } 144 | 145 | NTSTATUS 146 | Driver::API::QueryVirtualMemory( 147 | IN CONST HANDLE ProcessId, 148 | IN CONST PVOID Address, 149 | OUT CONST PVOID pOut 150 | ) { 151 | QUERY_VIRTUAL_MEMORY Message; 152 | Message.ProcessId = ProcessId; 153 | Message.Address = Address; 154 | Message.pOut = pOut; 155 | 156 | return SendRequest(REQUEST_TYPE::REQUEST_QUERY_VIRTUAL_MEMORY, &Message, sizeof(Message)); 157 | } 158 | 159 | NTSTATUS 160 | Driver::API::GetVADFlags( 161 | IN CONST HANDLE ProcessId, 162 | IN CONST PVOID Address, 163 | OUT CONST PVOID pOut 164 | ) { 165 | GET_VAD_FLAGS Message; 166 | Message.ProcessId = ProcessId; 167 | Message.Address = Address; 168 | Message.pOut = pOut; 169 | 170 | return SendRequest(REQUEST_TYPE::REQUEST_GET_VAD_FLAGS, &Message, sizeof(Message)); 171 | } 172 | 173 | NTSTATUS 174 | Driver::API::SetVADFlags( 175 | IN CONST HANDLE ProcessId, 176 | IN CONST PVOID Address, 177 | IN CONST MMVAD_FLAGS VADFlags 178 | ) { 179 | SET_VAD_FLAGS Message; 180 | Message.ProcessId = ProcessId; 181 | Message.Address = Address; 182 | Message.VADFlags = VADFlags; 183 | 184 | return SendRequest(REQUEST_TYPE::REQUEST_SET_VAD_FLAGS, &Message, sizeof(Message)); 185 | } 186 | 187 | NTSTATUS 188 | Driver::API::RemoveVADNode( 189 | IN CONST HANDLE ProcessId, 190 | IN CONST PVOID Address 191 | ) { 192 | REMOVE_VAD Message; 193 | Message.ProcessId = ProcessId; 194 | Message.Address = Address; 195 | 196 | return SendRequest(REQUEST_TYPE::REQUEST_REMOVE_VAD_NODE, &Message, sizeof(Message)); 197 | } 198 | 199 | NTSTATUS 200 | Driver::API::AllocateVAD( 201 | IN CONST HANDLE ProcessId, 202 | IN CONST PVOID Address, 203 | IN CONST ULONGLONG Size 204 | ) { 205 | ALLOCATE_VAD Message; 206 | Message.ProcessId = ProcessId; 207 | Message.Address = Address; 208 | Message.Size = Size; 209 | 210 | return SendRequest(REQUEST_TYPE::REQUEST_ALLOC_VAD, &Message, sizeof(Message)); 211 | } 212 | -------------------------------------------------------------------------------- /Client/Driver/Driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "CommunicationType.h" 4 | #include "../Define/VAD.h" 5 | 6 | #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) 7 | 8 | namespace Driver { 9 | NTSTATUS 10 | Initialize(); 11 | 12 | namespace API { 13 | 14 | NTSTATUS 15 | ReadMemory( 16 | IN CONST HANDLE ProcessId, 17 | IN CONST PVOID Address, 18 | IN CONST ULONG Size, 19 | OUT CONST PVOID pOut 20 | ); 21 | 22 | NTSTATUS 23 | WriteMemory( 24 | IN CONST HANDLE ProcessId, 25 | IN CONST DWORD64 Address, 26 | IN CONST ULONG Size, 27 | IN CONST PVOID pSrc 28 | ); 29 | 30 | NTSTATUS 31 | ProtectMemory( 32 | IN CONST HANDLE ProcessId, 33 | IN CONST PVOID Address, 34 | IN CONST DWORD Size, 35 | IN OUT CONST PVOID pInOutProtect 36 | ); 37 | 38 | NTSTATUS 39 | AllocMemory( 40 | IN CONST HANDLE ProcessId, 41 | OUT CONST PVOID pOut, 42 | IN CONST DWORD Size, 43 | IN CONST DWORD Protect 44 | ); 45 | 46 | NTSTATUS 47 | FreeMemory( 48 | IN CONST HANDLE ProcessId, 49 | IN CONST PVOID Address 50 | ); 51 | 52 | NTSTATUS 53 | GetPte( 54 | IN CONST HANDLE ProcessId, 55 | IN CONST PVOID Address, 56 | OUT CONST PVOID pOut 57 | ); 58 | 59 | NTSTATUS 60 | SetPte( 61 | IN CONST HANDLE ProcessId, 62 | IN CONST PVOID Address, 63 | IN CONST PTE_64 Pte 64 | ); 65 | 66 | NTSTATUS 67 | QueryVirtualMemory( 68 | IN CONST HANDLE ProcessId, 69 | IN CONST PVOID Address, 70 | OUT CONST PVOID pOut 71 | ); 72 | 73 | NTSTATUS 74 | GetVADFlags( 75 | IN CONST HANDLE ProcessId, 76 | IN CONST PVOID Address, 77 | OUT CONST PVOID pOut 78 | ); 79 | 80 | NTSTATUS 81 | SetVADFlags( 82 | IN CONST HANDLE ProcessId, 83 | IN CONST PVOID Address, 84 | IN CONST MMVAD_FLAGS VADFlags 85 | ); 86 | 87 | NTSTATUS 88 | RemoveVADNode( 89 | IN CONST HANDLE ProcessId, 90 | IN CONST PVOID Address 91 | ); 92 | 93 | NTSTATUS 94 | AllocateVAD( 95 | IN CONST HANDLE ProcessId, 96 | IN CONST PVOID Address, 97 | IN CONST ULONGLONG Size 98 | ); 99 | } 100 | } -------------------------------------------------------------------------------- /Client/Inject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Inject.h" 4 | #include "Library/skCrypter.h" 5 | #include "Driver/Driver.h" 6 | #include "Utils/MemoryUtils.h" 7 | #include "Utils/Hijack.h" 8 | 9 | #pragma comment(lib, "ntdll.lib") 10 | 11 | extern "C" NTSYSAPI PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(PVOID Base); 12 | 13 | // FACE Injector 14 | 15 | BOOL 16 | RelocateImage( 17 | PVOID pRemoteImg, 18 | PVOID pLocalImg, 19 | PIMAGE_NT_HEADERS NtHead 20 | ) { 21 | typedef struct _RELOC_ENTRY { 22 | ULONG ToRVA; 23 | ULONG Size; 24 | struct 25 | { 26 | WORD Offset : 12; 27 | WORD Type : 4; 28 | } Item[1]; 29 | } RELOC_ENTRY, * PRELOC_ENTRY; 30 | 31 | ULONGLONG DeltaOffset = (ULONGLONG)pRemoteImg - NtHead->OptionalHeader.ImageBase; 32 | if (!DeltaOffset) 33 | return TRUE; 34 | else if (!(NtHead->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) 35 | return FALSE; 36 | 37 | PRELOC_ENTRY RelocEnt = (PRELOC_ENTRY)MemoryUtils::RVA_VA(NtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, NtHead, pLocalImg); 38 | ULONGLONG RelocEnd = (ULONGLONG)RelocEnt + NtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; 39 | 40 | if (RelocEnt == nullptr) 41 | return TRUE; 42 | 43 | while ((uintptr_t)RelocEnt < RelocEnd && RelocEnt->Size) { 44 | DWORD RecordsCount = (RelocEnt->Size - 8) >> 1; 45 | for (DWORD i = 0; i < RecordsCount; i++) { 46 | WORD FixType = (RelocEnt->Item[i].Type); 47 | WORD ShiftDelta = (RelocEnt->Item[i].Offset) % 4096; 48 | 49 | if (FixType == IMAGE_REL_BASED_ABSOLUTE) 50 | continue; 51 | 52 | if (FixType == IMAGE_REL_BASED_HIGHLOW || FixType == IMAGE_REL_BASED_DIR64) { 53 | uintptr_t FixVA = (uintptr_t)MemoryUtils::RVA_VA(RelocEnt->ToRVA, NtHead, pLocalImg); 54 | 55 | if (!FixVA) 56 | FixVA = (uintptr_t)pLocalImg; 57 | 58 | *(uintptr_t*)(FixVA + ShiftDelta) += DeltaOffset; 59 | } 60 | } 61 | 62 | RelocEnt = (PRELOC_ENTRY)((LPBYTE)RelocEnt + RelocEnt->Size); 63 | } 64 | return TRUE; 65 | } 66 | 67 | ULONGLONG 68 | ResolveFunctionAddress( 69 | LPCSTR ModName, 70 | LPCSTR ModFunc 71 | ) { 72 | HMODULE hModule = LoadLibraryExA(ModName, NULL, DONT_RESOLVE_DLL_REFERENCES); 73 | ULONGLONG FuncOffset = (ULONGLONG)GetProcAddress(hModule, ModFunc); 74 | FuncOffset -= (ULONGLONG)hModule; 75 | FreeLibrary(hModule); 76 | 77 | return FuncOffset; 78 | } 79 | 80 | BOOL 81 | ResolveImport( 82 | DWORD ThreadId, 83 | DWORD ProcessId, 84 | PVOID pLocalImg, 85 | PIMAGE_NT_HEADERS NtHead 86 | ) { 87 | PIMAGE_IMPORT_DESCRIPTOR ImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)MemoryUtils::RVA_VA(NtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, NtHead, pLocalImg); 88 | if (!NtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress || !NtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) \ 89 | return TRUE; 90 | 91 | LPSTR ModuleName = NULL; 92 | while ((ModuleName = (LPSTR)MemoryUtils::RVA_VA(ImportDesc->Name, NtHead, pLocalImg))) { 93 | uintptr_t BaseImage = (uintptr_t)LoadLibraryA(ModuleName); 94 | 95 | if (!BaseImage) 96 | return FALSE; 97 | 98 | PIMAGE_THUNK_DATA IhData = (PIMAGE_THUNK_DATA)MemoryUtils::RVA_VA(ImportDesc->FirstThunk, NtHead, pLocalImg); 99 | while (IhData->u1.AddressOfData) { 100 | if (IhData->u1.Ordinal & IMAGE_ORDINAL_FLAG) 101 | IhData->u1.Function = BaseImage + ResolveFunctionAddress(ModuleName, (LPCSTR)(IhData->u1.Ordinal & 0xFFFF)); 102 | else { 103 | IMAGE_IMPORT_BY_NAME* IBN = (PIMAGE_IMPORT_BY_NAME)MemoryUtils::RVA_VA(IhData->u1.AddressOfData, NtHead, pLocalImg); 104 | IhData->u1.Function = BaseImage + ResolveFunctionAddress(ModuleName, (LPCSTR)IBN->Name); 105 | } IhData++; 106 | } ImportDesc++; 107 | } return true; 108 | } 109 | 110 | VOID 111 | WriteSections( 112 | DWORD ProcessId, 113 | PVOID pModuleBase, 114 | PVOID LocalImage, 115 | PIMAGE_NT_HEADERS NtHead 116 | ) { 117 | PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHead); 118 | for (WORD SectionCount = 0; SectionCount < NtHead->FileHeader.NumberOfSections; SectionCount++, Section++) { 119 | NTSTATUS WriteStatus = Driver::API::WriteMemory((HANDLE)ProcessId, (DWORD64)((ULONGLONG)pModuleBase + Section->VirtualAddress), Section->SizeOfRawData, (PVOID)((ULONGLONG)LocalImage + Section->PointerToRawData)); 120 | } 121 | } 122 | 123 | VOID 124 | EraseDiscardableSect( 125 | DWORD ProcessId, 126 | PVOID pModuleBase, 127 | PIMAGE_NT_HEADERS NtHead 128 | ) { 129 | PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(NtHead); 130 | for (WORD SectionCount = 0; SectionCount < NtHead->FileHeader.NumberOfSections; SectionCount++, Section++) { 131 | if (Section->SizeOfRawData == 0) 132 | continue; 133 | 134 | if (Section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { 135 | PVOID pZeroMemory = VirtualAlloc(NULL, Section->SizeOfRawData, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 136 | Driver::API::WriteMemory((HANDLE)ProcessId, (DWORD64)((ULONGLONG)pModuleBase + Section->VirtualAddress), Section->SizeOfRawData, pZeroMemory); 137 | VirtualFree(pZeroMemory, 0, MEM_RELEASE); 138 | } 139 | } 140 | } 141 | 142 | VOID 143 | Inject::Map( 144 | LPCSTR WindowClassName, 145 | LPCSTR DllPath, 146 | PCHAR SpoofPageProtection, 147 | PCHAR RemoveVADNode, 148 | PCHAR AllocateBehindThreadStack 149 | ) { 150 | PVOID DllImage = MemoryUtils::GetDllFromFile(DllPath); 151 | if (!DllImage) { 152 | auto Text = skCrypt("Invalid dll\n"); 153 | printf(Text); 154 | Text.clear(); 155 | return; 156 | } 157 | 158 | PIMAGE_NT_HEADERS DllNtHead = RtlImageNtHeader(DllImage); 159 | if (!DllNtHead) { 160 | auto Text = skCrypt("Invalid PE header\n"); 161 | printf(Text); 162 | Text.clear(); 163 | return; 164 | } 165 | 166 | ULONG ThreadId = NULL, ProcessId = NULL; 167 | MemoryUtils::GetProcessIdAndThreadIdFromWindowClass(WindowClassName, &ProcessId, &ThreadId); 168 | if (!ThreadId || !ProcessId) { 169 | auto Text = skCrypt("Invalid thread id / process id\n"); 170 | printf(Text); 171 | Text.clear(); 172 | return; 173 | } 174 | 175 | PVOID AllocateBase = NULL; 176 | if (!strcmp(AllocateBehindThreadStack, "1")) { 177 | if (AllocateBase = MemoryUtils::GetLastThreadStack(ProcessId)) 178 | Driver::API::AllocateVAD((HANDLE)ProcessId, AllocateBase, DllNtHead->OptionalHeader.SizeOfImage); 179 | } 180 | else { 181 | Driver::API::AllocMemory((HANDLE)ProcessId, 182 | &AllocateBase, 183 | DllNtHead->OptionalHeader.SizeOfImage, 184 | !strcmp(SpoofPageProtection, "1") ? PAGE_READWRITE : PAGE_EXECUTE_READWRITE); 185 | } 186 | 187 | if (!AllocateBase) { 188 | auto Text = skCrypt("Failed to allocate memory"); 189 | printf(Text); 190 | Text.clear(); 191 | return; 192 | } 193 | 194 | ULONG DllSize = DllNtHead->OptionalHeader.SizeOfImage; 195 | ULONG DllEntryPointOffset = DllNtHead->OptionalHeader.AddressOfEntryPoint; 196 | 197 | if (!RelocateImage(AllocateBase, DllImage, DllNtHead)) { 198 | Driver::API::FreeMemory((HANDLE)ProcessId, AllocateBase); 199 | auto Text = skCrypt("Failed to relocate image\n"); 200 | printf(Text); 201 | Text.clear(); 202 | return; 203 | } 204 | 205 | if (!ResolveImport(ThreadId, ProcessId, DllImage, DllNtHead)) { 206 | Driver::API::FreeMemory((HANDLE)ProcessId, AllocateBase); 207 | auto Text = skCrypt("Failed to resolve imports\n"); 208 | printf(Text); 209 | Text.clear(); 210 | return; 211 | } 212 | 213 | WriteSections(ProcessId, AllocateBase, DllImage, DllNtHead); 214 | EraseDiscardableSect(ProcessId, AllocateBase, DllNtHead); 215 | 216 | printf("Wrote DLL to process %i at address 0x%p\n", ProcessId, AllocateBase); 217 | 218 | if (!strcmp(SpoofPageProtection, "1")) { 219 | MemoryUtils::FlipExecutableBitForMemoryRegion((HANDLE)ProcessId, AllocateBase, 0); 220 | } 221 | else if (!strcmp(SpoofPageProtection, "2")) { 222 | MMVAD_FLAGS VadFlags{}; 223 | Driver::API::GetVADFlags((HANDLE)ProcessId, AllocateBase, &VadFlags); 224 | VadFlags.Protection = PAGE_READWRITE; 225 | Driver::API::SetVADFlags((HANDLE)ProcessId, AllocateBase, VadFlags); 226 | } 227 | 228 | Hijack::CallViaSetWindowsHookEx(ProcessId, ThreadId, AllocateBase, DllNtHead); 229 | 230 | if (!strcmp(RemoveVADNode, "1")) { 231 | Driver::API::RemoveVADNode((HANDLE)ProcessId, AllocateBase); 232 | } 233 | 234 | VirtualFree(DllImage, 0, MEM_RELEASE); 235 | } 236 | -------------------------------------------------------------------------------- /Client/Inject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Inject { 5 | VOID 6 | Map( 7 | LPCSTR WindowClassName, 8 | LPCSTR DllPath, 9 | PCHAR SpoofPageProtection, 10 | PCHAR RemoveVADNode, 11 | PCHAR AllocateBehindThreadStack 12 | ); 13 | } -------------------------------------------------------------------------------- /Client/Library/skCrypter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*____________________________________________________________________________________________________________ 4 | 5 | Original Author: skadro 6 | Github: https://github.com/skadro-official 7 | License: See end of file 8 | 9 | skCrypter 10 | Compile-time, Usermode + Kernelmode, safe and lightweight string crypter library for C++11+ 11 | 12 | *Not removing this part is appreciated* 13 | ____________________________________________________________________________________________________________*/ 14 | 15 | #ifdef _KERNEL_MODE 16 | namespace std 17 | { 18 | // STRUCT TEMPLATE remove_reference 19 | template 20 | struct remove_reference { 21 | using type = _Ty; 22 | }; 23 | 24 | template 25 | struct remove_reference<_Ty&> { 26 | using type = _Ty; 27 | }; 28 | 29 | template 30 | struct remove_reference<_Ty&&> { 31 | using type = _Ty; 32 | }; 33 | 34 | template 35 | using remove_reference_t = typename remove_reference<_Ty>::type; 36 | 37 | // STRUCT TEMPLATE remove_const 38 | template 39 | struct remove_const { // remove top-level const qualifier 40 | using type = _Ty; 41 | }; 42 | 43 | template 44 | struct remove_const { 45 | using type = _Ty; 46 | }; 47 | 48 | template 49 | using remove_const_t = typename remove_const<_Ty>::type; 50 | } 51 | #else 52 | #include 53 | #endif 54 | 55 | namespace skc 56 | { 57 | template 58 | using clean_type = typename std::remove_const_t>; 59 | 60 | template 61 | class skCrypter 62 | { 63 | public: 64 | __forceinline constexpr skCrypter(T* data) 65 | { 66 | crypt(data); 67 | } 68 | 69 | __forceinline T* get() 70 | { 71 | return _storage; 72 | } 73 | 74 | __forceinline int size() // (w)char count 75 | { 76 | return _size; 77 | } 78 | 79 | __forceinline char key() 80 | { 81 | return _key1; 82 | } 83 | 84 | __forceinline T* encrypt() 85 | { 86 | if (!isEncrypted()) 87 | crypt(_storage); 88 | 89 | return _storage; 90 | } 91 | 92 | __forceinline T* decrypt() 93 | { 94 | if (isEncrypted()) 95 | crypt(_storage); 96 | 97 | return _storage; 98 | } 99 | 100 | __forceinline bool isEncrypted() 101 | { 102 | return _storage[_size - 1] != 0; 103 | } 104 | 105 | __forceinline void clear() // set full storage to 0 106 | { 107 | for (int i = 0; i < _size; i++) 108 | { 109 | _storage[i] = 0; 110 | } 111 | } 112 | 113 | __forceinline operator T* () 114 | { 115 | decrypt(); 116 | 117 | return _storage; 118 | } 119 | 120 | private: 121 | __forceinline constexpr void crypt(T* data) 122 | { 123 | for (int i = 0; i < _size; i++) 124 | { 125 | _storage[i] = data[i] ^ (_key1 + i % (1 + _key2)); 126 | } 127 | } 128 | 129 | T _storage[_size]{}; 130 | }; 131 | } 132 | 133 | #define skCrypt(str) skCrypt_key(str, __TIME__[4], __TIME__[7]) 134 | #define skCrypt_key(str, key1, key2) []() { \ 135 | constexpr static auto crypted = skc::skCrypter \ 136 | >((skc::clean_type*)str); \ 137 | return crypted; }() 138 | 139 | /*________________________________________________________________________________ 140 | 141 | MIT License 142 | 143 | Copyright (c) 2020 skadro 144 | 145 | Permission is hereby granted, free of charge, to any person obtaining a copy 146 | of this software and associated documentation files (the "Software"), to deal 147 | in the Software without restriction, including without limitation the rights 148 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 149 | copies of the Software, and to permit persons to whom the Software is 150 | furnished to do so, subject to the following conditions: 151 | 152 | The above copyright notice and this permission notice shall be included in all 153 | copies or substantial portions of the Software. 154 | 155 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 157 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 158 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 159 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 160 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 161 | SOFTWARE. 162 | 163 | ________________________________________________________________________________*/ -------------------------------------------------------------------------------- /Client/Utils/Hijack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Hijack.h" 4 | #include "../Driver/Driver.h" 5 | 6 | BYTE RemoteCallDllMain[92] = { 7 | 0x48, 0x83, 0xEC, 0x38, 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0x8B, 0x44, 0x24, 8 | 0x20, 0x83, 0x38, 0x00, 0x75, 0x39, 0x48, 0x8B, 0x44, 0x24, 0x20, 0xC7, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x20, 0x48, 9 | 0x8B, 0x40, 0x08, 0x48, 0x89, 0x44, 0x24, 0x28, 0x45, 0x33, 0xC0, 0xBA, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x20, 0x48, 0x8B, 10 | 0x48, 0x10, 0xFF, 0x54, 0x24, 0x28, 0x48, 0x8B, 0x44, 0x24, 0x20, 0xC7, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xC4, 0x38, 0xC3, 0xCC 11 | }; DWORD ShellDataOffset = 0x6; 12 | 13 | typedef struct _MAIN_STRUCT { 14 | INT Status; 15 | uintptr_t FnDllMain; 16 | HINSTANCE DllBase; 17 | } MAIN_STRUCT, * PMAIN_STRUCT; 18 | 19 | BOOL 20 | Hijack::CallViaSetWindowsHookEx( 21 | DWORD ProcessId, 22 | DWORD ThreadId, 23 | PVOID DllBase, 24 | PIMAGE_NT_HEADERS NtHeader 25 | ) { 26 | HMODULE NtDll = LoadLibraryW(L"ntdll.dll"); 27 | 28 | PVOID AllocShellCode = NULL; 29 | Driver::API::AllocMemory((HANDLE)ProcessId, &AllocShellCode, 0x1000, PAGE_EXECUTE_READWRITE); 30 | 31 | DWORD ShellSize = sizeof(RemoteCallDllMain) + sizeof(MAIN_STRUCT); 32 | PVOID AllocLocal = VirtualAlloc(NULL, ShellSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 33 | RtlCopyMemory(AllocLocal, &RemoteCallDllMain, sizeof(RemoteCallDllMain)); 34 | ULONGLONG ShellData = (ULONGLONG)AllocShellCode + sizeof(RemoteCallDllMain); 35 | *(ULONGLONG*)((ULONGLONG)AllocLocal + ShellDataOffset) = ShellData; 36 | 37 | PMAIN_STRUCT MainData = (PMAIN_STRUCT)((ULONGLONG)AllocLocal + sizeof(RemoteCallDllMain)); 38 | MainData->DllBase = (HINSTANCE)DllBase; 39 | MainData->FnDllMain = ((ULONGLONG)DllBase + NtHeader->OptionalHeader.AddressOfEntryPoint); 40 | Driver::API::WriteMemory((HANDLE)ProcessId, (DWORD64)AllocShellCode, ShellSize, AllocLocal); 41 | 42 | HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)AllocShellCode, NtDll, ThreadId); 43 | while (MainData->Status != 2) { 44 | PostThreadMessage(ThreadId, WM_NULL, 0, 0); 45 | Sleep(10); 46 | Driver::API::ReadMemory((HANDLE)ProcessId, (PVOID)ShellData, sizeof(MAIN_STRUCT), (PVOID)MainData); 47 | } 48 | UnhookWindowsHookEx(hHook); 49 | 50 | BYTE ZeroShell[116ui64] = { 0 }; 51 | Driver::API::WriteMemory((HANDLE)ProcessId, (DWORD64)AllocShellCode, 116ui64, ZeroShell); 52 | 53 | Driver::API::FreeMemory((HANDLE)ProcessId, AllocShellCode); 54 | VirtualFree(AllocLocal, 0, MEM_RELEASE); 55 | 56 | return TRUE; 57 | } 58 | -------------------------------------------------------------------------------- /Client/Utils/Hijack.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace Hijack { 4 | BOOL 5 | CallViaSetWindowsHookEx( 6 | DWORD ProcessId, 7 | DWORD ThreadId, 8 | PVOID DllBase, 9 | PIMAGE_NT_HEADERS NtHeader 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /Client/Utils/MemoryUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "MemoryUtils.h" 5 | #include "../Driver/Driver.h" 6 | 7 | using std::vector; 8 | 9 | typedef struct _CLIENT_ID { 10 | HANDLE UniqueProcess; 11 | HANDLE UniqueThread; 12 | } CLIENT_ID; 13 | 14 | typedef struct _THREAD_BASIC_INFORMATION { 15 | NTSTATUS ExitStatus; 16 | PVOID TebBaseAddress; 17 | CLIENT_ID ClientId; 18 | KAFFINITY AffinityMask; 19 | LONG Priority; 20 | LONG BasePriority; 21 | } THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION; 22 | 23 | typedef NTSTATUS(NTAPI* _NtQueryInformationThread) ( 24 | HANDLE ThreadHandle, 25 | ULONG ThreadInformationClass, 26 | PVOID ThreadInformation, 27 | ULONG ThreadInformationLength, 28 | PULONG ReturnLength 29 | ); 30 | 31 | PVOID 32 | MemoryUtils::GetDllFromFile( 33 | LPCSTR DllPath 34 | ) { 35 | HANDLE hDll = CreateFileA(DllPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 36 | if (hDll == INVALID_HANDLE_VALUE) 37 | return NULL; 38 | 39 | DWORD DllFileSize = GetFileSize(hDll, NULL); 40 | PVOID DllBuffer = VirtualAlloc(NULL, DllFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 41 | 42 | if (!ReadFile(hDll, DllBuffer, DllFileSize, NULL, FALSE)) { 43 | VirtualFree(DllBuffer, 0, MEM_RELEASE); 44 | goto Exit; 45 | } 46 | 47 | Exit: 48 | CloseHandle(hDll); 49 | return DllBuffer; 50 | } 51 | 52 | VOID 53 | MemoryUtils::GetProcessIdAndThreadIdFromWindowClass( 54 | LPCSTR WindowClassName, 55 | PDWORD pProcessId, 56 | PDWORD pThreadId 57 | ) { 58 | *pProcessId = 0; 59 | while (!*pProcessId) { 60 | *pThreadId = GetWindowThreadProcessId(FindWindowA(WindowClassName, NULL), pProcessId); 61 | Sleep(20); 62 | } 63 | } 64 | 65 | PVOID 66 | MemoryUtils::RVA_VA( 67 | ULONGLONG RVA, 68 | PIMAGE_NT_HEADERS NtHead, 69 | PVOID LocalImage 70 | ) { 71 | PIMAGE_SECTION_HEADER pFirstSect = IMAGE_FIRST_SECTION(NtHead); 72 | for (PIMAGE_SECTION_HEADER pSection = pFirstSect; pSection < pFirstSect + NtHead->FileHeader.NumberOfSections; pSection++) 73 | if (RVA >= pSection->VirtualAddress && RVA < pSection->VirtualAddress + pSection->Misc.VirtualSize) 74 | return (PUCHAR)LocalImage + pSection->PointerToRawData + (RVA - pSection->VirtualAddress); 75 | 76 | return NULL; 77 | } 78 | 79 | BOOL 80 | MemoryUtils::FlipExecutableBitForMemoryRegion( 81 | HANDLE ProcessId, 82 | PVOID Address, 83 | LONGLONG ExecuteDisable 84 | ) { 85 | MEMORY_BASIC_INFORMATION MBI{}; 86 | Driver::API::QueryVirtualMemory(ProcessId, Address, &MBI); 87 | 88 | for ( 89 | ULONGLONG i = reinterpret_cast(MBI.BaseAddress); 90 | i < (reinterpret_cast(MBI.BaseAddress) + MBI.RegionSize); 91 | i += 0x1000 92 | ) { 93 | PTE_64 PTE{}; 94 | Driver::API::GetPte(ProcessId, reinterpret_cast(i), &PTE); 95 | PTE.ExecuteDisable = ExecuteDisable; 96 | Driver::API::SetPte(ProcessId, reinterpret_cast(i), PTE); 97 | } 98 | 99 | return TRUE; 100 | } 101 | 102 | vector 103 | WalkProcessThreads( 104 | ULONG ProcessId 105 | ) { 106 | vector ThreadIds{}; 107 | THREADENTRY32 TE32; 108 | 109 | HANDLE Handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 110 | if (Handle == INVALID_HANDLE_VALUE) { 111 | return {}; 112 | } 113 | 114 | TE32.dwSize = sizeof(THREADENTRY32); 115 | if (!Thread32First(Handle, &TE32)) { 116 | CloseHandle(Handle); 117 | return {}; 118 | } 119 | 120 | do { 121 | if (TE32.th32OwnerProcessID == ProcessId) { 122 | ThreadIds.push_back(TE32.th32ThreadID); 123 | } 124 | } while (Thread32Next(Handle, &TE32)); 125 | 126 | CloseHandle(Handle); 127 | return ThreadIds; 128 | } 129 | 130 | PVOID 131 | MemoryUtils::GetLastThreadStack( 132 | ULONG ProcessId 133 | ) { 134 | vector ThreadStacks{}; 135 | 136 | _NtQueryInformationThread NtQueryInformationThread = (_NtQueryInformationThread)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationThread"); 137 | 138 | vector ThreadIds = WalkProcessThreads(ProcessId); 139 | for (ULONG ThreadId : ThreadIds) { 140 | THREAD_BASIC_INFORMATION TBI; 141 | NT_TIB TIB; 142 | 143 | HANDLE Handle = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, ThreadId); 144 | NtQueryInformationThread(Handle, 0x0, &TBI, sizeof(THREAD_BASIC_INFORMATION), NULL); 145 | Driver::API::ReadMemory((HANDLE)ProcessId, TBI.TebBaseAddress, sizeof(TIB), &TIB); 146 | 147 | ThreadStacks.push_back(TIB.StackLimit); 148 | } 149 | 150 | PVOID LastThreadStack = 0; 151 | for (UINT i = 0; i < ThreadStacks.size(); i++) { 152 | if (ThreadStacks[i] > LastThreadStack) 153 | LastThreadStack = ThreadStacks[i]; 154 | } 155 | 156 | MEMORY_BASIC_INFORMATION MBI{}; 157 | Driver::API::QueryVirtualMemory((HANDLE)ProcessId, LastThreadStack, &MBI); 158 | 159 | return (PVOID)((ULONGLONG)MBI.BaseAddress + MBI.RegionSize); 160 | } 161 | -------------------------------------------------------------------------------- /Client/Utils/MemoryUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "../Define/IA32.h" 4 | 5 | namespace MemoryUtils { 6 | PVOID 7 | GetDllFromFile( 8 | LPCSTR DllPath 9 | ); 10 | 11 | VOID 12 | GetProcessIdAndThreadIdFromWindowClass( 13 | LPCSTR WindowClassName, 14 | PDWORD pProcessId, 15 | PDWORD pThreadId 16 | ); 17 | 18 | PVOID 19 | RVA_VA( 20 | ULONGLONG RVA, 21 | PIMAGE_NT_HEADERS NtHead, 22 | PVOID LocalImage 23 | ); 24 | 25 | BOOL 26 | FlipExecutableBitForMemoryRegion( 27 | HANDLE ProcessId, 28 | PVOID Address, 29 | LONGLONG ExecuteDisable 30 | ); 31 | 32 | PVOID 33 | GetLastThreadStack( 34 | ULONG ProcessId 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /Driver/API.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "API.h" 3 | #include "Utils/MemoryUtils.h" 4 | #include "Define/NT.h" 5 | #include "Define/Patterns.h" 6 | 7 | PMMVAD_SHORT(*MiAllocateVad)(UINT_PTR start, UINT_PTR end, LOGICAL deletable) = NULL; 8 | NTSTATUS(*MiInsertVadCharges)(PMMVAD_SHORT vad, PEPROCESS process) = NULL; 9 | VOID(*MiInsertVad)(PMMVAD_SHORT vad, PEPROCESS process) = NULL; 10 | 11 | NTSTATUS 12 | API::ReadMemory( 13 | CONST PREAD_MEMORY Message 14 | ) { 15 | NTSTATUS Status = STATUS_SUCCESS; 16 | PEPROCESS Process = NULL; 17 | 18 | Status = PsLookupProcessByProcessId(Message->ProcessId, &Process); 19 | 20 | if (!NT_SUCCESS(Status)) { 21 | return Status; 22 | } 23 | 24 | SIZE_T Result = 0; 25 | 26 | __try { 27 | 28 | Status = MmCopyVirtualMemory( 29 | Process, 30 | (PVOID)Message->Address, 31 | PsGetCurrentProcess(), 32 | (PVOID)Message->pOut, 33 | Message->Size, 34 | KernelMode, 35 | &Result 36 | ); 37 | } 38 | __except (EXCEPTION_EXECUTE_HANDLER) { 39 | 40 | Status = GetExceptionCode(); 41 | } 42 | 43 | ObDereferenceObject(Process); 44 | 45 | return Status; 46 | } 47 | 48 | NTSTATUS 49 | API::WriteMemory( 50 | CONST PWRITE_MEMORY Message 51 | ) { 52 | NTSTATUS Status = STATUS_SUCCESS; 53 | PEPROCESS Process = NULL; 54 | 55 | Status = PsLookupProcessByProcessId(Message->ProcessId, &Process); 56 | 57 | if (!NT_SUCCESS(Status)) { 58 | return Status; 59 | } 60 | 61 | SIZE_T Result = 0; 62 | 63 | __try { 64 | Status = MmCopyVirtualMemory( 65 | PsGetCurrentProcess(), 66 | (PVOID)Message->pSrc, 67 | Process, 68 | (PVOID)Message->Address, 69 | Message->Size, 70 | KernelMode, 71 | &Result 72 | ); 73 | } 74 | __except (EXCEPTION_EXECUTE_HANDLER) { 75 | Status = GetExceptionCode(); 76 | } 77 | 78 | ObDereferenceObject(Process); 79 | 80 | return Status; 81 | } 82 | 83 | NTSTATUS 84 | API::ProtectMemory( 85 | CONST PPROTECT_MEMORY Message 86 | ) { 87 | PEPROCESS Process = NULL; 88 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 89 | if (NT_SUCCESS(Status)) { 90 | DWORD Protect = NULL; 91 | SIZE_T ReturnSize = NULL; 92 | if (MemoryUtils::SafeCopy(&Protect, Message->InOutProtect, sizeof(Protect))) { 93 | SIZE_T Size = Message->Size; 94 | 95 | KeAttachProcess(Process); 96 | Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Message->Address, &Size, Protect, &Protect); 97 | KeDetachProcess(); 98 | 99 | MemoryUtils::SafeCopy(Message->InOutProtect, &Protect, sizeof(Protect)); 100 | } 101 | else { 102 | Status = STATUS_ACCESS_VIOLATION; 103 | } 104 | 105 | ObDereferenceObject(Process); 106 | } 107 | 108 | return Status; 109 | } 110 | 111 | NTSTATUS 112 | API::AllocMemory( 113 | CONST PALLOC_MEMORY Message 114 | ) { 115 | PEPROCESS Process = NULL; 116 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 117 | if (NT_SUCCESS(Status)) { 118 | PVOID Address = NULL; 119 | SIZE_T size = Message->Size; 120 | 121 | KeAttachProcess(Process); 122 | ZwAllocateVirtualMemory(NtCurrentProcess(), &Address, 0, &size, MEM_COMMIT | MEM_RESERVE, Message->Protect); 123 | KeDetachProcess(); 124 | 125 | MemoryUtils::SafeCopy(Message->pOut, &Address, sizeof(Address)); 126 | 127 | ObDereferenceObject(Process); 128 | } 129 | 130 | return Status; 131 | } 132 | 133 | NTSTATUS 134 | API::FreeMemory( 135 | CONST PFREE_MEMORY Message 136 | ) { 137 | PEPROCESS Process = NULL; 138 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 139 | if (NT_SUCCESS(Status)) { 140 | SIZE_T Size = 0; 141 | 142 | KeAttachProcess(Process); 143 | ZwFreeVirtualMemory(NtCurrentProcess(), &Message->Address, &Size, MEM_RELEASE); 144 | KeDetachProcess(); 145 | 146 | ObDereferenceObject(Process); 147 | } 148 | 149 | return Status; 150 | } 151 | 152 | NTSTATUS 153 | API::GetPte( 154 | CONST PGET_PTE Message 155 | ) { 156 | PTE_64 PTEToCopy{}; 157 | PEPROCESS Process = NULL; 158 | if (NT_SUCCESS(PsLookupProcessByProcessId(Message->ProcessId, &Process))) { 159 | KAPC_STATE state; 160 | KeStackAttachProcess(Process, &state); 161 | 162 | CR3 cr3{}; 163 | cr3.Flags = __readcr3(); 164 | PTE_64* pte = (PTE_64*)MemoryUtils::GetPte(Message->Address, cr3); 165 | if (pte) { 166 | PTEToCopy.Present = pte->Present; 167 | PTEToCopy.Write = pte->Write; 168 | PTEToCopy.Supervisor = pte->Supervisor; 169 | PTEToCopy.PageLevelWriteThrough = pte->PageLevelWriteThrough; 170 | PTEToCopy.PageLevelCacheDisable = pte->PageLevelCacheDisable; 171 | PTEToCopy.Accessed = pte->Accessed; 172 | PTEToCopy.Dirty = pte->Dirty; 173 | PTEToCopy.Pat = pte->Pat; 174 | PTEToCopy.Global = pte->Global; 175 | PTEToCopy.CopyOnWrite = pte->CopyOnWrite; 176 | PTEToCopy.Unused = pte->Unused; 177 | PTEToCopy.Write1 = pte->Write1; 178 | PTEToCopy.PageFrameNumber = pte->PageFrameNumber; 179 | PTEToCopy.Reserved1 = pte->Reserved1; 180 | PTEToCopy.Ignored2 = pte->Ignored2; 181 | PTEToCopy.ProtectionKey = pte->ProtectionKey; 182 | PTEToCopy.ExecuteDisable = pte->ExecuteDisable; 183 | PTEToCopy.Flags = pte->Flags; 184 | } 185 | KeUnstackDetachProcess(&state); 186 | MemoryUtils::SafeCopy(Message->pOut, &PTEToCopy, sizeof(PTE_64)); 187 | } 188 | 189 | ObDereferenceObject(Process); 190 | 191 | return STATUS_SUCCESS; 192 | } 193 | 194 | NTSTATUS 195 | API::SetPte( 196 | CONST PSET_PTE Message 197 | ) { 198 | PEPROCESS Process = NULL; 199 | if (NT_SUCCESS(PsLookupProcessByProcessId(Message->ProcessId, &Process))) { 200 | KeAttachProcess(Process); 201 | CR3 cr3{}; 202 | cr3.Flags = __readcr3(); 203 | PTE_64* pte = (PTE_64*)MemoryUtils::GetPte(Message->Address, cr3); 204 | if (pte) { 205 | if (pte->Present) { 206 | pte->Present = Message->Pte.Present; 207 | pte->Write = Message->Pte.Write; 208 | pte->Supervisor = Message->Pte.Supervisor; 209 | pte->PageLevelWriteThrough = Message->Pte.PageLevelWriteThrough; 210 | pte->PageLevelCacheDisable = Message->Pte.PageLevelCacheDisable; 211 | pte->Accessed = Message->Pte.Accessed; 212 | pte->Dirty = Message->Pte.Dirty; 213 | pte->Pat = Message->Pte.Pat; 214 | pte->Global = Message->Pte.Global; 215 | pte->CopyOnWrite = Message->Pte.Global; 216 | pte->Unused = Message->Pte.Unused; 217 | pte->Write1 = Message->Pte.Write1; 218 | pte->PageFrameNumber = Message->Pte.PageFrameNumber; 219 | pte->Reserved1 = Message->Pte.Reserved1; 220 | pte->Ignored2 = Message->Pte.Ignored2; 221 | pte->ProtectionKey = Message->Pte.ProtectionKey; 222 | pte->ExecuteDisable = Message->Pte.ExecuteDisable; 223 | pte->Flags = Message->Pte.Flags; 224 | } 225 | } 226 | KeDetachProcess(); 227 | } 228 | 229 | ObDereferenceObject(Process); 230 | 231 | return STATUS_SUCCESS; 232 | } 233 | 234 | NTSTATUS 235 | API::QueryVirtualMemory( 236 | CONST PQUERY_VIRTUAL_MEMORY Message 237 | ) { 238 | PEPROCESS Process = NULL; 239 | if (!NT_SUCCESS(PsLookupProcessByProcessId(Message->ProcessId, &Process))) { 240 | return STATUS_UNSUCCESSFUL; 241 | } 242 | MEMORY_BASIC_INFORMATION Mbi; 243 | 244 | KeAttachProcess(Process); 245 | ZwQueryVirtualMemory(NtCurrentProcess(), Message->Address, MemoryBasicInformation, &Mbi, sizeof(Mbi), NULL); 246 | KeDetachProcess(); 247 | 248 | MemoryUtils::SafeCopy(Message->pOut, &Mbi, sizeof(Mbi)); 249 | 250 | return STATUS_SUCCESS; 251 | } 252 | 253 | NTSTATUS 254 | API::GetVADFlags( 255 | CONST PGET_VAD_FLAGS Message 256 | ) { 257 | PEPROCESS Process = NULL; 258 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 259 | if (!NT_SUCCESS(Status)) { 260 | ObDereferenceObject(Process); 261 | return STATUS_UNSUCCESSFUL; 262 | } 263 | 264 | PMMVAD_SHORT pVadShort = NULL; 265 | Status = MemoryUtils::FindVAD(Process, (ULONGLONG)Message->Address, &pVadShort); 266 | 267 | if (NT_SUCCESS(Status)) { 268 | MemoryUtils::SafeCopy(Message->pOut, &pVadShort->u.VadFlags, sizeof(MMVAD_FLAGS)); 269 | } 270 | 271 | ObDereferenceObject(Process); 272 | return Status; 273 | } 274 | 275 | NTSTATUS 276 | API::SetVADFlags( 277 | CONST PSET_VAD_FLAGS Message 278 | ) { 279 | PEPROCESS Process = NULL; 280 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 281 | if (!NT_SUCCESS(Status)) { 282 | ObDereferenceObject(Process); 283 | return STATUS_UNSUCCESSFUL; 284 | } 285 | 286 | PMMVAD_SHORT pVadShort = NULL; 287 | Status = MemoryUtils::FindVAD(Process, (ULONGLONG)Message->Address, &pVadShort); 288 | 289 | if (NT_SUCCESS(Status)) { 290 | pVadShort->u.VadFlags.Lock = Message->VADFlags.Lock; 291 | pVadShort->u.VadFlags.LockContended = Message->VADFlags.LockContended; 292 | pVadShort->u.VadFlags.DeleteInProgress = Message->VADFlags.DeleteInProgress; 293 | pVadShort->u.VadFlags.NoChange = Message->VADFlags.NoChange; 294 | pVadShort->u.VadFlags.VadType = Message->VADFlags.VadType; 295 | pVadShort->u.VadFlags.Protection = Message->VADFlags.Protection; 296 | pVadShort->u.VadFlags.PreferredNode = Message->VADFlags.PreferredNode; 297 | pVadShort->u.VadFlags.PageSize = Message->VADFlags.PageSize; 298 | pVadShort->u.VadFlags.PrivateMemory = Message->VADFlags.PrivateMemory; 299 | } 300 | 301 | ObDereferenceObject(Process); 302 | return Status; 303 | } 304 | 305 | NTSTATUS 306 | API::RemoveVADNode( 307 | CONST PREMOVE_VAD Message 308 | ) { 309 | PEPROCESS Process = NULL; 310 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 311 | if (!NT_SUCCESS(Status)) { 312 | ObDereferenceObject(Process); 313 | return STATUS_UNSUCCESSFUL; 314 | } 315 | 316 | PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)Process + 0x7d8); 317 | 318 | PMMVAD_SHORT pVadShort = NULL; 319 | Status = MemoryUtils::FindVAD(Process, (ULONGLONG)Message->Address, &pVadShort); 320 | 321 | RtlAvlRemoveNode(pTable, reinterpret_cast(pVadShort)); 322 | 323 | return STATUS_SUCCESS; 324 | } 325 | 326 | NTSTATUS 327 | API::AllocateVad( 328 | CONST PALLOCATE_VAD Message 329 | ) { 330 | 331 | if (!MiAllocateVad) { 332 | MiAllocateVad = (PMMVAD_SHORT(*)(UINT_PTR, UINT_PTR, LOGICAL))MemoryUtils::FindPatternImage((PCHAR)MemoryUtils::GetKernelBase(), MI_ALLOCATE_VAD_PATTERN, MI_ALLOCATE_VAD_MASK); 333 | if (!MiAllocateVad) { 334 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MiAllocateVad not found"); 335 | return STATUS_UNSUCCESSFUL; 336 | } 337 | } 338 | 339 | if (!MiInsertVadCharges) { 340 | MiInsertVadCharges = (NTSTATUS(*)(PMMVAD_SHORT, PEPROCESS))MemoryUtils::FindPatternImage((PCHAR)MemoryUtils::GetKernelBase(), MI_INSERT_VAD_CHANGES_PATTERN, MI_INSERT_VAD_CHANGES_MASK); 341 | if (!MiInsertVadCharges) { 342 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MiInsertVadCharges not found"); 343 | return STATUS_UNSUCCESSFUL; 344 | } 345 | } 346 | 347 | if (!MiInsertVad) { 348 | MiInsertVad = (VOID(*)(PMMVAD_SHORT, PEPROCESS))MemoryUtils::FindPatternImage((PCHAR)MemoryUtils::GetKernelBase(), MI_INSERT_VAD_PATTERN, MI_INSERT_VAD_MASK); 349 | if (!MiInsertVad) { 350 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MiInsertVad not found"); 351 | return STATUS_UNSUCCESSFUL; 352 | } 353 | } 354 | 355 | PEPROCESS Process = NULL; 356 | NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)Message->ProcessId, &Process); 357 | if (!NT_SUCCESS(Status)) { 358 | ObDereferenceObject(Process); 359 | return STATUS_UNSUCCESSFUL; 360 | } 361 | 362 | ULONGLONG Start = (ULONGLONG)Message->Address; 363 | ULONGLONG End = (ULONGLONG)Message->Address + Message->Size; 364 | 365 | KeAttachProcess(Process); 366 | 367 | MEMORY_BASIC_INFORMATION MBI{}; 368 | if (!NT_SUCCESS(ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)Start, MemoryBasicInformation, &MBI, sizeof(MBI), NULL))) { 369 | return STATUS_UNSUCCESSFUL; 370 | } 371 | 372 | PMMVAD_SHORT VAD = MiAllocateVad(Start, End, TRUE); 373 | if (!VAD) { 374 | return STATUS_UNSUCCESSFUL; 375 | } 376 | 377 | PMMVAD_FLAGS Flags = (PMMVAD_FLAGS)&VAD->u.LongFlags; 378 | Flags->Protection = (6); 379 | Flags->NoChange = 0; 380 | 381 | if (!NT_SUCCESS(MiInsertVadCharges(VAD, Process))) { 382 | ExFreePool(VAD); 383 | return STATUS_UNSUCCESSFUL; 384 | } 385 | 386 | MiInsertVad(VAD, Process); 387 | 388 | KeDetachProcess(); 389 | 390 | ObDereferenceObject(Process); 391 | 392 | return STATUS_SUCCESS; 393 | } 394 | -------------------------------------------------------------------------------- /Driver/API.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "Communication/CommunicationType.h" 5 | 6 | namespace API { 7 | 8 | NTSTATUS 9 | ReadMemory( 10 | CONST PREAD_MEMORY Message 11 | ); 12 | 13 | NTSTATUS 14 | WriteMemory( 15 | CONST PWRITE_MEMORY Message 16 | ); 17 | 18 | NTSTATUS 19 | ProtectMemory( 20 | CONST PPROTECT_MEMORY Message 21 | ); 22 | 23 | NTSTATUS 24 | AllocMemory( 25 | CONST PALLOC_MEMORY Message 26 | ); 27 | 28 | NTSTATUS 29 | FreeMemory( 30 | CONST PFREE_MEMORY Message 31 | ); 32 | 33 | NTSTATUS 34 | GetPte( 35 | CONST PGET_PTE Message 36 | ); 37 | 38 | NTSTATUS 39 | SetPte( 40 | CONST PSET_PTE Message 41 | ); 42 | 43 | NTSTATUS 44 | QueryVirtualMemory( 45 | CONST PQUERY_VIRTUAL_MEMORY Message 46 | ); 47 | 48 | NTSTATUS 49 | GetVADFlags( 50 | CONST PGET_VAD_FLAGS Message 51 | ); 52 | 53 | NTSTATUS 54 | SetVADFlags( 55 | CONST PSET_VAD_FLAGS Message 56 | ); 57 | 58 | NTSTATUS 59 | RemoveVADNode( 60 | CONST PREMOVE_VAD Message 61 | ); 62 | 63 | NTSTATUS 64 | AllocateVad( 65 | CONST PALLOCATE_VAD Message 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /Driver/Communication/Communication.cpp: -------------------------------------------------------------------------------- 1 | #include "Communication.h" 2 | #include "CommunicationType.h" 3 | #include "../Utils/MemoryUtils.h" 4 | #include "../API.h" 5 | #include "../Define/Patterns.h" 6 | #include "../Library/skCrypter.h" 7 | 8 | #define DATA_UNIQUE (0x8392) 9 | #define RELATIVE_ADDR(addr, size) ((PVOID)((PBYTE)(addr) + *(PINT)((PBYTE)(addr) + ((size) - (INT)sizeof(INT))) + (size))) 10 | 11 | INT64(NTAPI* EnumerateDebuggingDevicesOriginal)(PVOID, PVOID); 12 | INT64(__fastcall* HvlpQueryApicIdAndNumaNodeOriginal)(PVOID, PVOID, PVOID); 13 | INT64(__fastcall* HvlpQueryProcessorNodeOriginal)(PVOID, PVOID, PVOID); 14 | 15 | INT64 NTAPI 16 | hkHvlpQueryApicIdAndNumaNode( 17 | PREQUEST_DATA Data, 18 | PINT64 Status, 19 | PVOID a3 20 | ) { 21 | REQUEST_DATA SafeData = { 0 }; 22 | if (!MemoryUtils::SafeCopy(&SafeData, Data, sizeof(SafeData)) || SafeData.Unique != DATA_UNIQUE) { 23 | return EnumerateDebuggingDevicesOriginal(Data, Status); 24 | } 25 | 26 | switch (SafeData.Type) { 27 | case REQUEST_READ_MEMORY: { 28 | READ_MEMORY Args; 29 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 30 | *Status = STATUS_ACCESS_VIOLATION; 31 | return 0; 32 | } 33 | *Status = API::ReadMemory(&Args); 34 | return 0; 35 | } 36 | 37 | case REQUEST_WRITE_MEMORY: { 38 | WRITE_MEMORY Args; 39 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 40 | *Status = STATUS_ACCESS_VIOLATION; 41 | return 0; 42 | } 43 | *Status = API::WriteMemory(&Args); 44 | return 0; 45 | } 46 | 47 | case REQUEST_PROTECT_MEMORY: { 48 | PROTECT_MEMORY Args; 49 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 50 | *Status = STATUS_ACCESS_VIOLATION; 51 | return 0; 52 | } 53 | *Status = API::ProtectMemory(&Args); 54 | return 0; 55 | } 56 | 57 | case REQUEST_ALLOC_MEMORY: { 58 | ALLOC_MEMORY Args; 59 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 60 | *Status = STATUS_ACCESS_VIOLATION; 61 | return 0; 62 | } 63 | *Status = API::AllocMemory(&Args); 64 | return 0; 65 | } 66 | 67 | case REQUEST_FREE_MEMORY: { 68 | FREE_MEMORY Args; 69 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 70 | *Status = STATUS_ACCESS_VIOLATION; 71 | return 0; 72 | } 73 | *Status = API::FreeMemory(&Args); 74 | return 0; 75 | } 76 | 77 | case REQUEST_GET_PTE: { 78 | GET_PTE Args; 79 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 80 | *Status = STATUS_ACCESS_VIOLATION; 81 | return 0; 82 | } 83 | *Status = API::GetPte(&Args); 84 | return 0; 85 | } 86 | 87 | case REQUEST_SET_PTE: { 88 | SET_PTE Args; 89 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 90 | *Status = STATUS_ACCESS_VIOLATION; 91 | return 0; 92 | } 93 | *Status = API::SetPte(&Args); 94 | return 0; 95 | } 96 | 97 | case REQUEST_QUERY_VIRTUAL_MEMORY: { 98 | QUERY_VIRTUAL_MEMORY Args; 99 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 100 | *Status = STATUS_ACCESS_VIOLATION; 101 | return 0; 102 | } 103 | *Status = API::QueryVirtualMemory(&Args); 104 | return 0; 105 | } 106 | 107 | case REQUEST_GET_VAD_FLAGS: { 108 | GET_VAD_FLAGS Args; 109 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 110 | *Status = STATUS_ACCESS_VIOLATION; 111 | return 0; 112 | } 113 | *Status = API::GetVADFlags(&Args); 114 | return 0; 115 | } 116 | 117 | case REQUEST_SET_VAD_FLAGS: { 118 | SET_VAD_FLAGS Args; 119 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 120 | *Status = STATUS_ACCESS_VIOLATION; 121 | return 0; 122 | } 123 | *Status = API::SetVADFlags(&Args); 124 | return 0; 125 | } 126 | 127 | case REQUEST_REMOVE_VAD_NODE: { 128 | REMOVE_VAD Args; 129 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 130 | *Status = STATUS_ACCESS_VIOLATION; 131 | return 0; 132 | } 133 | *Status = API::RemoveVADNode(&Args); 134 | return 0; 135 | } 136 | 137 | case REQUEST_ALLOC_VAD: { 138 | ALLOCATE_VAD Args; 139 | if (!MemoryUtils::SafeCopy(&Args, SafeData.Arguments, sizeof(Args))) { 140 | *Status = STATUS_ACCESS_VIOLATION; 141 | return 0; 142 | } 143 | *Status = API::AllocateVad(&Args); 144 | return 0; 145 | } 146 | } 147 | 148 | *Status = STATUS_NOT_IMPLEMENTED; 149 | return 0; 150 | } 151 | 152 | NTSTATUS 153 | Communication::Initialize() { 154 | PCHAR Base = (PCHAR)MemoryUtils::GetKernelBase(); 155 | 156 | auto xKdEnumerateDebuggingDevicesPattern = skCrypt(KD_ENUMERATE_DEBUGGING_DEVICES_PATTERN); 157 | auto xKdEnumerateDebuggingDevicesMask = skCrypt(KD_ENUMERATE_DEBUGGING_DEVICES_MASK); 158 | PBYTE FunctionAddress = (PBYTE)MemoryUtils::FindPatternImage(Base, xKdEnumerateDebuggingDevicesPattern, xKdEnumerateDebuggingDevicesMask); 159 | xKdEnumerateDebuggingDevicesPattern.clear(); 160 | xKdEnumerateDebuggingDevicesMask.clear(); 161 | if (!FunctionAddress) { 162 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "failed to get xKdEnumerateDebuggingDevices"); 163 | return STATUS_UNSUCCESSFUL; 164 | } 165 | 166 | auto HvlpQueryApicIdAndNumaNodePattern = skCrypt(HVLP_QUERY_APIC_ID_AND_NUMA_NODE_PATTERN); 167 | auto HvlpQueryApicIdAndNumaNodeMask = skCrypt(HVLP_QUERY_APIC_ID_AND_NUMA_NODE_MASK); 168 | PBYTE HvlpQueryApicIdAndNumaNodeAddress = (PBYTE)MemoryUtils::FindPatternImage(Base, HvlpQueryApicIdAndNumaNodePattern, HvlpQueryApicIdAndNumaNodeMask); 169 | HvlpQueryApicIdAndNumaNodePattern.clear(); 170 | HvlpQueryApicIdAndNumaNodeMask.clear(); 171 | if (!HvlpQueryApicIdAndNumaNodeAddress) { 172 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "failed to get HvlpQueryApicIdAndNumaNodeAddress"); 173 | return STATUS_UNSUCCESSFUL; 174 | } 175 | 176 | auto HvlpQueryApicIdAndNumaNodeCallPattern = skCrypt(HVLP_QUERY_APIC_ID_AND_NUMA_NODE_CALL_PATTERN); 177 | auto HvlpQueryApicIdAndNumaNodeCallMask = skCrypt(HVLP_QUERY_APIC_ID_AND_NUMA_NODE_CALL_MASK); 178 | PBYTE HvlpQueryApicIdAndNumaNodeCallAddress = (PBYTE)MemoryUtils::FindPatternImage(Base, HvlpQueryApicIdAndNumaNodeCallPattern, HvlpQueryApicIdAndNumaNodeCallMask); 179 | HvlpQueryApicIdAndNumaNodeCallPattern.clear(); 180 | HvlpQueryApicIdAndNumaNodeCallMask.clear(); 181 | if (!HvlpQueryApicIdAndNumaNodeAddress) { 182 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "failed to get HvlpQueryApicIdAndNumaNodeCallAddress"); 183 | return STATUS_UNSUCCESSFUL; 184 | } 185 | 186 | *(PVOID*)&HvlpQueryApicIdAndNumaNodeOriginal = InterlockedExchangePointer((volatile PVOID*)RELATIVE_ADDR(HvlpQueryApicIdAndNumaNodeAddress, 7), (PVOID)hkHvlpQueryApicIdAndNumaNode); 187 | *(PVOID*)&EnumerateDebuggingDevicesOriginal = InterlockedExchangePointer((volatile PVOID*)RELATIVE_ADDR(FunctionAddress, 7), (PVOID)HvlpQueryApicIdAndNumaNodeCallAddress); 188 | 189 | return STATUS_SUCCESS; 190 | } -------------------------------------------------------------------------------- /Driver/Communication/Communication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Communication { 5 | NTSTATUS 6 | Initialize(); 7 | } 8 | -------------------------------------------------------------------------------- /Driver/Communication/CommunicationType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "../Define/IA32.h" 5 | #include "../Define/NT.h" 6 | 7 | typedef struct _READ_MEMORY { 8 | HANDLE ProcessId; 9 | DWORD64 Address; 10 | ULONG Size; 11 | PVOID pOut; 12 | } READ_MEMORY, * PREAD_MEMORY; 13 | 14 | typedef struct _WRITE_MEMORY { 15 | HANDLE ProcessId; 16 | DWORD64 Address; 17 | ULONG Size; 18 | PVOID pSrc; 19 | } WRITE_MEMORY, * PWRITE_MEMORY; 20 | 21 | typedef struct _PROTECT_MEMORY { 22 | HANDLE ProcessId; 23 | PVOID Address; 24 | DWORD Size; 25 | PVOID InOutProtect; 26 | } PROTECT_MEMORY, * PPROTECT_MEMORY; 27 | 28 | typedef struct _ALLOC_MEMORY { 29 | HANDLE ProcessId; 30 | PVOID pOut; 31 | DWORD Size; 32 | DWORD Protect; 33 | } ALLOC_MEMORY, * PALLOC_MEMORY; 34 | 35 | typedef struct _FREE_MEMORY { 36 | HANDLE ProcessId; 37 | PVOID Address; 38 | } FREE_MEMORY, * PFREE_MEMORY; 39 | 40 | typedef struct _GET_PTE { 41 | HANDLE ProcessId; 42 | PVOID Address; 43 | PTE_64* pOut; 44 | } GET_PTE, * PGET_PTE; 45 | 46 | typedef struct _SET_PTE { 47 | HANDLE ProcessId; 48 | PVOID Address; 49 | PTE_64 Pte; 50 | } SET_PTE, * PSET_PTE; 51 | 52 | typedef struct _QUERY_VIRTUAL_MEMORY { 53 | HANDLE ProcessId; 54 | PVOID Address; 55 | PVOID pOut; 56 | } QUERY_VIRTUAL_MEMORY, * PQUERY_VIRTUAL_MEMORY; 57 | 58 | typedef struct _GET_VAD_FLAGS { 59 | HANDLE ProcessId; 60 | PVOID Address; 61 | PVOID pOut; 62 | } GET_VAD_FLAGS, * PGET_VAD_FLAGS; 63 | 64 | typedef struct _SET_VAD_FLAGS { 65 | HANDLE ProcessId; 66 | PVOID Address; 67 | MMVAD_FLAGS VADFlags; 68 | } SET_VAD_FLAGS, * PSET_VAD_FLAGS; 69 | 70 | typedef struct _REMOVE_VAD { 71 | HANDLE ProcessId; 72 | PVOID Address; 73 | } REMOVE_VAD, * PREMOVE_VAD; 74 | 75 | typedef struct _ALLOCATE_VAD { 76 | HANDLE ProcessId; 77 | PVOID Address; 78 | ULONGLONG Size; 79 | ULONG Protection; 80 | } ALLOCATE_VAD, * PALLOCATE_VAD; 81 | 82 | typedef enum _REQUEST_TYPE { 83 | REQUEST_READ_MEMORY, 84 | REQUEST_WRITE_MEMORY, 85 | REQUEST_PROTECT_MEMORY, 86 | REQUEST_ALLOC_MEMORY, 87 | REQUEST_FREE_MEMORY, 88 | REQUEST_GET_PTE, 89 | REQUEST_SET_PTE, 90 | REQUEST_QUERY_VIRTUAL_MEMORY, 91 | REQUEST_GET_VAD_FLAGS, 92 | REQUEST_SET_VAD_FLAGS, 93 | REQUEST_REMOVE_VAD_NODE, 94 | REQUEST_ALLOC_VAD 95 | } REQUEST_TYPE; 96 | 97 | typedef struct _REQUEST_DATA { 98 | DWORD Unique; 99 | REQUEST_TYPE Type; 100 | PVOID Arguments; 101 | } REQUEST_DATA, * PREQUEST_DATA; 102 | -------------------------------------------------------------------------------- /Driver/Define/CRT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | static char* stristr(const char* str1, const char* str2) { 5 | const char* p1 = str1; 6 | const char* p2 = str2; 7 | const char* r = *p2 == 0 ? str1 : 0; 8 | 9 | while (*p1 != 0 && *p2 != 0) 10 | { 11 | if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 12 | { 13 | if (r == 0) 14 | { 15 | r = p1; 16 | } 17 | 18 | p2++; 19 | } 20 | else 21 | { 22 | p2 = str2; 23 | if (r != 0) 24 | { 25 | p1 = r + 1; 26 | } 27 | 28 | if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 29 | { 30 | r = p1; 31 | p2++; 32 | } 33 | else 34 | { 35 | r = 0; 36 | } 37 | } 38 | 39 | p1++; 40 | } 41 | 42 | return *p2 == 0 ? (char*)r : 0; 43 | } -------------------------------------------------------------------------------- /Driver/Define/NT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #define WINDOWS_1803 17134 7 | #define WINDOWS_1809 17763 8 | #define WINDOWS_1903 18362 9 | #define WINDOWS_1909 18363 10 | #define WINDOWS_2004 19041 11 | #define WINDOWS_20H2 19569 12 | #define WINDOWS_21H1 20180 13 | 14 | typedef struct _MM_AVL_NODE // Size=24 15 | { 16 | struct _MM_AVL_NODE* LeftChild; // Size=8 Offset=0 17 | struct _MM_AVL_NODE* RightChild; // Size=8 Offset=8 18 | 19 | union ___unnamed1666 // Size=8 20 | { 21 | struct 22 | { 23 | __int64 Balance : 2; // Size=8 Offset=0 BitOffset=0 BitCount=2 24 | }; 25 | struct _MM_AVL_NODE* Parent; // Size=8 Offset=0 26 | } u1; 27 | } MM_AVL_NODE, * PMM_AVL_NODE, * PMMADDRESS_NODE; 28 | 29 | typedef struct _RTL_AVL_TREE // Size=8 30 | { 31 | PMM_AVL_NODE BalancedRoot; 32 | void* NodeHint; 33 | unsigned __int64 NumberGenericTableElements; 34 | } RTL_AVL_TREE, * PRTL_AVL_TREE, MM_AVL_TABLE, * PMM_AVL_TABLE; 35 | 36 | union _EX_PUSH_LOCK // Size=8 37 | { 38 | struct 39 | { 40 | unsigned __int64 Locked : 1; // Size=8 Offset=0 BitOffset=0 BitCount=1 41 | unsigned __int64 Waiting : 1; // Size=8 Offset=0 BitOffset=1 BitCount=1 42 | unsigned __int64 Waking : 1; // Size=8 Offset=0 BitOffset=2 BitCount=1 43 | unsigned __int64 MultipleShared : 1; // Size=8 Offset=0 BitOffset=3 BitCount=1 44 | unsigned __int64 Shared : 60; // Size=8 Offset=0 BitOffset=4 BitCount=60 45 | }; 46 | unsigned __int64 Value; // Size=8 Offset=0 47 | void* Ptr; // Size=8 Offset=0 48 | }; 49 | 50 | typedef struct _MMVAD_FLAGS { 51 | ULONG Lock : 1; //0x0 52 | ULONG LockContended : 1; //0x0 53 | ULONG DeleteInProgress : 1; //0x0 54 | ULONG NoChange : 1; //0x0 55 | ULONG VadType : 3; //0x0 56 | ULONG Protection : 5; //0x0 57 | ULONG PreferredNode : 6; //0x0 58 | ULONG PageSize : 2; //0x0 59 | ULONG PrivateMemory : 1; //0x0 60 | } MMVAD_FLAGS, * PMMVAD_FLAGS; 61 | 62 | struct _MMVAD_FLAGS1 // Size=4 63 | { 64 | unsigned long CommitCharge : 31; // Size=4 Offset=0 BitOffset=0 BitCount=31 65 | unsigned long MemCommit : 1; // Size=4 Offset=0 BitOffset=31 BitCount=1 66 | }; 67 | 68 | struct _MMVAD_FLAGS2 // Size=4 69 | { 70 | unsigned long FileOffset : 24; // Size=4 Offset=0 BitOffset=0 BitCount=24 71 | unsigned long Large : 1; // Size=4 Offset=0 BitOffset=24 BitCount=1 72 | unsigned long TrimBehind : 1; // Size=4 Offset=0 BitOffset=25 BitCount=1 73 | unsigned long Inherit : 1; // Size=4 Offset=0 BitOffset=26 BitCount=1 74 | unsigned long CopyOnWrite : 1; // Size=4 Offset=0 BitOffset=27 BitCount=1 75 | unsigned long NoValidationNeeded : 1; // Size=4 Offset=0 BitOffset=28 BitCount=1 76 | unsigned long Spare : 3; // Size=4 Offset=0 BitOffset=29 BitCount=3 77 | }; 78 | 79 | struct _MI_VAD_SEQUENTIAL_INFO // Size=8 80 | { 81 | unsigned __int64 Length : 12; // Size=8 Offset=0 BitOffset=0 BitCount=12 82 | unsigned __int64 Vpn : 52; // Size=8 Offset=0 BitOffset=12 BitCount=52 83 | }; 84 | 85 | union ___unnamed1951 // Size=4 86 | { 87 | unsigned long LongFlags; // Size=4 Offset=0 88 | struct _MMVAD_FLAGS VadFlags; // Size=4 Offset=0 89 | }; 90 | 91 | union ___unnamed1952 // Size=4 92 | { 93 | unsigned long LongFlags1; // Size=4 Offset=0 94 | struct _MMVAD_FLAGS1 VadFlags1; // Size=4 Offset=0 95 | }; 96 | 97 | union ___unnamed2047 // Size=4 98 | { 99 | unsigned long LongFlags2; // Size=4 Offset=0 100 | struct _MMVAD_FLAGS2 VadFlags2; // Size=4 Offset=0 101 | }; 102 | 103 | union ___unnamed2048 // Size=8 104 | { 105 | struct _MI_VAD_SEQUENTIAL_INFO SequentialVa; // Size=8 Offset=0 106 | struct _MMEXTEND_INFO* ExtendedInfo; // Size=8 Offset=0 107 | }; 108 | 109 | typedef struct _MMVAD_SHORT 110 | { 111 | union 112 | { 113 | struct 114 | { 115 | struct _MMVAD_SHORT* NextVad; //0x0 116 | VOID* ExtraCreateInfo; //0x8 117 | }; 118 | struct _RTL_BALANCED_NODE VadNode; //0x0 119 | }; 120 | ULONG StartingVpn; //0x18 121 | ULONG EndingVpn; //0x1c 122 | UCHAR StartingVpnHigh; //0x20 123 | UCHAR EndingVpnHigh; //0x21 124 | UCHAR CommitChargeHigh; //0x22 125 | UCHAR SpareNT64VadUChar; //0x23 126 | LONG ReferenceCount; //0x24 127 | union _EX_PUSH_LOCK PushLock; //0x28 128 | union ___unnamed1951 u; // Size=4 Offset=48 129 | union ___unnamed1952 u1; // Size=4 Offset=52 //0x34 130 | struct _MI_VAD_EVENT_BLOCK* EventList; //0x38 131 | } MMVAD_SHORT, * PMMVAD_SHORT; 132 | 133 | typedef struct _MMVAD // Size=128 134 | { 135 | struct _MMVAD_SHORT Core; // Size=64 Offset=0 136 | union ___unnamed2047 u2; // Size=4 Offset=64 137 | unsigned long pad0; // Size=4 Offset=68 138 | struct _SUBSECTION* Subsection; // Size=8 Offset=72 139 | struct _MMPTE* FirstPrototypePte; // Size=8 Offset=80 140 | struct _MMPTE* LastContiguousPte; // Size=8 Offset=88 141 | struct _LIST_ENTRY ViewLinks; // Size=16 Offset=96 142 | struct _EPROCESS* VadsProcess; // Size=8 Offset=112 143 | union ___unnamed2048 u4; // Size=8 Offset=120 144 | struct _FILE_OBJECT* FileObject; // Size=8 Offset=128 145 | } MMVAD, * PMMVAD; 146 | 147 | typedef struct _SYSTEM_MODULE { 148 | HANDLE Section; 149 | PVOID MappedBase; 150 | PVOID ImageBase; 151 | ULONG ImageSize; 152 | ULONG Flags; 153 | USHORT LoadOrderIndex; 154 | USHORT InitOrderIndex; 155 | USHORT LoadCount; 156 | USHORT OffsetToFileName; 157 | UCHAR FullPathName[MAXIMUM_FILENAME_LENGTH]; 158 | } SYSTEM_MODULE, * PSYSTEM_MODULE; 159 | 160 | typedef struct _SYSTEM_MODULE_INFORMATION { 161 | ULONG NumberOfModules; 162 | SYSTEM_MODULE Modules[1]; 163 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; 164 | 165 | 166 | typedef enum _SYSTEM_INFORMATION_CLASS { 167 | SystemBasicInformation = 0x0, 168 | SystemProcessorInformation = 0x1, 169 | SystemPerformanceInformation = 0x2, 170 | SystemTimeOfDayInformation = 0x3, 171 | SystemPathInformation = 0x4, 172 | SystemProcessInformation = 0x5, 173 | SystemCallCountInformation = 0x6, 174 | SystemDeviceInformation = 0x7, 175 | SystemProcessorPerformanceInformation = 0x8, 176 | SystemFlagsInformation = 0x9, 177 | SystemCallTimeInformation = 0xa, 178 | SystemModuleInformation = 0xb, 179 | SystemLocksInformation = 0xc, 180 | SystemStackTraceInformation = 0xd, 181 | SystemPagedPoolInformation = 0xe, 182 | SystemNonPagedPoolInformation = 0xf, 183 | SystemHandleInformation = 0x10, 184 | SystemObjectInformation = 0x11, 185 | SystemPageFileInformation = 0x12, 186 | SystemVdmInstemulInformation = 0x13, 187 | SystemVdmBopInformation = 0x14, 188 | SystemFileCacheInformation = 0x15, 189 | SystemPoolTagInformation = 0x16, 190 | SystemInterruptInformation = 0x17, 191 | SystemDpcBehaviorInformation = 0x18, 192 | SystemFullMemoryInformation = 0x19, 193 | SystemLoadGdiDriverInformation = 0x1a, 194 | SystemUnloadGdiDriverInformation = 0x1b, 195 | SystemTimeAdjustmentInformation = 0x1c, 196 | SystemSummaryMemoryInformation = 0x1d, 197 | SystemMirrorMemoryInformation = 0x1e, 198 | SystemPerformanceTraceInformation = 0x1f, 199 | SystemObsolete0 = 0x20, 200 | SystemExceptionInformation = 0x21, 201 | SystemCrashDumpStateInformation = 0x22, 202 | SystemKernelDebuggerInformation = 0x23, 203 | SystemContextSwitchInformation = 0x24, 204 | SystemRegistryQuotaInformation = 0x25, 205 | SystemExtendServiceTableInformation = 0x26, 206 | SystemPrioritySeperation = 0x27, 207 | SystemVerifierAddDriverInformation = 0x28, 208 | SystemVerifierRemoveDriverInformation = 0x29, 209 | SystemProcessorIdleInformation = 0x2a, 210 | SystemLegacyDriverInformation = 0x2b, 211 | SystemCurrentTimeZoneInformation = 0x2c, 212 | SystemLookasideInformation = 0x2d, 213 | SystemTimeSlipNotification = 0x2e, 214 | SystemSessionCreate = 0x2f, 215 | SystemSessionDetach = 0x30, 216 | SystemSessionInformation = 0x31, 217 | SystemRangeStartInformation = 0x32, 218 | SystemVerifierInformation = 0x33, 219 | SystemVerifierThunkExtend = 0x34, 220 | SystemSessionProcessInformation = 0x35, 221 | SystemLoadGdiDriverInSystemSpace = 0x36, 222 | SystemNumaProcessorMap = 0x37, 223 | SystemPrefetcherInformation = 0x38, 224 | SystemExtendedProcessInformation = 0x39, 225 | SystemRecommendedSharedDataAlignment = 0x3a, 226 | SystemComPlusPackage = 0x3b, 227 | SystemNumaAvailableMemory = 0x3c, 228 | SystemProcessorPowerInformation = 0x3d, 229 | SystemEmulationBasicInformation = 0x3e, 230 | SystemEmulationProcessorInformation = 0x3f, 231 | SystemExtendedHandleInformation = 0x40, 232 | SystemLostDelayedWriteInformation = 0x41, 233 | SystemBigPoolInformation = 0x42, 234 | SystemSessionPoolTagInformation = 0x43, 235 | SystemSessionMappedViewInformation = 0x44, 236 | SystemHotpatchInformation = 0x45, 237 | SystemObjectSecurityMode = 0x46, 238 | SystemWatchdogTimerHandler = 0x47, 239 | SystemWatchdogTimerInformation = 0x48, 240 | SystemLogicalProcessorInformation = 0x49, 241 | SystemWow64SharedInformationObsolete = 0x4a, 242 | SystemRegisterFirmwareTableInformationHandler = 0x4b, 243 | SystemFirmwareTableInformation = 0x4c, 244 | SystemModuleInformationEx = 0x4d, 245 | SystemVerifierTriageInformation = 0x4e, 246 | SystemSuperfetchInformation = 0x4f, 247 | SystemMemoryListInformation = 0x50, 248 | SystemFileCacheInformationEx = 0x51, 249 | SystemThreadPriorityClientIdInformation = 0x52, 250 | SystemProcessorIdleCycleTimeInformation = 0x53, 251 | SystemVerifierCancellationInformation = 0x54, 252 | SystemProcessorPowerInformationEx = 0x55, 253 | SystemRefTraceInformation = 0x56, 254 | SystemSpecialPoolInformation = 0x57, 255 | SystemProcessIdInformation = 0x58, 256 | SystemErrorPortInformation = 0x59, 257 | SystemBootEnvironmentInformation = 0x5a, 258 | SystemHypervisorInformation = 0x5b, 259 | SystemVerifierInformationEx = 0x5c, 260 | SystemTimeZoneInformation = 0x5d, 261 | SystemImageFileExecutionOptionsInformation = 0x5e, 262 | SystemCoverageInformation = 0x5f, 263 | SystemPrefetchPatchInformation = 0x60, 264 | SystemVerifierFaultsInformation = 0x61, 265 | SystemSystemPartitionInformation = 0x62, 266 | SystemSystemDiskInformation = 0x63, 267 | SystemProcessorPerformanceDistribution = 0x64, 268 | SystemNumaProximityNodeInformation = 0x65, 269 | SystemDynamicTimeZoneInformation = 0x66, 270 | SystemCodeIntegrityInformation = 0x67, 271 | SystemProcessorMicrocodeUpdateInformation = 0x68, 272 | SystemProcessorBrandString = 0x69, 273 | SystemVirtualAddressInformation = 0x6a, 274 | SystemLogicalProcessorAndGroupInformation = 0x6b, 275 | SystemProcessorCycleTimeInformation = 0x6c, 276 | SystemStoreInformation = 0x6d, 277 | SystemRegistryAppendString = 0x6e, 278 | SystemAitSamplingValue = 0x6f, 279 | SystemVhdBootInformation = 0x70, 280 | SystemCpuQuotaInformation = 0x71, 281 | SystemNativeBasicInformation = 0x72, 282 | SystemErrorPortTimeouts = 0x73, 283 | SystemLowPriorityIoInformation = 0x74, 284 | SystemBootEntropyInformation = 0x75, 285 | SystemVerifierCountersInformation = 0x76, 286 | SystemPagedPoolInformationEx = 0x77, 287 | SystemSystemPtesInformationEx = 0x78, 288 | SystemNodeDistanceInformation = 0x79, 289 | SystemAcpiAuditInformation = 0x7a, 290 | SystemBasicPerformanceInformation = 0x7b, 291 | SystemQueryPerformanceCounterInformation = 0x7c, 292 | SystemSessionBigPoolInformation = 0x7d, 293 | SystemBootGraphicsInformation = 0x7e, 294 | SystemScrubPhysicalMemoryInformation = 0x7f, 295 | SystemBadPageInformation = 0x80, 296 | SystemProcessorProfileControlArea = 0x81, 297 | SystemCombinePhysicalMemoryInformation = 0x82, 298 | SystemEntropyInterruptTimingInformation = 0x83, 299 | SystemConsoleInformation = 0x84, 300 | SystemPlatformBinaryInformation = 0x85, 301 | SystemThrottleNotificationInformation = 0x86, 302 | SystemHypervisorProcessorCountInformation = 0x87, 303 | SystemDeviceDataInformation = 0x88, 304 | SystemDeviceDataEnumerationInformation = 0x89, 305 | SystemMemoryTopologyInformation = 0x8a, 306 | SystemMemoryChannelInformation = 0x8b, 307 | SystemBootLogoInformation = 0x8c, 308 | SystemProcessorPerformanceInformationEx = 0x8d, 309 | SystemSpare0 = 0x8e, 310 | SystemSecureBootPolicyInformation = 0x8f, 311 | SystemPageFileInformationEx = 0x90, 312 | SystemSecureBootInformation = 0x91, 313 | SystemEntropyInterruptTimingRawInformation = 0x92, 314 | SystemPortableWorkspaceEfiLauncherInformation = 0x93, 315 | SystemFullProcessInformation = 0x94, 316 | SystemKernelDebuggerInformationEx = 0x95, 317 | SystemBootMetadataInformation = 0x96, 318 | SystemSoftRebootInformation = 0x97, 319 | SystemElamCertificateInformation = 0x98, 320 | SystemOfflineDumpConfigInformation = 0x99, 321 | SystemProcessorFeaturesInformation = 0x9a, 322 | SystemRegistryReconciliationInformation = 0x9b, 323 | SystemSupportedProcessArchitectures = 0xb5, 324 | } SYSTEM_INFORMATION_CLASS; 325 | 326 | extern "C" { 327 | NTSYSAPI 328 | NTSTATUS 329 | NTAPI 330 | NtQuerySystemInformation( 331 | IN DWORD SystemInformationClass, 332 | OUT PVOID SystemInformation, 333 | IN ULONG SystemInformationLength, 334 | OUT PULONG ReturnLength 335 | ); 336 | 337 | NTSYSAPI 338 | NTSTATUS 339 | NTAPI 340 | MmCopyVirtualMemory( 341 | PEPROCESS SourceProcess, 342 | PVOID SourceAddress, 343 | PEPROCESS TargetProcess, 344 | PVOID TargetAddress, 345 | SIZE_T BufferSize, 346 | KPROCESSOR_MODE PreviousMode, 347 | PSIZE_T ReturnSize 348 | ); 349 | 350 | NTSYSAPI 351 | NTSTATUS 352 | WINAPI 353 | ZwQuerySystemInformation( 354 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 355 | IN OUT PVOID SystemInformation, 356 | IN ULONG SystemInformationLength, 357 | OUT OPTIONAL PULONG ReturnLength 358 | ); 359 | 360 | NTSYSAPI 361 | NTSTATUS 362 | NTAPI 363 | ZwProtectVirtualMemory( 364 | IN HANDLE ProcessHandle, 365 | IN OUT PVOID* BaseAddress, 366 | IN SIZE_T* NumberOfBytesToProtect, 367 | IN ULONG NewAccessProtection, 368 | OUT PULONG OldAccessProtection 369 | ); 370 | 371 | NTSYSAPI 372 | NTSTATUS 373 | NTAPI 374 | ObReferenceObjectByName( 375 | __in PUNICODE_STRING ObjectName, 376 | __in ULONG Attributes, 377 | __in_opt PACCESS_STATE AccessState, 378 | __in_opt ACCESS_MASK DesiredAccess, 379 | __in POBJECT_TYPE ObjectType, 380 | __in KPROCESSOR_MODE AccessMode, 381 | __inout_opt PVOID ParseContext, 382 | __out PVOID* Object 383 | ); 384 | 385 | NTSYSAPI 386 | PVOID 387 | NTAPI 388 | RtlAvlRemoveNode( 389 | IN PRTL_AVL_TREE pTree, 390 | IN PMMADDRESS_NODE pNode 391 | ); 392 | 393 | } 394 | -------------------------------------------------------------------------------- /Driver/Define/Patterns.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // *** Listed versions are not comprehensive 4 | 5 | // 1903, 1909, 20h1, 20h2, 21h1 6 | // 48 8D 0D ? ? ? ? E8 ? ? ? ? 4C 8B 8C 7 | #define PIDDB_LOCK_PATTERN "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C" 8 | #define PIDDB_LOCK_MASK "xxx????x????xxx" 9 | 10 | // 1903, 1909, 20h1, 20h2, 21h1 11 | // 66 03 D2 48 8D 0D 12 | #define PIDDB_TABLE_PATTERN "\x66\x03\xD2\x48\x8D\x0D" 13 | #define PIDDB_TABLE_MASK "xxxxxx" 14 | 15 | // 1903, 1909, 20h1, 20h2, 21h1 16 | // 4C 8B 15 ? ? ? ? 4C 8B C9 17 | #define MMU_PATTERN "\x4C\x8B\x15\x00\x00\x00\x00\x4C\x8B\xC9" 18 | #define MMU_MASK "xxx????xxx" 19 | 20 | // 1903, 1909, 20h1, 20h2, 21h1 21 | // 8B 05 ? ? ? ? 83 F8 32 22 | #define MML_PATTERN "\x8B\x05\x00\x00\x00\x00\x83\xF8\x32" 23 | #define MML_MASK "xx????xxx" 24 | 25 | // 1903, 1909, 20h1, 20h2, 21h1 26 | // 4C 8D 35 ? ? ? ? E9 ? ? ? ? 8B 84 24 27 | #define CI_DLL_KERNEL_HASH_BUCKET_PATTERN "\x4C\x8D\x35\x00\x00\x00\x00\xE9\x00\x00\x00\x00\x8B\x84\x24" 28 | #define CI_DLL_KERNEL_HASH_BUCKET_MASK "xxx????x????xxx" 29 | 30 | // 1903, 1909, 20h1, 20h2, 21h1 31 | // 48 8B 05 ? ? ? ? E8 ? ? ? ? 8B C8 85 C0 78 40 32 | #define KD_ENUMERATE_DEBUGGING_DEVICES_PATTERN "\x48\x8B\x05\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x8B\xC8\x85\xC0\x78\x40" 33 | #define KD_ENUMERATE_DEBUGGING_DEVICES_MASK "xxx????x????xxxxxx" 34 | 35 | // 1903, 1909, 20h1, 20h2, 21h1 36 | // 48 8B 05 ? ? ? ? 45 33 C0 E8 37 | #define HVLP_QUERY_APIC_ID_AND_NUMA_NODE_PATTERN "\x48\x8B\x05\x00\x00\x00\x00\x45\x33\xC0\xE8" 38 | #define HVLP_QUERY_APIC_ID_AND_NUMA_NODE_MASK "xxx????xxxx" 39 | 40 | // 1903, 1909, 20h1, 20h2, 21h1 41 | // 48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 83 0A FF 42 | #define HVLP_QUERY_APIC_ID_AND_NUMA_NODE_CALL_PATTERN "\x48\x89\x5C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x20\x83\x0A\xFF" 43 | #define HVLP_QUERY_APIC_ID_AND_NUMA_NODE_CALL_MASK "xxxx?xxxx?xxxxxxxx" 44 | 45 | // 2004, 20h2 46 | // 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B E9 41 8B F8 B9 ? ? ? ? 48 8B F2 8B D1 41 B8 ? ? ? ? 47 | #define MI_ALLOCATE_VAD_PATTERN "\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x48\x83\xEC\x30\x48\x8B\xE9\x41\x8B\xF8\xB9\x00\x00\x00\x00\x48\x8B\xF2\x8B\xD1\x41\xB8\x00\x00\x00\x00" 48 | #define MI_ALLOCATE_VAD_MASK "xxxx?xxxx?xxxx?xxxxxxxxxxxx????xxxxxxx????" 49 | 50 | // 2004, 20h2 51 | // 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 54 41 55 41 56 41 57 48 83 EC 20 8B 41 18 48 8B D9 44 0F B6 71 ? 45 33 E4 52 | #define MI_INSERT_VAD_CHANGES_PATTERN "\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x20\x8B\x41\x18\x48\x8B\xD9\x44\x0F\xB6\x71\x00\x45\x33\xE4" 53 | #define MI_INSERT_VAD_CHANGES_MASK "xxxx?xxxx?xxxx?xxxxxxxxxxxxxxxxxxxxxxx?xxx" 54 | 55 | // 2004, 20h2 56 | // 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 54 41 55 41 56 41 57 48 83 EC 20 8B 41 1C 33 ED 0F B6 59 21 57 | #define MI_INSERT_VAD_PATTERN "\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x83\xEC\x20\x8B\x41\x1C\x33\xED\x0F\xB6\x59\x21" 58 | #define MI_INSERT_VAD_MASK "xxxx?xxxx?xxxx?xxxxxxxxxxxxxxxxxxxxxx" 59 | -------------------------------------------------------------------------------- /Driver/Driver.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; Driver.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System ; TODO: specify appropriate Class 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} ; TODO: specify appropriate ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=Driver.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | PnpLockdown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 12 16 | Driver_Device_CoInstaller_CopyFiles = 11 17 | 18 | [SourceDisksNames] 19 | 1 = %DiskName%,,,"" 20 | 21 | [SourceDisksFiles] 22 | Driver.sys = 1,, 23 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 24 | 25 | ;***************************************** 26 | ; Install Section 27 | ;***************************************** 28 | 29 | [Manufacturer] 30 | %ManufacturerName%=Standard,NT$ARCH$ 31 | 32 | [Standard.NT$ARCH$] 33 | %Driver.DeviceDesc%=Driver_Device, Root\Driver ; TODO: edit hw-id 34 | 35 | [Driver_Device.NT] 36 | CopyFiles=Drivers_Dir 37 | 38 | [Drivers_Dir] 39 | Driver.sys 40 | 41 | ;-------------- Service installation 42 | [Driver_Device.NT.Services] 43 | AddService = Driver,%SPSVCINST_ASSOCSERVICE%, Driver_Service_Inst 44 | 45 | ; -------------- Driver driver install sections 46 | [Driver_Service_Inst] 47 | DisplayName = %Driver.SVCDESC% 48 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 49 | StartType = 3 ; SERVICE_DEMAND_START 50 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 51 | ServiceBinary = %12%\Driver.sys 52 | 53 | ; 54 | ;--- Driver_Device Coinstaller installation ------ 55 | ; 56 | 57 | [Driver_Device.NT.CoInstallers] 58 | AddReg=Driver_Device_CoInstaller_AddReg 59 | CopyFiles=Driver_Device_CoInstaller_CopyFiles 60 | 61 | [Driver_Device_CoInstaller_AddReg] 62 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 63 | 64 | [Driver_Device_CoInstaller_CopyFiles] 65 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 66 | 67 | [Driver_Device.NT.Wdf] 68 | KmdfService = Driver, Driver_wdfsect 69 | [Driver_wdfsect] 70 | KmdfLibraryVersion = $KMDFVERSION$ 71 | 72 | [Strings] 73 | SPSVCINST_ASSOCSERVICE= 0x00000002 74 | ManufacturerName="" ;TODO: Replace with your manufacturer name 75 | DiskName = "Driver Installation Disk" 76 | Driver.DeviceDesc = "Driver Device" 77 | Driver.SVCDESC = "Driver Service" 78 | -------------------------------------------------------------------------------- /Driver/Driver.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {04FFC011-260A-4E15-A499-143645DC5920} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | Driver 45 | $(LatestTargetPlatformVersion) 46 | 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Driver 53 | KMDF 54 | Universal 55 | 56 | 57 | Windows10 58 | false 59 | WindowsKernelModeDriver10.0 60 | Driver 61 | KMDF 62 | Universal 63 | 64 | 65 | Windows10 66 | true 67 | WindowsKernelModeDriver10.0 68 | Driver 69 | KMDF 70 | Universal 71 | 72 | 73 | Windows10 74 | false 75 | WindowsKernelModeDriver10.0 76 | Driver 77 | KMDF 78 | Universal 79 | Spectre 80 | 1 81 | 82 | 83 | Windows10 84 | true 85 | WindowsKernelModeDriver10.0 86 | Driver 87 | KMDF 88 | Universal 89 | 90 | 91 | Windows10 92 | false 93 | WindowsKernelModeDriver10.0 94 | Driver 95 | KMDF 96 | Universal 97 | 98 | 99 | Windows10 100 | true 101 | WindowsKernelModeDriver10.0 102 | Driver 103 | KMDF 104 | Universal 105 | 106 | 107 | Windows10 108 | false 109 | WindowsKernelModeDriver10.0 110 | Driver 111 | KMDF 112 | Universal 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | DbgengKernelDebugger 124 | 125 | 126 | DbgengKernelDebugger 127 | 128 | 129 | DbgengKernelDebugger 130 | 131 | 132 | DbgengKernelDebugger 133 | 134 | 135 | DbgengKernelDebugger 136 | 137 | 138 | DbgengKernelDebugger 139 | 140 | 141 | DbgengKernelDebugger 142 | 143 | 144 | DbgengKernelDebugger 145 | 146 | 147 | 148 | sha256 149 | 150 | 151 | 152 | 153 | sha256 154 | 155 | 156 | 157 | 158 | sha256 159 | 160 | 161 | 162 | 163 | sha256 164 | 165 | 166 | stdcpp17 167 | 168 | 169 | stdc17 170 | false 171 | false 172 | 173 | 174 | DriverEntry 175 | true 176 | 177 | 178 | 179 | 180 | sha256 181 | 182 | 183 | 184 | 185 | sha256 186 | 187 | 188 | 189 | 190 | sha256 191 | 192 | 193 | 194 | 195 | sha256 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /Driver/Driver.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {8E41214B-6785-4CFE-B992-037D68949A14} 10 | inf;inv;inx;mof;mc; 11 | 12 | 13 | {65afd367-7c3f-4693-a7e2-4ab83d132bb2} 14 | 15 | 16 | {cf362818-043c-45f5-84e5-3f47d81be686} 17 | 18 | 19 | {be97aca9-3f04-42b3-ad81-033615e5ac7e} 20 | 21 | 22 | {7ce15aa6-6a7d-4685-bbb7-27530c042e51} 23 | 24 | 25 | {cfec274e-6d97-439c-8548-8114c354f460} 26 | 27 | 28 | 29 | 30 | Driver Files 31 | 32 | 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files 39 | 40 | 41 | Source Files\Utils 42 | 43 | 44 | Source Files\Hide 45 | 46 | 47 | Source Files\Communication 48 | 49 | 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files\Utils 56 | 57 | 58 | Source Files\Library 59 | 60 | 61 | Source Files\Hide 62 | 63 | 64 | Source Files\Define 65 | 66 | 67 | Source Files\Define 68 | 69 | 70 | Source Files\Define 71 | 72 | 73 | Source Files\Define 74 | 75 | 76 | Source Files\Communication 77 | 78 | 79 | Source Files\Communication 80 | 81 | 82 | -------------------------------------------------------------------------------- /Driver/Hide/Hide.cpp: -------------------------------------------------------------------------------- 1 | #include "Hide.h" 2 | #include "../Utils/MemoryUtils.h" 3 | #include "../Library/skCrypter.h" 4 | #include "../Define/Patterns.h" 5 | 6 | #define MM_UNLOADED_DRIVERS_SIZE 50 7 | 8 | typedef struct _PIDDBCACHE_ENTRY { 9 | LIST_ENTRY List; 10 | UNICODE_STRING DriverName; 11 | ULONG TimeDateStamp; 12 | NTSTATUS LoadStatus; 13 | char _0x0028[16]; 14 | } PIDDBCACHE_ENTRY, * PPIDDBCACHE_ENTRY; 15 | 16 | typedef struct _MM_UNLOADED_DRIVER { 17 | UNICODE_STRING Name; 18 | PVOID ModuleStart; 19 | PVOID ModuleEnd; 20 | ULONG64 UnloadTime; 21 | } MM_UNLOADED_DRIVER, * PMM_UNLOADED_DRIVER; 22 | 23 | PERESOURCE 24 | GetPsLoaded() { 25 | PCHAR base = (PCHAR)MemoryUtils::GetKernelBase(); 26 | 27 | auto cMmGetSystemRoutineAddress = reinterpret_cast(MemoryUtils::GetExportedFunction((ULONGLONG)base, "MmGetSystemRoutineAddress")); 28 | 29 | ERESOURCE PsLoadedModuleResource; 30 | UNICODE_STRING routineName = RTL_CONSTANT_STRING(L"PsLoadedModuleResource"); 31 | auto cPsLoadedModuleResource = reinterpret_cast(cMmGetSystemRoutineAddress(&routineName)); 32 | 33 | return cPsLoadedModuleResource; 34 | } 35 | 36 | PMM_UNLOADED_DRIVER 37 | GetMmuAddress() { 38 | PCHAR base = (PCHAR)MemoryUtils::GetKernelBase(); 39 | 40 | auto MmuPattern = skCrypt(MMU_PATTERN); 41 | auto MmuMask = skCrypt(MMU_MASK); 42 | PVOID MmUnloadedDriversInstr = MemoryUtils::FindPatternImage(base, MmuPattern, MmuMask); 43 | MmuPattern.clear(); 44 | MmuMask.clear(); 45 | 46 | if (MmUnloadedDriversInstr == NULL) 47 | return { }; 48 | 49 | return *(PMM_UNLOADED_DRIVER*)MemoryUtils::ResolveRelativeAddress(MmUnloadedDriversInstr, 3, 7); 50 | } 51 | 52 | PULONG 53 | GetMmlAddress() { 54 | PCHAR Base = (PCHAR)MemoryUtils::GetKernelBase(); 55 | 56 | auto MmlPattern = skCrypt(MML_PATTERN); 57 | auto MmlMask = skCrypt(MML_MASK); 58 | PVOID mmlastunloadeddriverinst = MemoryUtils::FindPatternImage(Base, MmlPattern, MmlMask); 59 | MmlPattern.clear(); 60 | MmlMask.clear(); 61 | 62 | if (mmlastunloadeddriverinst == NULL) 63 | return { }; 64 | 65 | return (PULONG)MemoryUtils::ResolveRelativeAddress(mmlastunloadeddriverinst, 2, 6); 66 | } 67 | 68 | BOOL 69 | VerifyMmu() { 70 | return (GetMmuAddress() != NULL && GetMmlAddress() != NULL); 71 | } 72 | 73 | BOOL 74 | IsUnloadEmpty( 75 | PMM_UNLOADED_DRIVER Entry 76 | ) { 77 | if (Entry->Name.MaximumLength == 0 || Entry->Name.Length == 0 || Entry->Name.Buffer == NULL) 78 | return TRUE; 79 | 80 | return FALSE; 81 | } 82 | 83 | BOOL 84 | IsMmuFilled() { 85 | for (ULONG Idx = 0; Idx < MM_UNLOADED_DRIVERS_SIZE; ++Idx) { 86 | PMM_UNLOADED_DRIVER Entry = &GetMmuAddress()[Idx]; 87 | if (IsUnloadEmpty(Entry)) 88 | return FALSE; 89 | } 90 | return TRUE; 91 | } 92 | 93 | BOOL 94 | CleanMmu( 95 | UNICODE_STRING DriverName 96 | ) { 97 | auto ps_loaded = GetPsLoaded(); 98 | 99 | ExAcquireResourceExclusiveLite(ps_loaded, TRUE); 100 | 101 | BOOLEAN Modified = FALSE; 102 | BOOLEAN Filled = IsMmuFilled(); 103 | 104 | for (ULONG Index = 0; Index < MM_UNLOADED_DRIVERS_SIZE; ++Index) { 105 | PMM_UNLOADED_DRIVER Entry = &GetMmuAddress()[Index]; 106 | if (IsUnloadEmpty(Entry)) { 107 | continue; 108 | } 109 | BOOL empty = IsUnloadEmpty(Entry); 110 | if (Modified) { 111 | PMM_UNLOADED_DRIVER PrevEntry = &GetMmuAddress()[Index - 1]; 112 | RtlCopyMemory(PrevEntry, Entry, sizeof(MM_UNLOADED_DRIVER)); 113 | 114 | if (Index == MM_UNLOADED_DRIVERS_SIZE - 1) { 115 | RtlFillMemory(Entry, sizeof(MM_UNLOADED_DRIVER), 0); 116 | } 117 | } 118 | else if (RtlEqualUnicodeString(&DriverName, &Entry->Name, TRUE)) { 119 | PVOID BufferPool = Entry->Name.Buffer; 120 | RtlFillMemory(Entry, sizeof(MM_UNLOADED_DRIVER), 0); 121 | ExFreePoolWithTag(BufferPool, 'TDmM'); 122 | 123 | *GetMmlAddress() = (Filled ? MM_UNLOADED_DRIVERS_SIZE : *GetMmlAddress()) - 1; 124 | Modified = TRUE; 125 | } 126 | } 127 | 128 | if (Modified) { 129 | ULONG64 PreviousTime = 0; 130 | 131 | for (LONG Index = MM_UNLOADED_DRIVERS_SIZE - 2; Index >= 0; --Index) { 132 | PMM_UNLOADED_DRIVER Entry = &GetMmuAddress()[Index]; 133 | if (IsUnloadEmpty(Entry)) { 134 | continue; 135 | } 136 | 137 | if (PreviousTime != 0 && Entry->UnloadTime > PreviousTime) { 138 | Entry->UnloadTime = PreviousTime - MemoryUtils::RandomNumber(); 139 | } 140 | 141 | PreviousTime = Entry->UnloadTime; 142 | } 143 | 144 | CleanMmu(DriverName); 145 | } 146 | 147 | ExReleaseResourceLite(ps_loaded); 148 | 149 | return Modified; 150 | } 151 | 152 | PERESOURCE 153 | GetPiDDBLock() { 154 | PCHAR base = (PCHAR)MemoryUtils::GetKernelBase(); 155 | 156 | auto PiDDBLockPattern = skCrypt(PIDDB_LOCK_PATTERN); 157 | auto PiDDBLockMask = skCrypt(PIDDB_LOCK_MASK); 158 | PERESOURCE PiDDBLock = (PERESOURCE)MemoryUtils::FindPatternImage(base, PiDDBLockPattern, PiDDBLockMask); 159 | PiDDBLockPattern.clear(); 160 | PiDDBLockMask.clear(); 161 | 162 | PiDDBLock = (PERESOURCE)MemoryUtils::ResolveRelativeAddress((PVOID)PiDDBLock, 3, 7); 163 | if (!PiDDBLock) { 164 | return 0; 165 | } 166 | 167 | return PiDDBLock; 168 | } 169 | 170 | PRTL_AVL_TABLE 171 | GetPiDDBTable() { 172 | PCHAR base = (PCHAR)MemoryUtils::GetKernelBase(); 173 | 174 | auto PiDDBTablePattern = skCrypt(PIDDB_TABLE_PATTERN); 175 | auto PiDDBTableMask = skCrypt(PIDDB_TABLE_MASK); 176 | PRTL_AVL_TABLE PiDDBCacheTable = (PRTL_AVL_TABLE)MemoryUtils::FindPatternImage(base, PiDDBTablePattern, PiDDBTableMask); 177 | PiDDBTablePattern.clear(); 178 | PiDDBTableMask.clear(); 179 | 180 | PiDDBCacheTable = (PRTL_AVL_TABLE)MemoryUtils::ResolveRelativeAddress((PVOID)PiDDBCacheTable, 6, 10); 181 | 182 | if (!PiDDBCacheTable) { 183 | return 0; 184 | } 185 | 186 | return PiDDBCacheTable; 187 | } 188 | 189 | BOOL 190 | VerifyPiDDB() { 191 | return (GetPiDDBLock() != 0 && GetPiDDBTable() != 0); 192 | } 193 | 194 | BOOL 195 | CleanPiDDB( 196 | UNICODE_STRING DriverName 197 | ) { 198 | PERESOURCE PiDDBLock = GetPiDDBLock(); 199 | PRTL_AVL_TABLE PiDDBCacheTable = GetPiDDBTable(); 200 | PiDDBCacheTable->TableContext = (PVOID)1; 201 | 202 | PIDDBCACHE_ENTRY LookupEntry = { 0 }; 203 | LookupEntry.DriverName = DriverName; 204 | 205 | ExAcquireResourceExclusiveLite(PiDDBLock, TRUE); 206 | 207 | PPIDDBCACHE_ENTRY pFoundEntry = (PPIDDBCACHE_ENTRY)RtlLookupElementGenericTableAvl(PiDDBCacheTable, &LookupEntry); 208 | if (pFoundEntry == NULL) { 209 | ExReleaseResourceLite(PiDDBLock); 210 | return FALSE; 211 | } 212 | 213 | RemoveEntryList(&pFoundEntry->List); 214 | RtlDeleteElementGenericTableAvl(PiDDBCacheTable, pFoundEntry); 215 | 216 | ExReleaseResourceLite(PiDDBLock); 217 | 218 | return TRUE; 219 | } 220 | 221 | BOOL 222 | CleanKernelHashBucketList( 223 | UNICODE_STRING DriverName 224 | ) { 225 | auto CIDLLString = skCrypt("ci.dll"); 226 | CONST PVOID CIDLLBase = MemoryUtils::GetKernelModuleBase(CIDLLString); 227 | CIDLLString.clear(); 228 | 229 | if (!CIDLLBase) { 230 | return FALSE; 231 | } 232 | 233 | auto KernelBucketHashPattern = skCrypt(CI_DLL_KERNEL_HASH_BUCKET_PATTERN); 234 | auto KernelBucketHashMask = skCrypt(CI_DLL_KERNEL_HASH_BUCKET_MASK); 235 | CONST PVOID SignatureAddress = MemoryUtils::FindPatternImage((PCHAR)CIDLLBase, KernelBucketHashPattern, KernelBucketHashMask); 236 | KernelBucketHashPattern.clear(); 237 | KernelBucketHashMask.clear(); 238 | if (!SignatureAddress) { 239 | return FALSE; 240 | } 241 | 242 | CONST ULONGLONG* g_KernelHashBucketList = (ULONGLONG*)MemoryUtils::ResolveRelativeAddress(SignatureAddress, 3, 7); 243 | if (!g_KernelHashBucketList) { 244 | return FALSE; 245 | } 246 | 247 | LARGE_INTEGER Time{}; 248 | KeQuerySystemTimePrecise(&Time); 249 | 250 | BOOL Status = FALSE; 251 | for (ULONGLONG i = *g_KernelHashBucketList; i; i = *(ULONGLONG*)i) { 252 | CONST PWCHAR wsName = PWCH(i + 0x48); 253 | if (wcsstr(wsName, DriverName.Buffer)) { 254 | PUCHAR Hash = PUCHAR(i + 0x18); 255 | for (UINT j = 0; j < 20; j++) 256 | Hash[j] = UCHAR(RtlRandomEx(&Time.LowPart) % 255); 257 | 258 | Status = TRUE; 259 | } 260 | } 261 | 262 | return Status; 263 | } 264 | 265 | BOOL 266 | DeleteRegistryKey( 267 | UNICODE_STRING RegistryPath 268 | ) { 269 | HANDLE KeyHandle; 270 | OBJECT_ATTRIBUTES KeyAttributes; 271 | 272 | InitializeObjectAttributes(&KeyAttributes, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL); 273 | 274 | if (!NT_SUCCESS(ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &KeyAttributes))) { 275 | return FALSE; 276 | } 277 | 278 | if (!NT_SUCCESS(ZwDeleteKey(KeyHandle))) { 279 | return FALSE; 280 | } 281 | 282 | return TRUE; 283 | } 284 | 285 | BOOL 286 | DeleteFile( 287 | UNICODE_STRING FilePath 288 | ) { 289 | OBJECT_ATTRIBUTES FileAttributes; 290 | InitializeObjectAttributes(&FileAttributes, &FilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); 291 | 292 | if (!NT_SUCCESS(ZwDeleteFile(&FileAttributes))) { 293 | return FALSE; 294 | } 295 | 296 | return TRUE; 297 | } 298 | 299 | NTSTATUS 300 | Hide::Mapper( 301 | UNICODE_STRING DriverName 302 | ) { 303 | NTSTATUS Status = STATUS_SUCCESS; 304 | if (VerifyPiDDB()) { 305 | if (!CleanPiDDB(DriverName)) { 306 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to clean PiDDB"); 307 | Status = STATUS_UNSUCCESSFUL; 308 | } 309 | else { 310 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Successfully cleaned PiDDB"); 311 | } 312 | } 313 | else { 314 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to find PiDDB"); 315 | Status = STATUS_UNSUCCESSFUL; 316 | } 317 | 318 | if (VerifyMmu()) { 319 | if (!CleanMmu(DriverName)) { 320 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to clean MMU"); 321 | Status = STATUS_UNSUCCESSFUL; 322 | } 323 | else { 324 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Successfully cleaned MMU"); 325 | } 326 | } 327 | else { 328 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to find MMU"); 329 | Status = STATUS_UNSUCCESSFUL; 330 | } 331 | 332 | if (CleanKernelHashBucketList(DriverName)) { 333 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Successfully cleaned g_KernelHashBucketList"); 334 | } 335 | else { 336 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to clean g_KernelHashBucketList"); 337 | } 338 | 339 | //if (!DeleteRegistryKey(RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\mapper"))) { 340 | // DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Registry key deletion failed"); 341 | //} 342 | 343 | //if (!DeleteFile(RTL_CONSTANT_STRING(L"\\SystemRoot\\System32\\mapper.sys))) { 344 | // DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "File deletion failed"); 345 | //} 346 | 347 | return Status; 348 | } -------------------------------------------------------------------------------- /Driver/Hide/Hide.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Hide { 5 | NTSTATUS 6 | Mapper( 7 | UNICODE_STRING DriverName 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /Driver/Library/skCrypter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*____________________________________________________________________________________________________________ 4 | 5 | Original Author: skadro 6 | Github: https://github.com/skadro-official 7 | License: See end of file 8 | 9 | skCrypter 10 | Compile-time, Usermode + Kernelmode, safe and lightweight string crypter library for C++11+ 11 | 12 | *Not removing this part is appreciated* 13 | ____________________________________________________________________________________________________________*/ 14 | 15 | #ifdef _KERNEL_MODE 16 | namespace std 17 | { 18 | // STRUCT TEMPLATE remove_reference 19 | template 20 | struct remove_reference { 21 | using type = _Ty; 22 | }; 23 | 24 | template 25 | struct remove_reference<_Ty&> { 26 | using type = _Ty; 27 | }; 28 | 29 | template 30 | struct remove_reference<_Ty&&> { 31 | using type = _Ty; 32 | }; 33 | 34 | template 35 | using remove_reference_t = typename remove_reference<_Ty>::type; 36 | 37 | // STRUCT TEMPLATE remove_const 38 | template 39 | struct remove_const { // remove top-level const qualifier 40 | using type = _Ty; 41 | }; 42 | 43 | template 44 | struct remove_const { 45 | using type = _Ty; 46 | }; 47 | 48 | template 49 | using remove_const_t = typename remove_const<_Ty>::type; 50 | } 51 | #else 52 | #include 53 | #endif 54 | 55 | namespace skc 56 | { 57 | template 58 | using clean_type = typename std::remove_const_t>; 59 | 60 | template 61 | class skCrypter 62 | { 63 | public: 64 | __forceinline constexpr skCrypter(T* data) 65 | { 66 | crypt(data); 67 | } 68 | 69 | __forceinline T* get() 70 | { 71 | return _storage; 72 | } 73 | 74 | __forceinline int size() // (w)char count 75 | { 76 | return _size; 77 | } 78 | 79 | __forceinline char key() 80 | { 81 | return _key1; 82 | } 83 | 84 | __forceinline T* encrypt() 85 | { 86 | if (!isEncrypted()) 87 | crypt(_storage); 88 | 89 | return _storage; 90 | } 91 | 92 | __forceinline T* decrypt() 93 | { 94 | if (isEncrypted()) 95 | crypt(_storage); 96 | 97 | return _storage; 98 | } 99 | 100 | __forceinline bool isEncrypted() 101 | { 102 | return _storage[_size - 1] != 0; 103 | } 104 | 105 | __forceinline void clear() // set full storage to 0 106 | { 107 | for (int i = 0; i < _size; i++) 108 | { 109 | _storage[i] = 0; 110 | } 111 | } 112 | 113 | __forceinline operator T* () 114 | { 115 | decrypt(); 116 | 117 | return _storage; 118 | } 119 | 120 | private: 121 | __forceinline constexpr void crypt(T* data) 122 | { 123 | for (int i = 0; i < _size; i++) 124 | { 125 | _storage[i] = data[i] ^ (_key1 + i % (1 + _key2)); 126 | } 127 | } 128 | 129 | T _storage[_size]{}; 130 | }; 131 | } 132 | 133 | #define skCrypt(str) skCrypt_key(str, __TIME__[4], __TIME__[7]) 134 | #define skCrypt_key(str, key1, key2) []() { \ 135 | constexpr static auto crypted = skc::skCrypter \ 136 | >((skc::clean_type*)str); \ 137 | return crypted; }() 138 | 139 | /*________________________________________________________________________________ 140 | 141 | MIT License 142 | 143 | Copyright (c) 2020 skadro 144 | 145 | Permission is hereby granted, free of charge, to any person obtaining a copy 146 | of this software and associated documentation files (the "Software"), to deal 147 | in the Software without restriction, including without limitation the rights 148 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 149 | copies of the Software, and to permit persons to whom the Software is 150 | furnished to do so, subject to the following conditions: 151 | 152 | The above copyright notice and this permission notice shall be included in all 153 | copies or substantial portions of the Software. 154 | 155 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 157 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 158 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 159 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 160 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 161 | SOFTWARE. 162 | 163 | ________________________________________________________________________________*/ -------------------------------------------------------------------------------- /Driver/Main.cpp: -------------------------------------------------------------------------------- 1 | #define _KERNEL_MODE 2 | 3 | #include 4 | #include "Communication/Communication.h" 5 | #include "Hide/Hide.h" 6 | 7 | VOID 8 | TemporaryThread( 9 | PVOID StartContext 10 | ) { 11 | Communication::Initialize(); 12 | 13 | // Change to the name of the driver used to map 14 | Hide::Mapper(RTL_CONSTANT_STRING(L"mapper.sys")); 15 | } 16 | 17 | NTSTATUS 18 | DriverEntry( 19 | PDRIVER_OBJECT pDriverObject, 20 | PUNICODE_STRING pRegistryPath 21 | ) { 22 | UNREFERENCED_PARAMETER(pDriverObject); 23 | UNREFERENCED_PARAMETER(pRegistryPath); 24 | PAGED_CODE(); 25 | 26 | HANDLE hTemporaryThread = NULL; 27 | if (!NT_SUCCESS(PsCreateSystemThread( 28 | &hTemporaryThread, 29 | GENERIC_ALL, 30 | NULL, 31 | NULL, 32 | NULL, 33 | TemporaryThread, 34 | NULL 35 | ))) { 36 | return STATUS_UNSUCCESSFUL; 37 | } 38 | 39 | return STATUS_SUCCESS; 40 | } 41 | -------------------------------------------------------------------------------- /Driver/Utils/MemoryUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "MemoryUtils.h" 2 | #include "../Define/NT.h" 3 | #include "../Define/CRT.h" 4 | 5 | PVOID 6 | MemoryUtils::GetKernelBase() { 7 | PVOID KernelBase = NULL; 8 | 9 | ULONG size = NULL; 10 | NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, 0, 0, &size); 11 | if (STATUS_INFO_LENGTH_MISMATCH != status) { 12 | return KernelBase; 13 | } 14 | 15 | PSYSTEM_MODULE_INFORMATION Modules = (PSYSTEM_MODULE_INFORMATION)ExAllocatePool(NonPagedPool, size); 16 | if (!Modules) { 17 | return KernelBase; 18 | } 19 | 20 | if (!NT_SUCCESS(status = ZwQuerySystemInformation(SystemModuleInformation, Modules, size, 0))) { 21 | ExFreePool(Modules); 22 | return KernelBase; 23 | } 24 | 25 | if (Modules->NumberOfModules > 0) { 26 | KernelBase = Modules->Modules[0].ImageBase; 27 | } 28 | 29 | ExFreePool(Modules); 30 | return KernelBase; 31 | } 32 | 33 | PVOID 34 | MemoryUtils::GetKernelModuleBase( 35 | CHAR* ModuleName 36 | ) { 37 | PVOID ModuleBase = NULL; 38 | 39 | ULONG size = NULL; 40 | NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, 0, 0, &size); 41 | if (STATUS_INFO_LENGTH_MISMATCH != status) { 42 | return ModuleBase; 43 | } 44 | 45 | PSYSTEM_MODULE_INFORMATION Modules = (PSYSTEM_MODULE_INFORMATION)ExAllocatePool(NonPagedPool, size); 46 | if (!Modules) { 47 | return ModuleBase; 48 | } 49 | 50 | if (!NT_SUCCESS(status = ZwQuerySystemInformation(SystemModuleInformation, Modules, size, 0))) { 51 | ExFreePool(Modules); 52 | return ModuleBase; 53 | } 54 | 55 | for (UINT i = 0; i < Modules->NumberOfModules; i++) { 56 | CHAR* CurrentModuleName = reinterpret_cast(Modules->Modules[i].FullPathName); 57 | if (stristr(CurrentModuleName, ModuleName)) { 58 | ModuleBase = Modules->Modules[i].ImageBase; 59 | break; 60 | } 61 | } 62 | 63 | ExFreePool(Modules); 64 | return ModuleBase; 65 | 66 | } 67 | 68 | BOOL 69 | MemoryUtils::SafeCopy( 70 | PVOID Dest, 71 | PVOID Src, 72 | SIZE_T Size 73 | ) { 74 | SIZE_T returnSize = 0; 75 | if (NT_SUCCESS(MmCopyVirtualMemory(PsGetCurrentProcess(), Src, PsGetCurrentProcess(), Dest, Size, KernelMode, &returnSize)) && returnSize == Size) { 76 | return TRUE; 77 | } 78 | 79 | return FALSE; 80 | } 81 | 82 | 83 | TABLE_SEARCH_RESULT 84 | MiFindNodeOrParent( 85 | IN PMM_AVL_TABLE Table, 86 | IN ULONG_PTR StartingVpn, 87 | OUT PMMADDRESS_NODE* NodeOrParent 88 | ) { 89 | PMMADDRESS_NODE Child; 90 | PMMADDRESS_NODE NodeToExamine; 91 | PMMVAD_SHORT VpnCompare; 92 | ULONG_PTR startVpn; 93 | ULONG_PTR endVpn; 94 | 95 | if (Table->NumberGenericTableElements == 0) { 96 | return TableEmptyTree; 97 | } 98 | 99 | NodeToExamine = (PMMADDRESS_NODE)(Table->BalancedRoot); 100 | 101 | for (;;) { 102 | 103 | VpnCompare = (PMMVAD_SHORT)NodeToExamine; 104 | startVpn = VpnCompare->StartingVpn; 105 | endVpn = VpnCompare->EndingVpn; 106 | 107 | #if defined( _WIN81_ ) || defined( _WIN10_ ) 108 | startVpn |= (ULONG_PTR)VpnCompare->StartingVpnHigh << 32; 109 | endVpn |= (ULONG_PTR)VpnCompare->EndingVpnHigh << 32; 110 | #endif 111 | 112 | // 113 | // Compare the buffer with the key in the tree element. 114 | // 115 | 116 | if (StartingVpn < startVpn) { 117 | 118 | Child = NodeToExamine->LeftChild; 119 | 120 | if (Child != NULL) { 121 | NodeToExamine = Child; 122 | } 123 | else { 124 | 125 | // 126 | // Node is not in the tree. Set the output 127 | // parameter to point to what would be its 128 | // parent and return which child it would be. 129 | // 130 | 131 | *NodeOrParent = NodeToExamine; 132 | return TableInsertAsLeft; 133 | } 134 | } 135 | else if (StartingVpn <= endVpn) { 136 | 137 | // 138 | // This is the node. 139 | // 140 | 141 | *NodeOrParent = NodeToExamine; 142 | return TableFoundNode; 143 | } 144 | else { 145 | 146 | Child = NodeToExamine->RightChild; 147 | 148 | if (Child != NULL) { 149 | NodeToExamine = Child; 150 | } 151 | else { 152 | 153 | // 154 | // Node is not in the tree. Set the output 155 | // parameter to point to what would be its 156 | // parent and return which child it would be. 157 | // 158 | 159 | *NodeOrParent = NodeToExamine; 160 | return TableInsertAsRight; 161 | } 162 | } 163 | 164 | }; 165 | } 166 | 167 | NTSTATUS 168 | MemoryUtils::FindVAD( 169 | IN PEPROCESS pProcess, 170 | IN ULONG_PTR address, 171 | OUT PMMVAD_SHORT* pResult 172 | ) { 173 | NTSTATUS status = STATUS_SUCCESS; 174 | ULONG_PTR vpnStart = address >> PAGE_SHIFT; 175 | 176 | ASSERT(pProcess != NULL && pResult != NULL); 177 | if (pProcess == NULL || pResult == NULL) 178 | return STATUS_INVALID_PARAMETER; 179 | 180 | 181 | PMM_AVL_TABLE pTable = (PMM_AVL_TABLE)((PUCHAR)pProcess + 0x7d8); 182 | PMM_AVL_NODE pNode = (pTable->BalancedRoot); 183 | 184 | if (MiFindNodeOrParent(pTable, vpnStart, &pNode) == TableFoundNode) { 185 | *pResult = (PMMVAD_SHORT)pNode; 186 | } 187 | else { 188 | status = STATUS_NOT_FOUND; 189 | } 190 | 191 | return status; 192 | } 193 | 194 | PT_ENTRY_64* MemoryUtils::GetPte( 195 | PVOID VirtualAddress, 196 | CR3 HostCr3 197 | ) { 198 | ADDRESS_TRANSLATION_HELPER helper; 199 | UINT32 level; 200 | PT_ENTRY_64* finalEntry; 201 | PML4E_64* pml4; 202 | PML4E_64* pml4e; 203 | PDPTE_64* pdpt; 204 | PDPTE_64* pdpte; 205 | PDE_64* pd; 206 | PDE_64* pde; 207 | PTE_64* pt; 208 | PTE_64* pte; 209 | 210 | helper.AsUInt64 = (UINT64)VirtualAddress; 211 | 212 | PHYSICAL_ADDRESS addr; 213 | 214 | addr.QuadPart = HostCr3.AddressOfPageDirectory << PAGE_SHIFT; 215 | 216 | pml4 = (PML4E_64*)MmGetVirtualForPhysical(addr); 217 | 218 | pml4e = &pml4[helper.AsIndex.Pml4]; 219 | 220 | if (pml4e->Present == FALSE) { 221 | finalEntry = (PT_ENTRY_64*)pml4e; 222 | goto Exit; 223 | } 224 | 225 | addr.QuadPart = pml4e->PageFrameNumber << PAGE_SHIFT; 226 | 227 | pdpt = (PDPTE_64*)MmGetVirtualForPhysical(addr); 228 | 229 | pdpte = &pdpt[helper.AsIndex.Pdpt]; 230 | 231 | if ((pdpte->Present == FALSE) || (pdpte->LargePage != FALSE)) { 232 | finalEntry = (PT_ENTRY_64*)pdpte; 233 | goto Exit; 234 | } 235 | 236 | addr.QuadPart = pdpte->PageFrameNumber << PAGE_SHIFT; 237 | 238 | pd = (PDE_64*)MmGetVirtualForPhysical(addr); 239 | 240 | pde = &pd[helper.AsIndex.Pd]; 241 | 242 | if ((pde->Present == FALSE) || (pde->LargePage != FALSE)) { 243 | finalEntry = (PT_ENTRY_64*)pde; 244 | goto Exit; 245 | } 246 | 247 | addr.QuadPart = pde->PageFrameNumber << PAGE_SHIFT; 248 | 249 | pt = (PTE_64*)MmGetVirtualForPhysical(addr); 250 | 251 | pte = &pt[helper.AsIndex.Pt]; 252 | 253 | finalEntry = (PT_ENTRY_64*)pte; 254 | return (PT_ENTRY_64*)pte; 255 | 256 | Exit: 257 | return finalEntry; 258 | } 259 | 260 | ULONGLONG 261 | MemoryUtils::GetExportedFunction( 262 | CONST ULONGLONG mod, 263 | CONST CHAR* name 264 | ) { 265 | const auto dos_header = reinterpret_cast(mod); 266 | const auto nt_headers = reinterpret_cast(reinterpret_cast(dos_header) + dos_header->e_lfanew); 267 | 268 | const auto data_directory = nt_headers->OptionalHeader.DataDirectory[0]; 269 | const auto export_directory = reinterpret_cast(mod + data_directory.VirtualAddress); 270 | 271 | const auto address_of_names = reinterpret_cast(mod + export_directory->AddressOfNames); 272 | 273 | for (size_t i = 0; i < export_directory->NumberOfNames; i++) 274 | { 275 | const auto function_name = reinterpret_cast(mod + address_of_names[i]); 276 | 277 | if (!_stricmp(function_name, name)) 278 | { 279 | const auto name_ordinal = reinterpret_cast(mod + export_directory->AddressOfNameOrdinals)[i]; 280 | 281 | const auto function_rva = mod + reinterpret_cast(mod + export_directory->AddressOfFunctions)[name_ordinal]; 282 | return function_rva; 283 | } 284 | } 285 | 286 | return 0; 287 | } 288 | 289 | BOOL 290 | CheckMask( 291 | PCHAR Base, 292 | PCHAR Pattern, 293 | PCHAR Mask 294 | ) { 295 | for (; *Mask; ++Base, ++Pattern, ++Mask) { 296 | if (*Mask == 'x' && *Base != *Pattern) { 297 | return FALSE; 298 | } 299 | } 300 | 301 | return TRUE; 302 | } 303 | 304 | PVOID 305 | FindPattern( 306 | PCHAR Base, 307 | DWORD Length, 308 | PCHAR Pattern, 309 | PCHAR Mask 310 | ) { 311 | Length -= (DWORD)strlen(Mask); 312 | for (DWORD i = 0; i <= Length; ++i) { 313 | PVOID Addr = &Base[i]; 314 | if (CheckMask((PCHAR)Addr, Pattern, Mask)) { 315 | return Addr; 316 | } 317 | } 318 | 319 | return 0; 320 | } 321 | 322 | PVOID 323 | MemoryUtils::FindPatternImage( 324 | PCHAR Base, 325 | PCHAR Pattern, 326 | PCHAR Mask 327 | ) { 328 | PVOID Match = 0; 329 | 330 | PIMAGE_NT_HEADERS Headers = (PIMAGE_NT_HEADERS)(Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew); 331 | PIMAGE_SECTION_HEADER Sections = IMAGE_FIRST_SECTION(Headers); 332 | for (DWORD i = 0; i < Headers->FileHeader.NumberOfSections; ++i) { 333 | PIMAGE_SECTION_HEADER Section = &Sections[i]; 334 | if (*(PINT)Section->Name == 'EGAP' || memcmp(Section->Name, ".text", 5) == 0) { 335 | Match = FindPattern(Base + Section->VirtualAddress, Section->Misc.VirtualSize, Pattern, Mask); 336 | if (Match) { 337 | break; 338 | } 339 | } 340 | } 341 | 342 | return Match; 343 | } 344 | 345 | DWORD 346 | GetUserDirectoryTableBaseOffset() { 347 | RTL_OSVERSIONINFOW ver = { 0 }; 348 | RtlGetVersion(&ver); 349 | 350 | switch (ver.dwBuildNumber) 351 | { 352 | case WINDOWS_1803: 353 | return 0x0278; 354 | break; 355 | case WINDOWS_1809: 356 | return 0x0278; 357 | break; 358 | case WINDOWS_1903: 359 | return 0x0280; 360 | break; 361 | case WINDOWS_1909: 362 | return 0x0280; 363 | break; 364 | case WINDOWS_2004: 365 | return 0x0388; 366 | break; 367 | case WINDOWS_20H2: 368 | return 0x0388; 369 | break; 370 | case WINDOWS_21H1: 371 | return 0x0388; 372 | break; 373 | default: 374 | return 0x0388; 375 | } 376 | } 377 | 378 | PVOID 379 | MemoryUtils::ResolveRelativeAddress( 380 | PVOID Instruction, 381 | ULONG OffsetOffset, 382 | ULONG InstructionSize 383 | ) { 384 | ULONG_PTR Instr = (ULONG_PTR)Instruction; 385 | LONG RipOffset = *(PLONG)(Instr + OffsetOffset); 386 | PVOID ResolvedAddr = (PVOID)(Instr + InstructionSize + RipOffset); 387 | 388 | return ResolvedAddr; 389 | } 390 | 391 | UCHAR 392 | MemoryUtils::RandomNumber() { 393 | PVOID Base = MemoryUtils::GetKernelBase(); 394 | 395 | auto cMmGetSystemRoutineAddress = reinterpret_cast(MemoryUtils::GetExportedFunction((ULONGLONG)Base, "MmGetSystemRoutineAddress")); 396 | 397 | UNICODE_STRING RoutineName = RTL_CONSTANT_STRING(L"RtlRandom"); 398 | auto cRtlRandom = reinterpret_cast(cMmGetSystemRoutineAddress(&RoutineName)); 399 | 400 | ULONG Seed = 1234765; 401 | ULONG Rand = cRtlRandom(&Seed) % 100; 402 | 403 | UCHAR RandInt = 0; 404 | 405 | if (Rand >= 101 || Rand <= -1) 406 | RandInt = 72; 407 | 408 | return (UCHAR)(Rand); 409 | } 410 | -------------------------------------------------------------------------------- /Driver/Utils/MemoryUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "../Define/IA32.h" 5 | #include "../Define/NT.h" 6 | 7 | namespace MemoryUtils { 8 | PVOID 9 | GetKernelBase(); 10 | 11 | PVOID 12 | GetKernelModuleBase( 13 | CHAR* ModuleName 14 | ); 15 | 16 | BOOL 17 | SafeCopy( 18 | PVOID Dest, 19 | PVOID Src, 20 | SIZE_T Size 21 | ); 22 | 23 | NTSTATUS 24 | FindVAD( 25 | IN PEPROCESS pProcess, 26 | IN ULONG_PTR address, 27 | OUT PMMVAD_SHORT* pResult 28 | ); 29 | 30 | PT_ENTRY_64* 31 | GetPte( 32 | PVOID VirtualAddress, 33 | CR3 HostCr3 34 | ); 35 | 36 | ULONGLONG 37 | GetExportedFunction( 38 | CONST ULONGLONG Mod, 39 | CONST CHAR* Name 40 | ); 41 | 42 | PVOID 43 | FindPatternImage( 44 | PCHAR Base, 45 | PCHAR Pattern, 46 | PCHAR Mask 47 | ); 48 | 49 | PVOID 50 | ResolveRelativeAddress( 51 | PVOID Instruction, 52 | ULONG OffsetOffset, 53 | ULONG InstructionSize 54 | ); 55 | 56 | UCHAR 57 | RandomNumber(); 58 | } 59 | -------------------------------------------------------------------------------- /Images/BehindThreadStack.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kvmclgi/kernelmapper/1b15263529ad1075298171863d833b5ff93b06f3/Images/BehindThreadStack.PNG -------------------------------------------------------------------------------- /Images/NoSpoofing.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kvmclgi/kernelmapper/1b15263529ad1075298171863d833b5ff93b06f3/Images/NoSpoofing.PNG -------------------------------------------------------------------------------- /Images/PteSpoofing.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kvmclgi/kernelmapper/1b15263529ad1075298171863d833b5ff93b06f3/Images/PteSpoofing.PNG -------------------------------------------------------------------------------- /Images/RemoveVadNode.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kvmclgi/kernelmapper/1b15263529ad1075298171863d833b5ff93b06f3/Images/RemoveVadNode.PNG -------------------------------------------------------------------------------- /Images/VadSpoofing.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kvmclgi/kernelmapper/1b15263529ad1075298171863d833b5ff93b06f3/Images/VadSpoofing.PNG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clgi kernel mapper 2 | Manual mapper that uses PTE manipulation, Virtual Address Descriptor (VAD) manipulation, and forceful memory allocation to hide executable pages. 3 | 4 | ## Injector 5 | To hide our exectuable pages, the injector supports the following techniques: 6 | - Spoof page protection by modifying PTE execute bit or VAD protection flags 7 | - Remove created VAD entries after allocation 8 | - Forcefully allocate and write our DLL to wherever we want in the process address space 9 | 10 | Manipulating the VAD or underlying PTEs is desired in order to spoof page protection from API functions which rely on the VAD such as `NtQueryVirtualMemory`. In the case of this injector, we use VAD and PTE manipulation interchangely as they are both used to fake the protections specified by the VAD. 11 | 12 | Rather than "randomly" allocating memory by using an API function such as `NtAllocateVirtualMemory`, forcefully allocating memory via the VAD is used to write our DLL to an "unconventional" location in a processes address space. Anti-tampering solutions using heuristics to detect unwanted executable pages outside signed modules may avoid searching some memory regions to prevent false positives. This injector will allocate memory behind the thread stack. 13 | 14 | To execute our DLL, the injector will use `SetWindowsHookEx` to load a valid DLL such as `ntdll.dll`, then use the hook procedure to hijack control flow to call our DLL entry point. 15 | 16 | ## Driver 17 | Stealthy communication between our user-mode client and kernel-mode driver is achieved by placing a series of PatchGuard safe function hooks inside the windows kernel. An initial hook is placed on a function that is callable from user-mode using a syscall. Then, instead of immediately redirecting execution to our driver, the hook will lead to another function within the same kernel image, which we then hook to be redirected to our driver. 18 | 19 | The reason why we go through this process is to make it difficult to verify the integrity of `ntoskrnl.exe`. Since there are few usable functions inside `ntoskrnl.exe` suitable for communication, a separate driver looking to prevent tampering of `ntoskrnl.exe` could manually verify functions known to be used for user to kernel-mode communication by checking if they lead to an address outside a valid kernel image. However, if we chain hooks within the same kernel image the amount of possible functions an anti-tampering driver would need to verify increases significantly. 20 | 21 | The driver is meant to be mapped into the kernel and includes some functionality to hide that a mapper was ever loaded. This includes clearing the PiDDBCacheTable, MmUnloadedDrivers, and g_KernelHashBucketList. 22 | 23 | Strings in the driver and user-mode client are encrypted at compile time using skCrypter 24 | 25 | ## Showcase 26 | The following images show the process memory map of each setting after the DLL is mapped. The memory regions of the mapped DLL are highlighted. 27 | 28 | 29 | 33 | 37 | 38 | 42 | 46 | 47 | 51 |
30 |
31 | Generic manual mapping with no attempt to hide our DLL 32 |
34 |
35 | Spoof execution permission using PTE manipulation 36 |
39 |
40 | Spoof execution permission using VAD manipulation 41 |
43 |
44 | Remove created nodes from VAD tree 45 |
48 |
49 | Forcefully allocate and write DLL behind thread stack 50 |
52 | 53 | ## Usage 54 | 1. Load the driver 55 | 2. Run Client.exe from the command line 56 | 57 | ``` 58 | Usage: Client.exe 59 | : 60 | 0 - Do not spoof page protection 61 | 1 - Spoof page protection via PTE manipulation 62 | 2 - Spoof page protection via VAD manipulation 63 | : 64 | 0 - Do not remove VAD node 65 | 1 - Remove VAD node 66 | : 67 | 0 - Randomly allocate memory 68 | 1 - Allocate memory behind thread stack 69 | ``` 70 | 71 | ## Build 72 | Build using Visual Studio 2019 and the Windows Driver Kit 73 | 74 | ## Note 75 | The binaries were only tested on Windows 10 21H1 76 | 77 | Only supports injection of a x64 DLL into a x64 process 78 | 79 | The hooks placed on `ntoskrnl.exe` are not HVCI compatible 80 | 81 | --------------------------------------------------------------------------------