├── README.md
├── behaviorBased
├── behaviorBased.c
├── structs.h
├── utils.c
└── utils.h
├── communication
├── application.c
└── driver.c
├── miniFilter
├── miniFilter.c
└── miniFilter.h
└── threeProtection
├── PsProtect.h
├── RegMonitor.h
├── SelfProtect.h
├── myDriver.c
└── myDriver.h
/README.md:
--------------------------------------------------------------------------------
1 | # simpleAVdriver
2 | Simple AntiVirus Driver example
3 |
4 |
5 | 블로그 문서 : http://sanseolab.tistory.com/33
6 |
7 |
8 |
9 | 아래의 내용들을 참고하여 만든 간단한 프로젝트 : https://github.com/101196/ProcLogger
10 | 블로그 문서 : http://sanseolab.tistory.com/38
11 |
12 |
13 |
14 | [ reference ]
15 |
16 | miniFilter : https://github.com/guidoreina/minivers
17 |
18 | BehaviorBased : https://github.com/m0jt4b4/UWPHardening
19 |
20 | PsProtect : https://github.com/markjandrews/CodeMachineCourse/blob/master/source/kerrkt.labs/labs/ProcessBlock
21 |
22 | SelfProtect : https://github.com/KKamaa/Driver-Loader/tree/master/ProtectDriver/ProtectDriver
23 |
24 | RegMonitor : https://github.com/markjandrews/CodeMachineCourse/tree/master/source/kerrkt.labs/labs/HideReg
25 |
26 | Communication : http://ericasselin.com/userlandkernel-communication-deviceiocontrol-method
27 |
28 |
--------------------------------------------------------------------------------
/behaviorBased/behaviorBased.c:
--------------------------------------------------------------------------------
1 | #include "structs.h"
2 | #include "utils.h"
3 |
4 |
5 | extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);;
6 |
7 |
8 | LPSTR GetProcessNameFromPid(HANDLE pid) {
9 |
10 | PEPROCESS Process;
11 |
12 | if (PsLookupProcessByProcessId(pid, &Process) == STATUS_INVALID_PARAMETER) {
13 | return "[ SelfProtect ] [ ERROR ] PID required.";
14 | }
15 |
16 | return (LPSTR)PsGetProcessImageFileName(Process);
17 |
18 | }
19 |
20 |
21 | VOID OnImageLoadCallback(IN PUNICODE_STRING InFullImageName, IN HANDLE InProcessId, IN PIMAGE_INFO ImageInfo)
22 | {
23 | LPSTR processName;
24 | processName = GetProcessNameFromPid(InProcessId);
25 |
26 | if (!_stricmp(processName, "notepad.exe")) {
27 | DbgPrint("[ kernelAPC ] It's notepad.exe \n");
28 | if (InProcessId != 0 && InFullImageName != NULL && InFullImageName->Length > 0 && wcsstr(InFullImageName->Buffer, L"ntdll.dll"))
29 | {
30 | DbgPrint("[ kernelAPC ] It's ntdll.dll \n");
31 | }
32 | }
33 | else {
34 | return;
35 | }
36 |
37 |
38 | // check If ntdll is loading
39 | if (InProcessId != 0 && InFullImageName != NULL && InFullImageName->Length > 0 && wcsstr(InFullImageName->Buffer, L"ntdll.dll"))
40 | {
41 | NTSTATUS status = STATUS_SUCCESS;
42 | PEPROCESS pProcess = NULL;
43 | status = PsLookupProcessByProcessId(InProcessId, &pProcess);
44 | BOOLEAN isWow64 = (PsGetProcessWow64Process(pProcess) != NULL) ? TRUE : FALSE;
45 |
46 |
47 | // check if 64 bit ntdll is loading in 32 bit process
48 | if (isWow64 && wcsstr(InFullImageName->Buffer, L"System32"))
49 | return;
50 |
51 | // check if target process is protected
52 | if (PsIsProtectedProcess(pProcess))
53 | return;
54 |
55 | if (NT_SUCCESS(status))
56 | {
57 | KAPC_STATE apc;
58 | UNICODE_STRING ustrPath;
59 | PVOID pNtdll = NULL;
60 | PVOID LdrLoadDllLocal = NULL;
61 |
62 | KeStackAttachProcess(pProcess, &apc);
63 |
64 | // Get Ntdll address
65 | pNtdll = ImageInfo->ImageBase;
66 |
67 | // Get LdrLoadDll addresss
68 | LdrLoadDllLocal = SWIDGetModuleExport(pNtdll, "LdrLoadDll", pProcess, NULL);
69 |
70 | if (!LdrLoadDllLocal)
71 | {
72 | DPRINT("System Wide Injection Driver: %s: Failed to get LdrLoadDll address.\n", __FUNCTION__);
73 | status = STATUS_NOT_FOUND;
74 | KeUnstackDetachProcess(&apc);
75 | return;
76 | }
77 |
78 | // Call LdrLoadDll
79 | if (NT_SUCCESS(status))
80 | {
81 | PINJECT_BUFFER pUserBuf;
82 | if (isWow64)
83 | {
84 | RtlInitUnicodeString(&ustrPath, L"InjectionMitigationDLLx86.dll");
85 | pUserBuf = SWIDGetWow64Code(LdrLoadDllLocal, &ustrPath);
86 | }
87 | else
88 | {
89 | RtlInitUnicodeString(&ustrPath, L"InjectionMitigationDLLx64.dll");
90 | pUserBuf = SWIDGetNativeCode(LdrLoadDllLocal, &ustrPath);
91 | }
92 |
93 | status = SWIDApcInject(pUserBuf, (HANDLE)InProcessId);
94 | DPRINT("After SWIDApcInject() \n", __FUNCTION__);
95 | }
96 |
97 | KeUnstackDetachProcess(&apc);
98 | }
99 | else
100 | {
101 | DPRINT("System Wide Injection Driver: %s: PsLookupProcessByProcessId failed with status 0x%X.\n", __FUNCTION__, status);
102 |
103 | if (pProcess)
104 | ObDereferenceObject(pProcess);
105 |
106 | return;
107 | }
108 |
109 | if (pProcess)
110 | ObDereferenceObject(pProcess);
111 | }
112 | }
113 |
114 |
115 | NTSTATUS DefaultPassThrough(PDEVICE_OBJECT DeviceObject, PIRP Irp)
116 | {
117 | Irp->IoStatus.Information = 0;
118 | Irp->IoStatus.Status = STATUS_SUCCESS;
119 |
120 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
121 |
122 | return STATUS_SUCCESS;
123 | }
124 |
125 |
126 | void UnloadDriver(PDRIVER_OBJECT DriverObject)
127 | {
128 | PsRemoveLoadImageNotifyRoutine(OnImageLoadCallback);
129 | DPRINT("System Wide Injection Driver: %s: UnloadDriver.\n", __FUNCTION__);
130 | }
131 |
132 |
133 |
134 |
135 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
136 |
137 | NTSTATUS status;
138 | UNREFERENCED_PARAMETER(RegistryPath);
139 |
140 | DriverObject->DriverUnload = UnloadDriver;
141 |
142 | PsSetLoadImageNotifyRoutine(OnImageLoadCallback);
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/behaviorBased/structs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | typedef struct _SYSTEM_THREAD_INFORMATION
5 | {
6 | LARGE_INTEGER KernelTime;
7 | LARGE_INTEGER UserTime;
8 | LARGE_INTEGER CreateTime;
9 | ULONG WaitTime;
10 | PVOID StartAddress;
11 | CLIENT_ID ClientId;
12 | KPRIORITY Priority;
13 | LONG BasePriority;
14 | ULONG ContextSwitches;
15 | ULONG ThreadState;
16 | KWAIT_REASON WaitReason;
17 | } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
18 |
19 | typedef struct _SYSTEM_PROCESS_INFO
20 | {
21 | ULONG NextEntryOffset;
22 | ULONG NumberOfThreads;
23 | LARGE_INTEGER WorkingSetPrivateSize;
24 | ULONG HardFaultCount;
25 | ULONG NumberOfThreadsHighWatermark;
26 | ULONGLONG CycleTime;
27 | LARGE_INTEGER CreateTime;
28 | LARGE_INTEGER UserTime;
29 | LARGE_INTEGER KernelTime;
30 | UNICODE_STRING ImageName;
31 | KPRIORITY BasePriority;
32 | HANDLE UniqueProcessId;
33 | HANDLE InheritedFromUniqueProcessId;
34 | ULONG HandleCount;
35 | ULONG SessionId;
36 | ULONG_PTR UniqueProcessKey;
37 | SIZE_T PeakVirtualSize;
38 | SIZE_T VirtualSize;
39 | ULONG PageFaultCount;
40 | SIZE_T PeakWorkingSetSize;
41 | SIZE_T WorkingSetSize;
42 | SIZE_T QuotaPeakPagedPoolUsage;
43 | SIZE_T QuotaPagedPoolUsage;
44 | SIZE_T QuotaPeakNonPagedPoolUsage;
45 | SIZE_T QuotaNonPagedPoolUsage;
46 | SIZE_T PagefileUsage;
47 | SIZE_T PeakPagefileUsage;
48 | SIZE_T PrivatePageCount;
49 | LARGE_INTEGER ReadOperationCount;
50 | LARGE_INTEGER WriteOperationCount;
51 | LARGE_INTEGER OtherOperationCount;
52 | LARGE_INTEGER ReadTransferCount;
53 | LARGE_INTEGER WriteTransferCount;
54 | LARGE_INTEGER OtherTransferCount;
55 | SYSTEM_THREAD_INFORMATION Threads[1];
56 | } SYSTEM_PROCESS_INFO, *PSYSTEM_PROCESS_INFO;
57 |
58 | typedef struct _LDR_DATA_TABLE_ENTRY
59 | {
60 | LIST_ENTRY InLoadOrderLinks;
61 | LIST_ENTRY InMemoryOrderLinks;
62 | LIST_ENTRY InInitializationOrderLinks;
63 | PVOID DllBase;
64 | PVOID EntryPoint;
65 | ULONG SizeOfImage;
66 | UNICODE_STRING FullDllName;
67 | UNICODE_STRING BaseDllName;
68 | ULONG Flags;
69 | USHORT LoadCount;
70 | USHORT TlsIndex;
71 |
72 | union
73 | {
74 | LIST_ENTRY HashLinks;
75 |
76 | struct
77 | {
78 | PVOID SectionPointer;
79 | ULONG CheckSum;
80 | };
81 | };
82 |
83 | union
84 | {
85 | ULONG TimeDateStamp;
86 | PVOID LoadedImports;
87 | };
88 |
89 | struct _ACTIVATION_CONTEXT * EntryPointActivationContext;
90 | PVOID PatchInformation;
91 | LIST_ENTRY ForwarderLinks;
92 | LIST_ENTRY ServiceTagLinks;
93 | LIST_ENTRY StaticLinks;
94 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
95 |
96 | typedef struct _PEB_LDR_DATA
97 | {
98 | ULONG Length;
99 | UCHAR Initialized;
100 | PVOID SsHandle;
101 | LIST_ENTRY InLoadOrderModuleList;
102 | LIST_ENTRY InMemoryOrderModuleList;
103 | LIST_ENTRY InInitializationOrderModuleList;
104 | } PEB_LDR_DATA, *PPEB_LDR_DATA;
105 |
106 | typedef struct _PEB
107 | {
108 | UCHAR InheritedAddressSpace;
109 | UCHAR ReadImageFileExecOptions;
110 | UCHAR BeingDebugged;
111 | UCHAR BitField;
112 | PVOID Mutant;
113 | PVOID ImageBaseAddress;
114 | PPEB_LDR_DATA Ldr;
115 | PVOID ProcessParameters;
116 | PVOID SubSystemData;
117 | PVOID ProcessHeap;
118 | PVOID FastPebLock;
119 | PVOID AtlThunkSListPtr;
120 | PVOID IFEOKey;
121 | PVOID CrossProcessFlags;
122 | PVOID UserSharedInfoPtr;
123 | ULONG SystemReserved;
124 | ULONG AtlThunkSListPtr32;
125 | PVOID ApiSetMap;
126 | } PEB, *PPEB;
127 |
128 | typedef struct _INJECT_INFO
129 | {
130 | ULONG ProcessId;
131 | wchar_t DllName[1024];
132 | } INJECT_INFO, *PINJECT_INFO;
133 |
134 | typedef enum _KAPC_ENVIRONMENT
135 | {
136 | OriginalApcEnvironment,
137 | AttachedApcEnvironment,
138 | CurrentApcEnvironment,
139 | InsertApcEnvironment
140 | } KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;
141 |
142 |
143 | typedef struct _INJECT_BUFFER
144 | {
145 | UCHAR code[0x200];
146 | union
147 | {
148 | UNICODE_STRING path;
149 | UNICODE_STRING32 path32;
150 | };
151 |
152 | wchar_t buffer[488];
153 | PVOID module;
154 | ULONG complete;
155 | } INJECT_BUFFER, *PINJECT_BUFFER;
156 |
157 | // Image name resolve flags
158 | typedef enum _ResolveFlags
159 | {
160 | KApiShemaOnly = 1,
161 | KSkipSxS = 2,
162 | KFullPath = 4,
163 | } ResolveFlags;
164 |
165 | typedef struct tagACTCTXW
166 | {
167 | ULONG cbSize;
168 | ULONG dwFlags;
169 | PWCH lpSource;
170 | USHORT wProcessorArchitecture;
171 | USHORT wLangId;
172 | PWCH lpAssemblyDirectory;
173 | PWCH lpResourceName;
174 | PWCH lpApplicationName;
175 | PVOID hModule;
176 | } ACTCTXW, *PACTCTXW;
177 |
178 | typedef struct tagACTCTXW32
179 | {
180 | ULONG cbSize;
181 | ULONG dwFlags;
182 | ULONG lpSource;
183 | USHORT wProcessorArchitecture;
184 | USHORT wLangId;
185 | ULONG lpAssemblyDirectory;
186 | ULONG lpResourceName;
187 | ULONG lpApplicationName;
188 | ULONG hModule;
189 | } ACTCTXW32, *PACTCTXW32;
190 |
191 | ///
192 | /// User-mode memory region
193 | ///
194 | typedef struct _USER_CONTEXT
195 | {
196 | UCHAR code[0x1000]; // Code buffer
197 | union
198 | {
199 | UNICODE_STRING ustr;
200 | UNICODE_STRING32 ustr32;
201 | };
202 | wchar_t buffer[0x400]; // Buffer for unicode string
203 |
204 |
205 | // Activation context data
206 | union
207 | {
208 | ACTCTXW actx;
209 | ACTCTXW32 actx32;
210 | };
211 | HANDLE hCTX;
212 | ULONG hCookie;
213 |
214 | PVOID ptr; // Tmp data
215 | union
216 | {
217 | NTSTATUS status; // Last execution status
218 | PVOID retVal; // Function return value
219 | ULONG retVal32; // Function return value
220 | };
221 |
222 | //UCHAR tlsBuf[0x100];
223 | } USER_CONTEXT, *PUSER_CONTEXT;
224 |
225 | ///
226 | /// Manual map context
227 | ///
228 | typedef struct _MMAP_CONTEXT
229 | {
230 | PEPROCESS pProcess; // Target process
231 | PVOID pWorkerBuf; // Worker thread code buffer
232 | HANDLE hWorker; // Worker thread handle
233 | PETHREAD pWorker; // Worker thread object
234 | LIST_ENTRY modules; // Manual module list
235 | PUSER_CONTEXT userMem; // Tmp buffer in user space
236 | HANDLE hSync; // APC sync handle
237 | PKEVENT pSync; // APC sync object
238 | PVOID pSetEvent; // ZwSetEvent address
239 | PVOID pLoadImage; // LdrLoadDll address
240 | BOOLEAN tlsInitialized; // Static TLS was initialized
241 | } MMAP_CONTEXT, *PMMAP_CONTEXT;
242 |
243 |
244 |
245 | typedef struct _API_SET_VALUE_ENTRY
246 | {
247 | ULONG Flags;
248 | ULONG NameOffset;
249 | ULONG NameLength;
250 | ULONG ValueOffset;
251 | ULONG ValueLength;
252 | } API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY;
253 |
254 | typedef struct _API_SET_VALUE_ARRAY
255 | {
256 | ULONG Flags;
257 | ULONG NameOffset;
258 | ULONG Unk;
259 | ULONG NameLength;
260 | ULONG DataOffset;
261 | ULONG Count;
262 | } API_SET_VALUE_ARRAY, *PAPI_SET_VALUE_ARRAY;
263 |
264 | typedef struct _API_SET_NAMESPACE_ENTRY
265 | {
266 | ULONG Limit;
267 | ULONG Size;
268 | } API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY;
269 |
270 | typedef struct _API_SET_NAMESPACE_ARRAY
271 | {
272 | ULONG Version;
273 | ULONG Size;
274 | ULONG Flags;
275 | ULONG Count;
276 | ULONG Start;
277 | ULONG End;
278 | ULONG Unk[2];
279 | } API_SET_NAMESPACE_ARRAY, *PAPI_SET_NAMESPACE_ARRAY;
280 |
281 | typedef enum _SYSTEM_INFORMATION_CLASS {
282 | SystemBasicInformation,
283 | SystemProcessorInformation, // obsolete ... delete
284 | SystemPerformanceInformation,
285 | SystemTimeOfDayInformation,
286 | SystemPathInformation,
287 | SystemProcessInformation, // system process information
288 | SystemCallCountInformation,
289 | SystemDeviceInformation,
290 | SystemProcessorPerformanceInformation,
291 | SystemFlagsInformation,
292 | SystemCallTimeInformation,
293 | SystemModuleInformation, // system module
294 | SystemLocksInformation,
295 | SystemStackTraceInformation,
296 | SystemPagedPoolInformation,
297 | SystemNonPagedPoolInformation,
298 | SystemHandleInformation,
299 | SystemObjectInformation,
300 | SystemPageFileInformation,
301 | SystemVdmInstemulInformation,
302 | SystemVdmBopInformation,
303 | SystemFileCacheInformation,
304 | SystemPoolTagInformation,
305 | SystemInterruptInformation,
306 | SystemDpcBehaviorInformation,
307 | SystemFullMemoryInformation,
308 | SystemLoadGdiDriverInformation,
309 | SystemUnloadGdiDriverInformation,
310 | SystemTimeAdjustmentInformation,
311 | SystemSummaryMemoryInformation,
312 | SystemMirrorMemoryInformation,
313 | SystemPerformanceTraceInformation,
314 | SystemObsolete0,
315 | SystemExceptionInformation,
316 | SystemCrashDumpStateInformation,
317 | SystemKernelDebuggerInformation,
318 | SystemContextSwitchInformation,
319 | SystemRegistryQuotaInformation,
320 | SystemExtendServiceTableInformation,
321 | SystemPrioritySeperation,
322 | SystemVerifierAddDriverInformation,
323 | SystemVerifierRemoveDriverInformation,
324 | SystemProcessorIdleInformation,
325 | SystemLegacyDriverInformation,
326 | SystemCurrentTimeZoneInformation,
327 | SystemLookasideInformation,
328 | SystemTimeSlipNotification,
329 | SystemSessionCreate,
330 | SystemSessionDetach,
331 | SystemSessionInformation,
332 | SystemRangeStartInformation,
333 | SystemVerifierInformation,
334 | SystemVerifierThunkExtend,
335 | SystemSessionProcessInformation,
336 | SystemLoadGdiDriverInSystemSpace,
337 | SystemNumaProcessorMap,
338 | SystemPrefetcherInformation,
339 | SystemExtendedProcessInformation,
340 | SystemRecommendedSharedDataAlignment,
341 | SystemComPlusPackage,
342 | SystemNumaAvailableMemory,
343 | SystemProcessorPowerInformation,
344 | SystemEmulationBasicInformation,
345 | SystemEmulationProcessorInformation,
346 | SystemExtendedHandleInformation,
347 | SystemLostDelayedWriteInformation,
348 | SystemBigPoolInformation,
349 | SystemSessionPoolTagInformation,
350 | SystemSessionMappedViewInformation,
351 | SystemHotpatchInformation,
352 | SystemObjectSecurityMode,
353 | SystemWatchdogTimerHandler,
354 | SystemWatchdogTimerInformation,
355 | SystemLogicalProcessorInformation,
356 | SystemWow64SharedInformation,
357 | SystemRegisterFirmwareTableInformationHandler,
358 | SystemFirmwareTableInformation,
359 | SystemModuleInformationEx,
360 | SystemVerifierTriageInformation,
361 | SystemSuperfetchInformation,
362 | SystemMemoryListInformation,
363 | SystemFileCacheInformationEx,
364 | MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum
365 | } SYSTEM_INFORMATION_CLASS;
366 |
367 | typedef struct _PEB32
368 | {
369 | UCHAR InheritedAddressSpace;
370 | UCHAR ReadImageFileExecOptions;
371 | UCHAR BeingDebugged;
372 | UCHAR BitField;
373 | ULONG Mutant;
374 | ULONG ImageBaseAddress;
375 | ULONG Ldr;
376 | ULONG ProcessParameters;
377 | ULONG SubSystemData;
378 | ULONG ProcessHeap;
379 | ULONG FastPebLock;
380 | ULONG AtlThunkSListPtr;
381 | ULONG IFEOKey;
382 | ULONG CrossProcessFlags;
383 | ULONG UserSharedInfoPtr;
384 | ULONG SystemReserved;
385 | ULONG AtlThunkSListPtr32;
386 | ULONG ApiSetMap;
387 | } PEB32, *PPEB32;
388 |
389 |
390 | typedef struct _PEB_LDR_DATA32
391 | {
392 | ULONG Length;
393 | UCHAR Initialized;
394 | ULONG SsHandle;
395 | LIST_ENTRY32 InLoadOrderModuleList;
396 | LIST_ENTRY32 InMemoryOrderModuleList;
397 | LIST_ENTRY32 InInitializationOrderModuleList;
398 | } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
399 |
400 |
401 | typedef struct _LDR_DATA_TABLE_ENTRY32
402 | {
403 | LIST_ENTRY32 InLoadOrderLinks;
404 | LIST_ENTRY32 InMemoryOrderLinks;
405 | LIST_ENTRY32 InInitializationOrderLinks;
406 | ULONG DllBase;
407 | ULONG EntryPoint;
408 | ULONG SizeOfImage;
409 | UNICODE_STRING32 FullDllName;
410 | UNICODE_STRING32 BaseDllName;
411 | ULONG Flags;
412 | USHORT LoadCount;
413 | USHORT TlsIndex;
414 | LIST_ENTRY32 HashLinks;
415 | ULONG TimeDateStamp;
416 | } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
417 |
--------------------------------------------------------------------------------
/behaviorBased/utils.c:
--------------------------------------------------------------------------------
1 | #include "structs.h"
2 | #include "utils.h"
3 |
4 | void NTAPI KernelRoutine(PKAPC apc, PKNORMAL_ROUTINE * NormalRoutine, PVOID * NormalContext, \
5 | PVOID * SystemArgument1, PVOID * SystemArgument2)
6 | {
7 | ExFreePool(apc);
8 | }
9 |
10 | ///
11 | /// Get module base address by name
12 | ///
13 | /// Target process
14 | /// Nodule name to search for
15 | /// If TRUE - search in 32-bit PEB
16 | /// Found address, NULL if not found
17 | PVOID SWIDGetUserModule(IN PEPROCESS pProcess, IN PUNICODE_STRING ModuleName, IN BOOLEAN isWow64)
18 | {
19 | ASSERT(pProcess != NULL);
20 | if (pProcess == NULL)
21 | return NULL;
22 |
23 | // Protect from UserMode AV
24 | __try
25 | {
26 | LARGE_INTEGER time = { 0 };
27 | time.QuadPart = -250ll * 10 * 1000; // 250 msec.
28 |
29 | // Wow64 process
30 | if (isWow64)
31 | {
32 | PPEB32 pPeb32 = (PPEB32)PsGetProcessWow64Process(pProcess);
33 | if (pPeb32 == NULL)
34 | {
35 | DPRINT("System Wide Injection Driver: %s: No PEB32 present. Aborting.\n", __FUNCTION__);
36 | return NULL;
37 | }
38 |
39 | // Wait for loader a bit
40 | for (INT i = 0; !pPeb32->Ldr && i < 10; i++)
41 | {
42 | KeDelayExecutionThread(KernelMode, TRUE, &time);
43 | }
44 |
45 | // Still no loader
46 | if (!pPeb32->Ldr)
47 | {
48 | DPRINT("System Wide Injection Driver: %s: Loader32 was not intialiezd in time. Aborting.\n", __FUNCTION__);
49 | return NULL;
50 | }
51 |
52 | // Search in InLoadOrderModuleList
53 | for (PLIST_ENTRY32 pListEntry = (PLIST_ENTRY32)((PPEB_LDR_DATA32)pPeb32->Ldr)->InLoadOrderModuleList.Flink;
54 | pListEntry != &((PPEB_LDR_DATA32)pPeb32->Ldr)->InLoadOrderModuleList;
55 | pListEntry = (PLIST_ENTRY32)pListEntry->Flink)
56 | {
57 | UNICODE_STRING ustr;
58 | PLDR_DATA_TABLE_ENTRY32 pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
59 |
60 | RtlUnicodeStringInit(&ustr, (PWCH)pEntry->BaseDllName.Buffer);
61 |
62 | if (RtlCompareUnicodeString(&ustr, ModuleName, TRUE) == 0)
63 | return (PVOID)pEntry->DllBase;
64 | }
65 | }
66 | // Native process
67 | else
68 | {
69 | PPEB pPeb = PsGetProcessPeb(pProcess);
70 |
71 | if (!pPeb)
72 | {
73 | DPRINT("System Wide Injection Driver: %s: No PEB64 present. Aborting\n", __FUNCTION__);
74 | return NULL;
75 | }
76 |
77 | // Wait for loader a bit
78 | for (INT i = 0; !pPeb->Ldr && i < 10; i++)
79 | {
80 | KeDelayExecutionThread(KernelMode, TRUE, &time);
81 | }
82 |
83 | // Still no loader
84 | if (!pPeb->Ldr)
85 | {
86 | DPRINT("System Wide Injection Driver: %s: Loader64 was not intialiezd in time. Aborting\n", __FUNCTION__);
87 | return NULL;
88 | }
89 |
90 | // Search in InLoadOrderModuleList
91 | for (PLIST_ENTRY pListEntry = pPeb->Ldr->InLoadOrderModuleList.Flink;
92 | pListEntry != &pPeb->Ldr->InLoadOrderModuleList;
93 | pListEntry = pListEntry->Flink)
94 | {
95 | PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
96 | if (RtlCompareUnicodeString(&pEntry->BaseDllName, ModuleName, TRUE) == 0)
97 | return pEntry->DllBase;
98 | }
99 | }
100 | }
101 | __except (EXCEPTION_EXECUTE_HANDLER)
102 | {
103 | DPRINT("System Wide Injection Driver: %s: Exception, Code: 0x%X\n", __FUNCTION__, GetExceptionCode());
104 | }
105 |
106 | return NULL;
107 | }
108 |
109 | ///
110 | /// Allocate new Unicode string from Paged pool
111 | ///
112 | /// Resulting string
113 | /// Buffer size in bytes to alloacate
114 | /// Status code
115 | NTSTATUS SWIDSafeAllocateString(OUT PUNICODE_STRING result, IN USHORT size)
116 | {
117 | ASSERT(result != NULL);
118 | if (result == NULL || size == 0)
119 | return STATUS_INVALID_PARAMETER;
120 |
121 | result->Buffer = ExAllocatePoolWithTag(NonPagedPool, size, POOL_TAG);
122 | result->Length = 0;
123 | result->MaximumLength = size;
124 |
125 | if (result->Buffer)
126 | RtlZeroMemory(result->Buffer, size);
127 | else
128 | return STATUS_NO_MEMORY;
129 |
130 | return STATUS_SUCCESS;
131 | }
132 |
133 |
134 | ///
135 | /// Search for substring
136 | ///
137 | /// Source string
138 | /// Target string
139 | /// Case insensitive search
140 | /// Found position or -1 if not found
141 | LONG SWIDSafeSearchString(IN PUNICODE_STRING source, IN PUNICODE_STRING target, IN BOOLEAN CaseInSensitive)
142 | {
143 | ASSERT(source != NULL && target != NULL);
144 | if (source == NULL || target == NULL || source->Buffer == NULL || target->Buffer == NULL)
145 | return STATUS_INVALID_PARAMETER;
146 |
147 | // Size mismatch
148 | if (source->Length < target->Length)
149 | return -1;
150 |
151 | USHORT diff = source->Length - target->Length;
152 | for (USHORT i = 0; i < diff; i++)
153 | {
154 | if (RtlCompareUnicodeStrings(
155 | source->Buffer + i / sizeof(WCHAR),
156 | target->Length / sizeof(WCHAR),
157 | target->Buffer,
158 | target->Length / sizeof(WCHAR),
159 | CaseInSensitive
160 | ) == 0)
161 | {
162 | return i;
163 | }
164 | }
165 |
166 | return -1;
167 | }
168 |
169 |
170 | ///
171 | /// Allocate and copy string
172 | ///
173 | /// Resulting string
174 | /// Source string
175 | /// Status code
176 | NTSTATUS SWIDSafeInitString(OUT PUNICODE_STRING result, IN PUNICODE_STRING source)
177 | {
178 | ASSERT(result != NULL && source != NULL);
179 | if (result == NULL || source == NULL || source->Buffer == NULL)
180 | return STATUS_INVALID_PARAMETER;
181 |
182 | // No data to copy
183 | if (source->Length == 0)
184 | {
185 | result->Length = result->MaximumLength = 0;
186 | result->Buffer = NULL;
187 | return STATUS_SUCCESS;
188 | }
189 |
190 | result->Buffer = ExAllocatePoolWithTag(NonPagedPool, source->MaximumLength, POOL_TAG);
191 | result->Length = source->Length;
192 | result->MaximumLength = source->MaximumLength;
193 |
194 | //memcpy(result->Buffer, source->Buffer, source->Length);
195 | RtlCopyMemory(result->Buffer, source->Buffer, source->Length);
196 | return STATUS_SUCCESS;
197 | }
198 |
199 |
200 | ///
201 | /// Get file name from full path
202 | ///
203 | /// Path.
204 | /// Resulting name
205 | /// Status code
206 | NTSTATUS SWIDStripPath(IN PUNICODE_STRING path, OUT PUNICODE_STRING name)
207 | {
208 | ASSERT(path != NULL && name);
209 | if (path == NULL || name == NULL)
210 | return STATUS_INVALID_PARAMETER;
211 |
212 | // Empty string
213 | if (path->Length < 2)
214 | {
215 | *name = *path;
216 | return STATUS_NOT_FOUND;
217 | }
218 |
219 | for (USHORT i = (path->Length / sizeof(WCHAR)) - 1; i != 0; i--)
220 | {
221 | if (path->Buffer[i] == L'\\' || path->Buffer[i] == L'/')
222 | {
223 | name->Buffer = &path->Buffer[i + 1];
224 | name->Length = name->MaximumLength = path->Length - (i + 1) * sizeof(WCHAR);
225 | return STATUS_SUCCESS;
226 | }
227 | }
228 |
229 | *name = *path;
230 | return STATUS_NOT_FOUND;
231 | }
232 |
233 |
234 | ///
235 | /// Try to resolve image via API SET map
236 | ///
237 | /// Target process. Must be run in the context of this process
238 | /// Name to resolve
239 | /// Parent image name
240 | /// Resolved name if any
241 | /// Status code
242 | NTSTATUS SWIDResolveApiSet(
243 | IN PEPROCESS pProcess,
244 | IN PUNICODE_STRING name,
245 | IN PUNICODE_STRING baseImage,
246 | OUT PUNICODE_STRING resolved
247 | )
248 | {
249 | NTSTATUS status = STATUS_NOT_FOUND;
250 | PPEB32 pPeb32 = (PPEB32)PsGetProcessWow64Process(pProcess);
251 | PPEB pPeb = PsGetProcessPeb(pProcess);
252 | PAPI_SET_NAMESPACE_ARRAY pApiSetMap = (PAPI_SET_NAMESPACE_ARRAY)(pPeb32 != NULL ? (PVOID)pPeb32->ApiSetMap : pPeb->ApiSetMap);
253 |
254 | // Invalid name
255 | if (name == NULL || name->Length < 4 * sizeof(WCHAR) || name->Buffer == NULL ||
256 | (memcmp(name->Buffer, L"api-", 4) != 0 && memcmp(name->Buffer, L"ext-", 4) != 0))
257 | return STATUS_NOT_FOUND;
258 |
259 | // Iterate api set map
260 | for (ULONG i = 0; i < pApiSetMap->Count; i++)
261 | {
262 | PAPI_SET_NAMESPACE_ENTRY pDescriptor = NULL;
263 | PAPI_SET_VALUE_ARRAY pHostArray = NULL;
264 | wchar_t apiNameBuf[255] = { 0 };
265 | UNICODE_STRING apiName = { 0 };
266 |
267 |
268 | pDescriptor = (PAPI_SET_NAMESPACE_ENTRY)((PUCHAR)pApiSetMap + pApiSetMap->End + i * sizeof(API_SET_NAMESPACE_ENTRY));
269 | pHostArray = (PAPI_SET_VALUE_ARRAY)((PUCHAR)pApiSetMap + pApiSetMap->Start + sizeof(API_SET_VALUE_ARRAY) * pDescriptor->Size);
270 |
271 | memcpy(apiNameBuf, (PUCHAR)pApiSetMap + pHostArray->NameOffset, pHostArray->NameLength);
272 |
273 | RtlUnicodeStringInit(&apiName, apiNameBuf);
274 |
275 | // Check if this is a target api
276 | if (SWIDSafeSearchString(name, &apiName, TRUE) >= 0)
277 | {
278 | PAPI_SET_VALUE_ENTRY pHost = NULL;
279 | wchar_t apiHostNameBuf[255] = { 0 };
280 | UNICODE_STRING apiHostName = { 0 };
281 |
282 | pHost = (PAPI_SET_VALUE_ENTRY)((PUCHAR)pApiSetMap + pHostArray->DataOffset);
283 |
284 | // Sanity check
285 | if (pHostArray->Count < 1)
286 | return STATUS_NOT_FOUND;
287 |
288 | memcpy(apiHostNameBuf, (PUCHAR)pApiSetMap + pHost->ValueOffset, pHost->ValueLength);
289 | RtlUnicodeStringInit(&apiHostName, apiHostNameBuf);
290 |
291 | // No base name redirection
292 | if (pHostArray->Count == 1 || baseImage == NULL || baseImage->Buffer[0] == 0)
293 | {
294 | SWIDSafeInitString(resolved, &apiHostName);
295 | return STATUS_SUCCESS;
296 | }
297 | // Redirect accordingly to base name
298 | else
299 | {
300 | UNICODE_STRING baseImageName = { 0 };
301 | SWIDStripPath(baseImage, &baseImageName);
302 |
303 | if (RtlCompareUnicodeString(&apiHostName, &baseImageName, TRUE) == 0)
304 | {
305 | memset(apiHostNameBuf, 0, sizeof(apiHostNameBuf));
306 | memcpy(apiHostNameBuf, (PUCHAR)pApiSetMap + pHost[1].ValueOffset, pHost[1].ValueLength);
307 | RtlCreateUnicodeString(resolved, apiHostNameBuf);
308 | return STATUS_SUCCESS;
309 | }
310 | else
311 | {
312 | SWIDSafeInitString(resolved, &apiHostName);
313 | return STATUS_SUCCESS;
314 | }
315 | }
316 | }
317 | }
318 |
319 | return status;
320 | }
321 |
322 | ///
323 | /// Get exported function address
324 | ///
325 | /// Module base
326 | /// Function name or ordinal
327 | /// Target process for user module
328 | /// Dll name for api schema
329 | /// Found address, NULL if not found
330 | PVOID SWIDGetModuleExport(IN PVOID pBase, IN PCCHAR name_ord, IN PEPROCESS pProcess, IN PUNICODE_STRING baseName)
331 | {
332 | PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)pBase;
333 | PIMAGE_NT_HEADERS32 pNtHdr32 = NULL;
334 | PIMAGE_NT_HEADERS64 pNtHdr64 = NULL;
335 | PIMAGE_EXPORT_DIRECTORY pExport = NULL;
336 | ULONG expSize = 0;
337 | ULONG_PTR pAddress = 0;
338 |
339 | ASSERT(pBase != NULL);
340 | if (pBase == NULL)
341 | return NULL;
342 |
343 | /// Not a PE file
344 | if (pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
345 | {
346 | DPRINT("System Wide Injection Driver: %s: != IMAGE_DOS_SIGNATURE.\n", __FUNCTION__);
347 | return NULL;
348 | }
349 |
350 | pNtHdr32 = (PIMAGE_NT_HEADERS32)((PUCHAR)pBase + pDosHdr->e_lfanew);
351 | pNtHdr64 = (PIMAGE_NT_HEADERS64)((PUCHAR)pBase + pDosHdr->e_lfanew);
352 |
353 | // Not a PE file
354 | if (pNtHdr32->Signature != IMAGE_NT_SIGNATURE)
355 | {
356 | DPRINT("System Wide Injection Driver: %s: != IMAGE_NT_SIGNATURE.\n", __FUNCTION__);
357 | return NULL;
358 | }
359 |
360 | // 64 bit image
361 | if (pNtHdr32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
362 | {
363 | pExport = (PIMAGE_EXPORT_DIRECTORY)(pNtHdr64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)pBase);
364 | expSize = pNtHdr64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
365 | }
366 | // 32 bit image
367 | else
368 | {
369 | pExport = (PIMAGE_EXPORT_DIRECTORY)(pNtHdr32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)pBase);
370 | expSize = pNtHdr32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
371 | }
372 |
373 | PUSHORT pAddressOfOrds = (PUSHORT)(pExport->AddressOfNameOrdinals + (ULONG_PTR)pBase);
374 | PULONG pAddressOfNames = (PULONG)(pExport->AddressOfNames + (ULONG_PTR)pBase);
375 | PULONG pAddressOfFuncs = (PULONG)(pExport->AddressOfFunctions + (ULONG_PTR)pBase);
376 |
377 | for (ULONG i = 0; i < pExport->NumberOfFunctions; ++i)
378 | {
379 | USHORT OrdIndex = 0xFFFF;
380 | PCHAR pName = NULL;
381 |
382 | // Find by index
383 | if ((ULONG_PTR)name_ord <= 0xFFFF)
384 | {
385 | OrdIndex = (USHORT)i;
386 | }
387 | // Find by name
388 | else if ((ULONG_PTR)name_ord > 0xFFFF && i < pExport->NumberOfNames)
389 | {
390 | pName = (PCHAR)(pAddressOfNames[i] + (ULONG_PTR)pBase);
391 | OrdIndex = pAddressOfOrds[i];
392 | }
393 | // Weird params
394 | else
395 | {
396 | DPRINT("System Wide Injection Driver: %s: != Weird params.\n", __FUNCTION__);
397 | return NULL;
398 | }
399 |
400 | if (((ULONG_PTR)name_ord <= 0xFFFF && (USHORT)((ULONG_PTR)name_ord) == OrdIndex + pExport->Base) ||
401 | ((ULONG_PTR)name_ord > 0xFFFF && strcmp(pName, name_ord) == 0))
402 | {
403 | pAddress = pAddressOfFuncs[OrdIndex] + (ULONG_PTR)pBase;
404 |
405 | // Check forwarded export
406 | if (pAddress >= (ULONG_PTR)pExport && pAddress <= (ULONG_PTR)pExport + expSize)
407 | {
408 | WCHAR strbuf[256] = { 0 };
409 | ANSI_STRING forwarder = { 0 };
410 | ANSI_STRING import = { 0 };
411 |
412 | UNICODE_STRING uForwarder = { 0 };
413 | ULONG delimIdx = 0;
414 | PVOID forwardBase = NULL;
415 | PVOID result = NULL;
416 |
417 | // System image, not supported
418 | if (pProcess == NULL)
419 | {
420 | DPRINT("System Wide Injection Driver: %s: System image, not supported.\n", __FUNCTION__);
421 | return NULL;
422 | }
423 |
424 | RtlInitAnsiString(&forwarder, (PCSZ)pAddress);
425 | RtlInitEmptyUnicodeString(&uForwarder, strbuf, sizeof(strbuf));
426 |
427 | RtlAnsiStringToUnicodeString(&uForwarder, &forwarder, FALSE);
428 | for (ULONG j = 0; j < uForwarder.Length / sizeof(WCHAR); j++)
429 | {
430 | if (uForwarder.Buffer[j] == L'.')
431 | {
432 | uForwarder.Length = (USHORT)(j * sizeof(WCHAR));
433 | uForwarder.Buffer[j] = L'\0';
434 | delimIdx = j;
435 | break;
436 | }
437 | }
438 |
439 | // Get forward function name/ordinal
440 | RtlInitAnsiString(&import, forwarder.Buffer + delimIdx + 1);
441 | RtlAppendUnicodeToString(&uForwarder, L".dll");
442 |
443 | //
444 | // Check forwarded module
445 | //
446 | UNICODE_STRING resolved = { 0 };
447 | UNICODE_STRING resolvedName = { 0 };
448 | SWIDResolveImagePath(NULL, pProcess, KApiShemaOnly, &uForwarder, baseName, &resolved);
449 | SWIDStripPath(&resolved, &resolvedName);
450 |
451 | forwardBase = SWIDGetUserModule(pProcess, &resolvedName, PsGetProcessWow64Process(pProcess) != NULL);
452 | result = SWIDGetModuleExport(forwardBase, import.Buffer, pProcess, &resolvedName);
453 | RtlFreeUnicodeString(&resolved);
454 |
455 | return result;
456 | }
457 |
458 | break;
459 | }
460 | }
461 |
462 | return (PVOID)pAddress;
463 | }
464 |
465 |
466 | ULONG GenPrologue32(IN PUCHAR pBuf)
467 | {
468 | *pBuf = 0x55;
469 | *(PUSHORT)(pBuf + 1) = 0xE589;
470 |
471 | return 3;
472 | }
473 |
474 | ULONG GenPrologue64(IN PUCHAR pBuf)
475 | {
476 | *(PULONG)(pBuf + 0) = 0x244C8948; // mov [rsp + 0x08], rcx
477 | *(PUCHAR)(pBuf + 4) = 0x8; //
478 | *(PULONG)(pBuf + 5) = 0x24548948; // mov [rsp + 0x10], rdx
479 | *(PUCHAR)(pBuf + 9) = 0x10; //
480 | *(PULONG)(pBuf + 10) = 0x2444894C; // mov [rsp + 0x18], r8
481 | *(PUCHAR)(pBuf + 14) = 0x18; //
482 | *(PULONG)(pBuf + 15) = 0x244C894C; // mov [rsp + 0x20], r9
483 | *(PUCHAR)(pBuf + 19) = 0x20; //
484 | return 20;
485 | }
486 |
487 | ULONG GenPrologueT(IN BOOLEAN wow64, IN PUCHAR pBuf)
488 | {
489 | return wow64 ? GenPrologue32(pBuf) : GenPrologue64(pBuf);
490 | }
491 |
492 | ULONG GenCall32V(IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl)
493 | {
494 | ULONG ofst = 0;
495 |
496 | PULONG pArgBuf = ExAllocatePoolWithTag(NonPagedPool, argc * sizeof(ULONG), POOL_TAG);
497 |
498 | // cast args
499 | for (INT i = 0; i < argc; i++)
500 | {
501 | PVOID arg = va_arg(vl, PVOID);
502 | pArgBuf[i] = (ULONG)(ULONG_PTR)arg;
503 | }
504 |
505 | // push args
506 | for (INT i = argc - 1; i >= 0; i--)
507 | {
508 | *(PUSHORT)(pBuf + ofst) = 0x68; // push arg
509 | *(PULONG)(pBuf + ofst + 1) = pArgBuf[i]; //
510 | ofst += 5;
511 | }
512 |
513 | *(PUCHAR)(pBuf + ofst) = 0xB8; // mov eax, pFn
514 | *(PULONG)(pBuf + ofst + 1) = (ULONG)(ULONG_PTR)pFn; //
515 | ofst += 5;
516 |
517 | *(PUSHORT)(pBuf + ofst) = 0xD0FF; // call eax
518 | ofst += 2;
519 |
520 | ExFreePoolWithTag(pArgBuf, 0);
521 |
522 | return ofst;
523 | }
524 | ULONG GenCall64V(IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl)
525 | {
526 | USHORT rsp_diff = 0x28;
527 | ULONG ofst = 0;
528 | if (argc > 4)
529 | {
530 | rsp_diff = (USHORT)(argc * sizeof(ULONG_PTR));
531 | if (rsp_diff % 0x10)
532 | rsp_diff = ((rsp_diff / 0x10) + 1) * 0x10;
533 | rsp_diff += 8;
534 | }
535 |
536 | // sub rsp, rsp_diff
537 | *(PULONG)(pBuf + ofst) = (0x00EC8348 | rsp_diff << 24);
538 | ofst += 4;
539 |
540 | if (argc > 0)
541 | {
542 | PVOID arg = va_arg(vl, PVOID);
543 | *(PUSHORT)(pBuf + ofst) = 0xB948; // mov rcx, arg
544 | *(PVOID*)(pBuf + ofst + 2) = arg; //
545 | ofst += 10;
546 | }
547 | if (argc > 1)
548 | {
549 | PVOID arg = va_arg(vl, PVOID);
550 | *(PUSHORT)(pBuf + ofst) = 0xBA48; // mov rdx, arg
551 | *(PVOID*)(pBuf + ofst + 2) = arg; //
552 | ofst += 10;
553 | }
554 | if (argc > 2)
555 | {
556 | PVOID arg = va_arg(vl, PVOID);
557 | *(PUSHORT)(pBuf + ofst) = 0xB849; // mov r8, arg
558 | *(PVOID*)(pBuf + ofst + 2) = arg; //
559 | ofst += 10;
560 | }
561 | if (argc > 3)
562 | {
563 | PVOID arg = va_arg(vl, PVOID);
564 | *(PUSHORT)(pBuf + ofst) = 0xB949; // mov r9, arg
565 | *(PVOID*)(pBuf + ofst + 2) = arg; //
566 | ofst += 10;
567 | }
568 |
569 | for (INT i = 4; i < argc; i++)
570 | {
571 | PVOID arg = va_arg(vl, PVOID);
572 |
573 | *(PUSHORT)(pBuf + ofst) = 0xB848; // mov rcx, arg
574 | *(PVOID*)(pBuf + ofst + 2) = arg; //
575 | ofst += 10;
576 |
577 | // mov [rsp + i*8], rax
578 | *(PULONG)(pBuf + ofst) = 0x24448948;
579 | *(PUCHAR)(pBuf + ofst + 4) = (UCHAR)(0x20 + (i - 4) * sizeof(arg));
580 | ofst += 5;
581 | }
582 |
583 |
584 | *(PUSHORT)(pBuf + ofst) = 0xB848; // mov rax, pFn
585 | *(PVOID*)(pBuf + ofst + 2) = pFn; //
586 | ofst += 10;
587 |
588 | *(PUSHORT)(pBuf + ofst) = 0xD0FF; // call rax
589 | ofst += 2;
590 |
591 | // add rsp, rsp_diff
592 | *(PULONG)(pBuf + ofst) = (0x00C48348 | rsp_diff << 24);
593 | ofst += 4;
594 |
595 | return ofst;
596 | }
597 |
598 | ULONG GenCallTV(IN BOOLEAN wow64, IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl)
599 | {
600 | return wow64 ? GenCall32V(pBuf, pFn, argc, vl) : GenCall64V(pBuf, pFn, argc, vl);
601 | }
602 |
603 |
604 | ULONG GenEpilogue32(IN PUCHAR pBuf, IN INT retSize)
605 | {
606 | *(PUSHORT)pBuf = 0xEC89;
607 | *(pBuf + 2) = 0x5D;
608 | *(pBuf + 3) = 0xC2;
609 | *(PUSHORT)(pBuf + 4) = (USHORT)retSize;
610 |
611 | return 6;
612 | }
613 |
614 | ULONG GenEpilogue64(IN PUCHAR pBuf, IN INT retSize)
615 | {
616 | UNREFERENCED_PARAMETER(retSize);
617 |
618 | *(PULONG)(pBuf + 0) = 0x244C8B48; // mov rcx, [rsp + 0x08]
619 | *(PUCHAR)(pBuf + 4) = 0x8; //
620 | *(PULONG)(pBuf + 5) = 0x24548B48; // mov rdx, [rsp + 0x10]
621 | *(PUCHAR)(pBuf + 9) = 0x10; //
622 | *(PULONG)(pBuf + 10) = 0x24448B4C; // mov r8, [rsp + 0x18]
623 | *(PUCHAR)(pBuf + 14) = 0x18; //
624 | *(PULONG)(pBuf + 15) = 0x244C8B4C; // mov r9, [rsp + 0x20]
625 | *(PUCHAR)(pBuf + 19) = 0x20; //
626 | *(PUCHAR)(pBuf + 20) = 0xC3; // ret
627 | return 21;
628 | }
629 | ULONG GenEpilogueT(IN BOOLEAN wow64, IN PUCHAR pBuf, IN INT retSize)
630 | {
631 | return wow64 ? GenEpilogue32(pBuf, retSize) : GenEpilogue64(pBuf, retSize);
632 | }
633 |
634 | ULONG GenSync32(IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent)
635 | {
636 | ULONG ofst = 0;
637 |
638 | *(PUCHAR)(pBuf + ofst) = 0xA3; // mov [pStatus], eax
639 | *(PVOID*)(pBuf + ofst + 1) = pStatus; //
640 | ofst += 5;
641 |
642 | *(PUSHORT)(pBuf + ofst) = 0x006A; // push FALSE
643 | ofst += 2;
644 |
645 | *(PUCHAR)(pBuf + ofst) = 0x68; // push hEvent
646 | *(PULONG)(pBuf + ofst + 1) = (ULONG)(ULONG_PTR)hEvent; //
647 | ofst += 5;
648 |
649 | *(PUCHAR)(pBuf + ofst) = 0xB8; // mov eax, pSetEvent
650 | *(PULONG)(pBuf + ofst + 1) = (ULONG)(ULONG_PTR)pSetEvent;//
651 | ofst += 5;
652 |
653 | *(PUSHORT)(pBuf + ofst) = 0xD0FF; // call eax
654 | ofst += 2;
655 |
656 | return ofst;
657 | }
658 | ULONG GenSync64(IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent)
659 | {
660 | ULONG ofst = 0;
661 |
662 | *(PUSHORT)(pBuf + ofst) = 0xA348; // mov [pStatus], rax
663 | *(PVOID*)(pBuf + ofst + 2) = pStatus; //
664 | ofst += 10;
665 |
666 | *(PUSHORT)(pBuf + ofst) = 0xB948; // mov rcx, hEvent
667 | *(PHANDLE)(pBuf + ofst + 2) = hEvent; //
668 | ofst += 10;
669 |
670 | *(pBuf + ofst) = 0x48; // xor rdx, rdx
671 | *(PUSHORT)(pBuf + ofst + 1) = 0xD231; //
672 | ofst += 3;
673 |
674 | *(PUSHORT)(pBuf + ofst) = 0xB848; // mov rax, pSetEvent
675 | *(PVOID*)(pBuf + ofst + 2) = pSetEvent; //
676 | ofst += 10;
677 |
678 | *(PUSHORT)(pBuf + ofst) = 0xD0FF; // call rax
679 | ofst += 2;
680 |
681 | return ofst;
682 | }
683 |
684 |
685 | ULONG GenSyncT(IN BOOLEAN wow64, IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent)
686 | {
687 | return wow64 ? GenSync32(pBuf, pStatus, pSetEvent, hEvent) : GenSync64(pBuf, pStatus, pSetEvent, hEvent);
688 | }
689 |
690 | VOID KernelApcInjectCallback(
691 | PKAPC Apc,
692 | PKNORMAL_ROUTINE* NormalRoutine,
693 | PVOID* NormalContext,
694 | PVOID* SystemArgument1,
695 | PVOID* SystemArgument2
696 | )
697 | {
698 | UNREFERENCED_PARAMETER(SystemArgument1);
699 | UNREFERENCED_PARAMETER(SystemArgument2);
700 |
701 | // Skip execution
702 | if (PsIsThreadTerminating(PsGetCurrentThread()))
703 | *NormalRoutine = NULL;
704 |
705 | // Fix Wow64 APC
706 | if (PsGetCurrentProcessWow64Process() != NULL)
707 | PsWrapApcWow64Thread(NormalContext, (PVOID*)NormalRoutine);
708 |
709 | ExFreePoolWithTag(Apc, 0);
710 | }
711 |
712 | //
713 | // Injection APC routines
714 | //
715 | VOID KernelApcPrepareCallback(
716 | PKAPC Apc,
717 | PKNORMAL_ROUTINE* NormalRoutine,
718 | PVOID* NormalContext,
719 | PVOID* SystemArgument1,
720 | PVOID* SystemArgument2
721 | )
722 | {
723 | UNREFERENCED_PARAMETER(NormalRoutine);
724 | UNREFERENCED_PARAMETER(NormalContext);
725 | UNREFERENCED_PARAMETER(SystemArgument1);
726 | UNREFERENCED_PARAMETER(SystemArgument2);
727 |
728 | // Alert current thread
729 | KeTestAlertThread(UserMode);
730 | ExFreePoolWithTag(Apc, 0);
731 | }
732 | ///
733 | /// Queue user-mode APC to the target thread
734 | ///
735 | /// Target thread
736 | /// APC function
737 | /// Argument 1
738 | /// Argument 2
739 | /// Argument 3
740 | /// If TRUE - force delivery by issuing special kernel APC
741 | /// Status code
742 | NTSTATUS SWIDQueueUserApc(
743 | IN PETHREAD pThread,
744 | IN PVOID pUserFunc,
745 | IN PVOID Arg1,
746 | IN PVOID Arg2,
747 | IN PVOID Arg3,
748 | IN BOOLEAN bForce)
749 | {
750 | ASSERT(pThread != NULL);
751 | if (pThread == NULL)
752 | return STATUS_INVALID_PARAMETER;
753 |
754 | // Allocate APC
755 | PKAPC pPrepareApc = NULL;
756 | PKAPC pInjectApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), POOL_TAG);
757 |
758 | if (pInjectApc == NULL)
759 | {
760 | DPRINT("System Wide Injection Driver: %s: Failed to allocate APC.\n", __FUNCTION__);
761 | return STATUS_NO_MEMORY;
762 | }
763 |
764 | // Actual APC
765 | KeInitializeApc(
766 | pInjectApc, (PKTHREAD)pThread,
767 | OriginalApcEnvironment, &KernelApcInjectCallback,
768 | NULL, (PKNORMAL_ROUTINE)(ULONG_PTR)pUserFunc, UserMode, Arg1
769 | );
770 |
771 | // Setup force-delivery APC
772 | if (bForce)
773 | {
774 | pPrepareApc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), POOL_TAG);
775 | KeInitializeApc(
776 | pPrepareApc, (PKTHREAD)pThread,
777 | OriginalApcEnvironment, &KernelApcPrepareCallback,
778 | NULL, NULL, KernelMode, NULL
779 | );
780 | }
781 |
782 | // Insert APC
783 | if (KeInsertQueueApc(pInjectApc, Arg2, Arg3, 0))
784 | {
785 | if (bForce && pPrepareApc) {
786 | KeInsertQueueApc(pPrepareApc, NULL, NULL, 0);
787 | }
788 | DPRINT("In 1 SWIDQueueUserApc() \n", __FUNCTION__);
789 |
790 | return STATUS_SUCCESS;
791 | }
792 | else
793 | {
794 | DPRINT("System Wide Injection Driver: %s: Failed to insert APC.\n", __FUNCTION__);
795 |
796 | ExFreePoolWithTag(pInjectApc, 0);
797 |
798 | if (pPrepareApc)
799 | ExFreePoolWithTag(pPrepareApc, 0);
800 |
801 | return STATUS_NOT_CAPABLE;
802 | }
803 | }
804 |
805 | ///
806 | /// Call arbitrary function
807 | ///
808 | /// Perform call in a separate thread
809 | /// Loader context
810 | /// Routine to call.
811 | /// Number of arguments.
812 | /// Arguments
813 | /// Status code
814 | NTSTATUS SWIDCallRoutine(IN PMMAP_CONTEXT pContext, IN PVOID pRoutine, IN INT argc, ...)
815 | {
816 | NTSTATUS status = STATUS_SUCCESS;
817 | va_list vl;
818 | BOOLEAN wow64 = PsGetProcessWow64Process(pContext->pProcess) != NULL;
819 |
820 | va_start(vl, argc);
821 | ULONG ofst = GenPrologueT(wow64, pContext->userMem->code);
822 | ofst += GenCallTV(wow64, pContext->userMem->code + ofst, pRoutine, argc, vl);
823 | ofst += GenSyncT(wow64, pContext->userMem->code + ofst, &pContext->userMem->status, pContext->pSetEvent, pContext->hSync);
824 | ofst += GenEpilogueT(wow64, pContext->userMem->code + ofst, argc * sizeof(ULONG));
825 |
826 | KeResetEvent(pContext->pSync);
827 | status = SWIDQueueUserApc(pContext->pWorker, pContext->userMem->code, NULL, NULL, NULL, FALSE);
828 | if (NT_SUCCESS(status))
829 | {
830 | LARGE_INTEGER timeout = { 0 };
831 | timeout.QuadPart = -(10ll * 10 * 1000 * 1000); // 10s
832 |
833 | status = KeWaitForSingleObject(pContext->pSync, Executive, UserMode, TRUE, &timeout);
834 |
835 | timeout.QuadPart = -(1ll * 10 * 1000); // 1ms
836 | KeDelayExecutionThread(KernelMode, TRUE, &timeout);
837 | }
838 |
839 | va_end(vl);
840 |
841 | return status;
842 | }
843 |
844 | ///
845 | /// Get directory path name from full path
846 | ///
847 | /// Path
848 | /// Resulting directory path
849 | /// Status code
850 | NTSTATUS SWIDStripFilename(IN PUNICODE_STRING path, OUT PUNICODE_STRING dir)
851 | {
852 | ASSERT(path != NULL && dir);
853 | if (path == NULL || dir == NULL)
854 | return STATUS_INVALID_PARAMETER;
855 |
856 | // Empty string
857 | if (path->Length < 2)
858 | {
859 | *dir = *path;
860 | return STATUS_NOT_FOUND;
861 | }
862 |
863 | for (USHORT i = (path->Length / sizeof(WCHAR)) - 1; i != 0; i--)
864 | {
865 | if (path->Buffer[i] == L'\\' || path->Buffer[i] == L'/')
866 | {
867 | dir->Buffer = path->Buffer;
868 | dir->Length = dir->MaximumLength = i * sizeof(WCHAR);
869 | return STATUS_SUCCESS;
870 | }
871 | }
872 |
873 | *dir = *path;
874 | return STATUS_NOT_FOUND;
875 | }
876 |
877 | ///
878 | /// Check if file exists
879 | ///
880 | /// Fully qualifid path to a file
881 | /// Status code
882 | NTSTATUS SWIDFileExists(IN PUNICODE_STRING path)
883 | {
884 | HANDLE hFile = NULL;
885 | IO_STATUS_BLOCK statusBlock = { 0 };
886 | OBJECT_ATTRIBUTES obAttr = { 0 };
887 | InitializeObjectAttributes(&obAttr, path, OBJ_KERNEL_HANDLE, NULL, NULL);
888 |
889 | NTSTATUS status = ZwCreateFile(
890 | &hFile, FILE_READ_DATA | SYNCHRONIZE, &obAttr,
891 | &statusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
892 | FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0
893 | );
894 |
895 | if (NT_SUCCESS(status))
896 | ZwClose(hFile);
897 |
898 | return status;
899 | }
900 |
901 | ///
902 | ///Try to resolve image via SxS isolation
903 | ///
904 | /// Loader context.
905 | /// Name to resolve
906 | /// Resolved name if any
907 | /// Status code
908 | NTSTATUS SWIDResolveSxS(
909 | IN PMMAP_CONTEXT pContext,
910 | IN PUNICODE_STRING name,
911 | OUT PUNICODE_STRING resolved
912 | )
913 | {
914 | NTSTATUS status = STATUS_NOT_FOUND;
915 | UNICODE_STRING ustrNtdll = { 0 };
916 | BOOLEAN wow64 = PsGetProcessWow64Process(pContext->pProcess) != NULL;
917 |
918 | typedef struct _STRIBG_BUF
919 | {
920 | union
921 | {
922 | UNICODE_STRING name1;
923 | UNICODE_STRING32 name132;
924 | };
925 | union
926 | {
927 | UNICODE_STRING name2;
928 | UNICODE_STRING32 name232;
929 | };
930 | union
931 | {
932 | UNICODE_STRING origName;
933 | UNICODE_STRING32 origName32;
934 | };
935 | union
936 | {
937 | PUNICODE_STRING pResolved;
938 | ULONG pResolved32;
939 | };
940 | wchar_t origBuf[0x100];
941 | wchar_t staticBuf[0x200];
942 | } STRIBG_BUF, *PSTRIBG_BUF;
943 |
944 | PSTRIBG_BUF pStringBuf = (PSTRIBG_BUF)pContext->userMem->buffer;
945 |
946 | RtlUnicodeStringInit(&ustrNtdll, L"ntdll.dll");
947 |
948 | PVOID hNtdll = SWIDGetUserModule(pContext->pProcess, &ustrNtdll, wow64);
949 | PVOID pQueryName = SWIDGetModuleExport(hNtdll, "RtlDosApplyFileIsolationRedirection_Ustr", pContext->pProcess, NULL);
950 |
951 | if (pQueryName == NULL)
952 | {
953 | DPRINT("System Wide Injection Driver: %s: Failed to get RtlDosApplyFileIsolationRedirection_Ustr.\n", __FUNCTION__);
954 | return STATUS_NOT_FOUND;
955 | }
956 |
957 | RtlZeroMemory(pStringBuf->origBuf, sizeof(pStringBuf->origBuf));
958 | RtlZeroMemory(pStringBuf->staticBuf, sizeof(pStringBuf->staticBuf));
959 |
960 | // Fill params
961 | memcpy(pStringBuf->origBuf, name->Buffer, name->Length);
962 | if (wow64)
963 | {
964 | pStringBuf->origName32.Buffer = (ULONG)(ULONG_PTR)pStringBuf->origBuf;
965 | pStringBuf->origName32.MaximumLength = sizeof(pStringBuf->origBuf);
966 | pStringBuf->origName32.Length = name->Length;
967 |
968 | pStringBuf->name132.Buffer = (ULONG)(ULONG_PTR)pStringBuf->staticBuf;
969 | pStringBuf->name132.MaximumLength = sizeof(pStringBuf->staticBuf);
970 | pStringBuf->name132.Length = 0;
971 |
972 | pStringBuf->name232.Buffer = 0;
973 | pStringBuf->name232.Length = pStringBuf->name232.MaximumLength = 0;
974 | }
975 | else
976 | {
977 | RtlInitUnicodeString(&pStringBuf->origName, pStringBuf->origBuf);
978 | RtlInitEmptyUnicodeString(&pStringBuf->name1, pStringBuf->staticBuf, sizeof(pStringBuf->staticBuf));
979 | RtlInitEmptyUnicodeString(&pStringBuf->name2, NULL, 0);
980 | }
981 |
982 |
983 | // Prevent some unpredictable shit
984 | __try
985 | {
986 | // RtlDosApplyFileIsolationRedirection_Ustr
987 | status = SWIDCallRoutine(
988 | pContext, pQueryName, 9,
989 | (PVOID)TRUE, &pStringBuf->origName, NULL,
990 | &pStringBuf->name1, &pStringBuf->name2, &pStringBuf->pResolved,
991 | NULL, NULL, NULL
992 | );
993 |
994 | if (NT_SUCCESS(status) && NT_SUCCESS(pContext->userMem->status))
995 | {
996 | if (wow64)
997 | {
998 | ULONG tmp = ((PUNICODE_STRING32)pStringBuf->pResolved32)->Buffer;
999 | pStringBuf->pResolved = &pStringBuf->name1;
1000 | pStringBuf->pResolved->Buffer = (PWCH)tmp;
1001 | }
1002 |
1003 | RtlDowncaseUnicodeString(resolved, pStringBuf->pResolved, TRUE);
1004 | // TODO: name2 cleanup
1005 | }
1006 |
1007 | return NT_SUCCESS(status) ? pContext->userMem->status : status;
1008 | }
1009 | __except (EXCEPTION_EXECUTE_HANDLER)
1010 | {
1011 | DPRINT("System Wide Injection Driver: %s: Exception. Code: 0x%X.\n", __FUNCTION__, GetExceptionCode());
1012 | return STATUS_UNHANDLED_EXCEPTION;
1013 | }
1014 | }
1015 |
1016 |
1017 | ///
1018 | /// Resolve image name to fully qualified path
1019 | ///
1020 | /// Loader context
1021 | /// Target process. Must be running in the context of this process
1022 | /// Flags
1023 | /// Image name to resolve
1024 | /// Base image name for API SET translation
1025 | /// Resolved image path
1026 | /// Status code
1027 | NTSTATUS SWIDResolveImagePath(
1028 | IN PMMAP_CONTEXT pContext,
1029 | IN PEPROCESS pProcess,
1030 | IN ResolveFlags flags,
1031 | IN PUNICODE_STRING path,
1032 | IN PUNICODE_STRING baseImage,
1033 | OUT PUNICODE_STRING resolved
1034 | )
1035 | {
1036 | NTSTATUS status = STATUS_SUCCESS;
1037 | UNICODE_STRING pathLow = { 0 };
1038 | UNICODE_STRING filename = { 0 };
1039 | UNICODE_STRING fullResolved = { 0 };
1040 |
1041 | UNREFERENCED_PARAMETER(baseImage);
1042 |
1043 | ASSERT(pProcess != NULL && path != NULL && resolved != NULL);
1044 | if (pProcess == NULL || path == NULL || resolved == NULL)
1045 | {
1046 | DPRINT("System Wide Injection Driver: %s: Missing parameter.\n", __FUNCTION__);
1047 | return STATUS_INVALID_PARAMETER;
1048 | }
1049 |
1050 | RtlDowncaseUnicodeString(&pathLow, path, TRUE);
1051 | SWIDStripPath(&pathLow, &filename);
1052 |
1053 | // API Schema
1054 | if (NT_SUCCESS(SWIDResolveApiSet(pProcess, &filename, baseImage, resolved)))
1055 | {
1056 | SWIDSafeAllocateString(&fullResolved, 512);
1057 |
1058 | // Perpend system directory
1059 | if (PsGetProcessWow64Process(pProcess) != NULL)
1060 | RtlUnicodeStringCatString(&fullResolved, L"\\SystemRoot\\SysWow64\\");
1061 | else
1062 | RtlUnicodeStringCatString(&fullResolved, L"\\SystemRoot\\System32\\");
1063 |
1064 | RtlUnicodeStringCat(&fullResolved, resolved);
1065 | RtlFreeUnicodeString(resolved);
1066 | RtlFreeUnicodeString(&pathLow);
1067 |
1068 | *resolved = fullResolved;
1069 | return STATUS_SUCCESS;
1070 | }
1071 |
1072 | // Api schema only
1073 | if (flags & KApiShemaOnly)
1074 | goto skip;
1075 |
1076 | if (flags & KSkipSxS)
1077 | goto SkipSxS;
1078 |
1079 | // SxS
1080 | status = SWIDResolveSxS(pContext, &filename, resolved);
1081 | if (pContext && NT_SUCCESS(status))
1082 | {
1083 | SWIDSafeAllocateString(&fullResolved, 1024);
1084 | RtlUnicodeStringCatString(&fullResolved, L"\\??\\");
1085 | RtlUnicodeStringCat(&fullResolved, resolved);
1086 |
1087 | RtlFreeUnicodeString(resolved);
1088 | RtlFreeUnicodeString(&pathLow);
1089 |
1090 | *resolved = fullResolved;
1091 | return STATUS_SUCCESS;
1092 | }
1093 | else if (status == STATUS_UNHANDLED_EXCEPTION)
1094 | {
1095 | *resolved = pathLow;
1096 | return status;
1097 | }
1098 | else
1099 | status = STATUS_SUCCESS;
1100 |
1101 | SkipSxS:
1102 | SWIDSafeAllocateString(&fullResolved, 0x400);
1103 |
1104 | //
1105 | // Executable directory
1106 | //
1107 | ULONG bytes = 0;
1108 | if (NT_SUCCESS(ZwQueryInformationProcess(ZwCurrentProcess(), ProcessImageFileName, fullResolved.Buffer + 0x100, 0x200, &bytes)))
1109 | {
1110 | PUNICODE_STRING pPath = (PUNICODE_STRING)(fullResolved.Buffer + 0x100);
1111 | UNICODE_STRING parentDir = { 0 };
1112 | SWIDStripFilename(pPath, &parentDir);
1113 |
1114 | RtlCopyUnicodeString(&fullResolved, &parentDir);
1115 | RtlUnicodeStringCatString(&fullResolved, L"\\");
1116 | RtlUnicodeStringCat(&fullResolved, &filename);
1117 |
1118 | if (NT_SUCCESS(SWIDFileExists(&fullResolved)))
1119 | {
1120 | RtlFreeUnicodeString(resolved);
1121 | RtlFreeUnicodeString(&pathLow);
1122 |
1123 | *resolved = fullResolved;
1124 | return STATUS_SUCCESS;
1125 | }
1126 | }
1127 |
1128 | fullResolved.Length = 0;
1129 | RtlZeroMemory(fullResolved.Buffer, 0x400);
1130 |
1131 | //
1132 | // System directory
1133 | //
1134 | if (PsGetProcessWow64Process(pProcess) != NULL)
1135 | RtlUnicodeStringCatString(&fullResolved, L"\\SystemRoot\\SysWOW64\\");
1136 | else
1137 | RtlUnicodeStringCatString(&fullResolved, L"\\SystemRoot\\System32\\");
1138 |
1139 | RtlUnicodeStringCat(&fullResolved, &filename);
1140 | if (NT_SUCCESS(SWIDFileExists(&fullResolved)))
1141 | {
1142 | RtlFreeUnicodeString(resolved);
1143 | RtlFreeUnicodeString(&pathLow);
1144 |
1145 | *resolved = fullResolved;
1146 | return STATUS_SUCCESS;
1147 | }
1148 |
1149 | RtlFreeUnicodeString(&fullResolved);
1150 |
1151 | // Nothing found
1152 | skip:
1153 | *resolved = pathLow;
1154 | return status;
1155 | }
1156 |
1157 | ///
1158 | /// Build injection code for wow64 process
1159 | /// Must be running in target process context
1160 | ///
1161 | /// LdrLoadDll address
1162 | /// Path to the dll
1163 | /// Code pointer. When not needed, it should be freed with ZwFreeVirtualMemory
1164 | PINJECT_BUFFER SWIDGetWow64Code(IN PVOID LdrLoadDll, IN PUNICODE_STRING pPath)
1165 | {
1166 | NTSTATUS status = STATUS_SUCCESS;
1167 | PINJECT_BUFFER pBuffer = NULL;
1168 | SIZE_T size = PAGE_SIZE;
1169 |
1170 | // Code
1171 | UCHAR code[] =
1172 | {
1173 | 0x68, 0, 0, 0, 0, // push ModuleHandle offset +1
1174 | 0x68, 0, 0, 0, 0, // push ModuleFileName offset +6
1175 | 0x6A, 0, // push Flags
1176 | 0x6A, 0, // push PathToFile
1177 | 0xE8, 0, 0, 0, 0, // call LdrLoadDll offset +15
1178 | 0xBA, 0, 0, 0, 0, // mov edx, COMPLETE_OFFSET offset +20
1179 | 0xC7, 0x02, 0x7E, 0x1E, 0x37, 0xC0, // mov [edx], CALL_COMPLETE
1180 | 0xC2, 0x04, 0x00 // ret 4
1181 | };
1182 |
1183 | status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &pBuffer, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1184 | if (NT_SUCCESS(status))
1185 | {
1186 | // Copy path
1187 | PUNICODE_STRING32 pUserPath = &pBuffer->path32;
1188 | pUserPath->Length = pPath->Length;
1189 | pUserPath->MaximumLength = pPath->MaximumLength;
1190 | pUserPath->Buffer = (ULONG)(ULONG_PTR)pBuffer->buffer;
1191 |
1192 | // Copy path
1193 | memcpy((PVOID)pUserPath->Buffer, pPath->Buffer, pPath->Length);
1194 |
1195 | // Copy code
1196 | memcpy(pBuffer, code, sizeof(code));
1197 |
1198 | // Fill stubs
1199 | *(ULONG*)((PUCHAR)pBuffer + 1) = (ULONG)(ULONG_PTR)&pBuffer->module;
1200 | *(ULONG*)((PUCHAR)pBuffer + 6) = (ULONG)(ULONG_PTR)pUserPath;
1201 | *(ULONG*)((PUCHAR)pBuffer + 15) = (ULONG)((ULONG_PTR)LdrLoadDll - ((ULONG_PTR)pBuffer + 15) - 5 + 1);
1202 | *(ULONG*)((PUCHAR)pBuffer + 20) = (ULONG)(ULONG_PTR)&pBuffer->complete;
1203 |
1204 | return pBuffer;
1205 | }
1206 |
1207 | UNREFERENCED_PARAMETER(pPath);
1208 | return NULL;
1209 | }
1210 |
1211 | ///
1212 | /// Build injection code for native x64 process
1213 | /// Must be running in target process context
1214 | ///
1215 | /// LdrLoadDll address
1216 | /// Path to the dll
1217 | /// Code pointer. When not needed it should be freed with ZwFreeVirtualMemory
1218 | PINJECT_BUFFER SWIDGetNativeCode(IN PVOID LdrLoadDll, IN PUNICODE_STRING pPath)
1219 | {
1220 | NTSTATUS status = STATUS_SUCCESS;
1221 | PINJECT_BUFFER pBuffer = NULL;
1222 | SIZE_T size = PAGE_SIZE;
1223 |
1224 | // Code
1225 | UCHAR code[] =
1226 | {
1227 | 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x28
1228 | 0x48, 0x31, 0xC9, // xor rcx, rcx
1229 | 0x48, 0x31, 0xD2, // xor rdx, rdx
1230 | 0x49, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0, // mov r8, ModuleFileName offset +12
1231 | 0x49, 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, // mov r9, ModuleHandle offset +28
1232 | 0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0, // mov rax, LdrLoadDll offset +32
1233 | 0xFF, 0xD0, // call rax
1234 | 0x48, 0xBA, 0, 0, 0, 0, 0, 0, 0, 0, // mov rdx, COMPLETE_OFFSET offset +44
1235 | 0xC7, 0x02, 0x7E, 0x1E, 0x37, 0xC0, // mov [rdx], CALL_COMPLETE
1236 | 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28
1237 | 0xC3 // ret
1238 | };
1239 |
1240 | status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &pBuffer, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1241 | if (NT_SUCCESS(status))
1242 | {
1243 | // Copy path
1244 | PUNICODE_STRING pUserPath = &pBuffer->path;
1245 | pUserPath->Length = 0;
1246 | pUserPath->MaximumLength = sizeof(pBuffer->buffer);
1247 | pUserPath->Buffer = pBuffer->buffer;
1248 |
1249 | RtlUnicodeStringCopy(pUserPath, pPath);
1250 |
1251 | // Copy code
1252 | memcpy(pBuffer, code, sizeof(code));
1253 |
1254 | // Fill stubs
1255 | *(ULONGLONG*)((PUCHAR)pBuffer + 12) = (ULONGLONG)pUserPath;
1256 | *(ULONGLONG*)((PUCHAR)pBuffer + 22) = (ULONGLONG)&pBuffer->module;
1257 | *(ULONGLONG*)((PUCHAR)pBuffer + 32) = (ULONGLONG)LdrLoadDll;
1258 | *(ULONGLONG*)((PUCHAR)pBuffer + 44) = (ULONGLONG)&pBuffer->complete;
1259 |
1260 | return pBuffer;
1261 | }
1262 |
1263 | UNREFERENCED_PARAMETER(pPath);
1264 | return NULL;
1265 | }
1266 |
1267 | ///
1268 | /// Find first thread of the target process
1269 | ///
1270 | /// Target PID.
1271 | /// Found thread. Thread object reference count is increased by 1
1272 | /// Status code
1273 | NTSTATUS SWIDLookupProcessThread(IN HANDLE pid, OUT PETHREAD* ppThread)
1274 | {
1275 | NTSTATUS status = STATUS_SUCCESS;
1276 | PVOID pBuf = ExAllocatePoolWithTag(NonPagedPool, 1024 * 1024, POOL_TAG);
1277 | PSYSTEM_PROCESS_INFO pInfo = (PSYSTEM_PROCESS_INFO)pBuf;
1278 |
1279 | ASSERT(ppThread != NULL);
1280 | if (ppThread == NULL)
1281 | return STATUS_INVALID_PARAMETER;
1282 |
1283 | if (!pInfo)
1284 | {
1285 | DPRINT("System Wide Injection Driver: %s: Failed to allocate memory for process list\n", __FUNCTION__);
1286 | return STATUS_NO_MEMORY;
1287 | }
1288 |
1289 | // Get the process thread list
1290 | status = ZwQuerySystemInformation(SystemProcessInformation, pInfo, 1024 * 1024, NULL);
1291 | if (!NT_SUCCESS(status))
1292 | {
1293 | ExFreePoolWithTag(pBuf, 0);
1294 | return status;
1295 | }
1296 |
1297 | // Find target thread
1298 | if (NT_SUCCESS(status))
1299 | {
1300 | status = STATUS_NOT_FOUND;
1301 | for (;;)
1302 | {
1303 | if (pInfo->UniqueProcessId == pid)
1304 | {
1305 | status = STATUS_SUCCESS;
1306 | break;
1307 | }
1308 | else if (pInfo->NextEntryOffset)
1309 | pInfo = (PSYSTEM_PROCESS_INFO)((PUCHAR)pInfo + pInfo->NextEntryOffset);
1310 | else
1311 | break;
1312 | }
1313 | }
1314 |
1315 | // Reference target thread
1316 | if (NT_SUCCESS(status))
1317 | {
1318 | status = STATUS_NOT_FOUND;
1319 |
1320 | // Get first thread
1321 | for (ULONG i = 0; i < pInfo->NumberOfThreads; i++)
1322 | {
1323 | // Skip current thread
1324 | if (/*pInfo->Threads[i].WaitReason == Suspended ||
1325 | pInfo->Threads[i].ThreadState == 5 ||*/
1326 | pInfo->Threads[i].ClientId.UniqueThread == PsGetCurrentThread())
1327 | {
1328 | continue;
1329 | }
1330 |
1331 | status = PsLookupThreadByThreadId(pInfo->Threads[i].ClientId.UniqueThread, ppThread);
1332 | break;
1333 | }
1334 | }
1335 | else
1336 | DPRINT("System Wide Injection Driver : %s: Failed to locate process.\n", __FUNCTION__);
1337 |
1338 | if (pBuf)
1339 | ExFreePoolWithTag(pBuf, 0);
1340 |
1341 | return status;
1342 | }
1343 |
1344 |
1345 | //#define SEC_IMAGE 0x1000000
1346 |
1347 |
1348 | ///
1349 | /// Inject dll using APC
1350 | /// Must be running in target process context
1351 | ///
1352 | /// Injcetion code
1353 | /// Target process ID
1354 | /// Status code
1355 | NTSTATUS SWIDApcInject(IN PINJECT_BUFFER pUserBuf, IN HANDLE pid)
1356 | {
1357 | NTSTATUS status = STATUS_SUCCESS;
1358 | PETHREAD pThread = NULL;
1359 |
1360 | // Get suitable thread
1361 | status = SWIDLookupProcessThread(pid, &pThread);
1362 |
1363 | if (NT_SUCCESS(status))
1364 | {
1365 | status = SWIDQueueUserApc(pThread, pUserBuf->code, NULL, NULL, NULL, FALSE);
1366 |
1367 | if (!NT_SUCCESS(status))
1368 | DPRINT("System Wide Injection Driver: %s: SWIDQueueUserApc Failed.\n", __FUNCTION__);
1369 | }
1370 | else
1371 | DPRINT("System Wide Injection Driver: %s: Failed to locate thread.\n", __FUNCTION__);
1372 |
1373 | if (pThread)
1374 | ObDereferenceObject(pThread);
1375 |
1376 | return status;
1377 | }
1378 |
--------------------------------------------------------------------------------
/behaviorBased/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | #define DPRINT(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, format, __VA_ARGS__)
6 | #define CALL_COMPLETE 0xC0371E7E
7 | #define POOL_TAG 'Inj'
8 |
9 | typedef VOID(NTAPI * PKNORMAL_ROUTINE) (
10 | PVOID NormalContext,
11 | PVOID SystemArgument1,
12 | PVOID SystemArgument2
13 | );
14 |
15 | typedef VOID KKERNEL_ROUTINE(
16 | PRKAPC Apc,
17 | PKNORMAL_ROUTINE * NormalRoutine,
18 | PVOID * NormalContext,
19 | PVOID * SystemArgument1,
20 | PVOID * SystemArgument2
21 | );
22 |
23 | typedef KKERNEL_ROUTINE(NTAPI * PKKERNEL_ROUTINE);
24 |
25 | typedef VOID(NTAPI * PKRUNDOWN_ROUTINE) (
26 | PRKAPC Apc
27 | );
28 |
29 |
30 | void NTAPI KernelRoutine(PKAPC apc, PKNORMAL_ROUTINE * NormalRoutine, PVOID * NormalContext, \
31 | PVOID * SystemArgument1, PVOID * SystemArgument2);
32 |
33 | void KeInitializeApc(
34 | PRKAPC Apc,
35 | PRKTHREAD Thread,
36 | KAPC_ENVIRONMENT Environment,
37 | PKKERNEL_ROUTINE KernelRoutine,
38 | PKRUNDOWN_ROUTINE RundownRoutine,
39 | PKNORMAL_ROUTINE NormalRoutine,
40 | KPROCESSOR_MODE ProcessorMode,
41 | PVOID NormalContext
42 | );
43 |
44 | BOOLEAN KeInsertQueueApc(
45 | PRKAPC Apc,
46 | PVOID SystemArgument1,
47 | PVOID SystemArgument2,
48 | KPRIORITY Increment
49 | );
50 |
51 | NTSTATUS ZwQuerySystemInformation(ULONG InfoClass, PVOID Buffer, ULONG Length, PULONG ReturnLength);
52 | LPSTR PsGetProcessImageFileName(PEPROCESS Process);
53 |
54 |
55 | NTKERNELAPI
56 | PVOID
57 | NTAPI
58 | PsGetCurrentProcessWow64Process();
59 |
60 | NTSTRSAFEWORKERDDI
61 | RtlStringLengthWorkerW(
62 | _In_reads_or_z_(cchMax) STRSAFE_PCNZWCH psz,
63 | _In_ _In_range_(<= , NTSTRSAFE_MAX_CCH) size_t cchMax,
64 | _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength);
65 |
66 | NTKERNELAPI
67 | BOOLEAN
68 | NTAPI
69 | KeTestAlertThread(IN KPROCESSOR_MODE AlertMode);
70 |
71 | NTKERNELAPI
72 | PPEB
73 | NTAPI
74 | PsGetProcessPeb(IN PEPROCESS Process);
75 |
76 | NTSYSAPI
77 | NTSTATUS
78 | NTAPI
79 | ZwSetSystemInformation(
80 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
81 | IN PVOID SystemInformation,
82 | IN ULONG SystemInformationLength
83 | );
84 |
85 | NTSYSAPI
86 | NTSTATUS
87 | NTAPI
88 | ZwQueryInformationProcess(
89 | IN HANDLE ProcessHandle,
90 | IN PROCESSINFOCLASS ProcessInformationClass,
91 | OUT PVOID ProcessInformation,
92 | IN ULONG ProcessInformationLength,
93 | IN PULONG ReturnLength
94 | );
95 |
96 |
97 | NTSYSAPI
98 | NTSTATUS
99 | NTAPI
100 | ZwQueryInformationThread(
101 | IN HANDLE ThreadHandle,
102 | IN THREADINFOCLASS ThreadInformationClass,
103 | OUT PVOID ThreadInformation,
104 | IN ULONG ThreadInformationLength,
105 | OUT PULONG ReturnLength OPTIONAL
106 | );
107 |
108 | NTKERNELAPI
109 | PVOID
110 | NTAPI
111 | PsGetProcessWow64Process(IN PEPROCESS Process);
112 |
113 | NTKERNELAPI
114 | BOOLEAN
115 | NTAPI
116 | PsIsProtectedProcess(IN PEPROCESS Process);
117 |
118 | typedef NTSTATUS(NTAPI* fnNtCreateThreadEx)
119 | (
120 | OUT PHANDLE hThread,
121 | IN ACCESS_MASK DesiredAccess,
122 | IN PVOID ObjectAttributes,
123 | IN HANDLE ProcessHandle,
124 | IN PVOID lpStartAddress,
125 | IN PVOID lpParameter,
126 | IN ULONG Flags,
127 | IN SIZE_T StackZeroBits,
128 | IN SIZE_T SizeOfStackCommit,
129 | IN SIZE_T SizeOfStackReserve,
130 | OUT PVOID lpBytesBuffer
131 | );
132 |
133 |
134 | ///
135 | /// Get module base address by name
136 | ///
137 | /// Target process
138 | /// Nodule name to search for
139 | /// If TRUE - search in 32-bit PEB
140 | /// Found address, NULL if not found
141 | PVOID SWIDGetUserModule(IN PEPROCESS pProcess, IN PUNICODE_STRING ModuleName, IN BOOLEAN isWow64);
142 |
143 | ///
144 | /// Allocate new Unicode string from Paged pool
145 | ///
146 | /// Resulting string
147 | /// Buffer size in bytes to alloacate
148 | /// Status code
149 | NTSTATUS SWIDSafeAllocateString(OUT PUNICODE_STRING result, IN USHORT size);
150 |
151 |
152 | ///
153 | /// Search for substring
154 | ///
155 | /// Source string
156 | /// Target string
157 | /// Case insensitive search
158 | /// Found position or -1 if not found
159 | LONG SWIDSafeSearchString(IN PUNICODE_STRING source, IN PUNICODE_STRING target, IN BOOLEAN CaseInSensitive);
160 |
161 |
162 | ///
163 | /// Allocate and copy string
164 | ///
165 | /// Resulting string
166 | /// Source string
167 | /// Status code
168 | NTSTATUS SWIDSafeInitString(OUT PUNICODE_STRING result, IN PUNICODE_STRING source);
169 |
170 |
171 | ///
172 | /// Get file name from full path
173 | ///
174 | /// Path.
175 | /// Resulting name
176 | /// Status code
177 | NTSTATUS SWIDStripPath(IN PUNICODE_STRING path, OUT PUNICODE_STRING name);
178 |
179 |
180 | ///
181 | /// Try to resolve image via API SET map
182 | ///
183 | /// Target process. Must be run in the context of this process
184 | /// Name to resolve
185 | /// Parent image name
186 | /// Resolved name if any
187 | /// Status code
188 | NTSTATUS SWIDResolveApiSet(
189 | IN PEPROCESS pProcess,
190 | IN PUNICODE_STRING name,
191 | IN PUNICODE_STRING baseImage,
192 | OUT PUNICODE_STRING resolved
193 | );
194 |
195 | ///
196 | /// Get exported function address
197 | ///
198 | /// Module base
199 | /// Function name or ordinal
200 | /// Target process for user module
201 | /// Dll name for api schema
202 | /// Found address, NULL if not found
203 | PVOID SWIDGetModuleExport(IN PVOID pBase, IN PCCHAR name_ord, IN PEPROCESS pProcess, IN PUNICODE_STRING baseName);
204 |
205 |
206 | ULONG GenPrologue32(IN PUCHAR pBuf);
207 | ULONG GenPrologue64(IN PUCHAR pBuf);
208 | ULONG GenPrologueT(IN BOOLEAN wow64, IN PUCHAR pBuf);
209 |
210 | ULONG GenCall32V(IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl);
211 | ULONG GenCall64V(IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl);
212 | ULONG GenCallTV(IN BOOLEAN wow64, IN PUCHAR pBuf, IN PVOID pFn, IN INT argc, IN va_list vl);
213 |
214 | ULONG GenEpilogue32(IN PUCHAR pBuf, IN INT retSize);
215 | ULONG GenEpilogue64(IN PUCHAR pBuf, IN INT retSize);
216 | ULONG GenEpilogueT(IN BOOLEAN wow64, IN PUCHAR pBuf, IN INT retSize);
217 |
218 | ULONG GenSync32(IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent);
219 | ULONG GenSync64(IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent);
220 | ULONG GenSyncT(IN BOOLEAN wow64, IN PUCHAR pBuf, IN PNTSTATUS pStatus, IN PVOID pSetEvent, IN HANDLE hEvent);
221 |
222 | VOID KernelApcInjectCallback(
223 | PKAPC Apc,
224 | PKNORMAL_ROUTINE* NormalRoutine,
225 | PVOID* NormalContext,
226 | PVOID* SystemArgument1,
227 | PVOID* SystemArgument2
228 | );
229 |
230 | //
231 | // Injection APC routines
232 | //
233 | VOID KernelApcPrepareCallback(
234 | PKAPC Apc,
235 | PKNORMAL_ROUTINE* NormalRoutine,
236 | PVOID* NormalContext,
237 | PVOID* SystemArgument1,
238 | PVOID* SystemArgument2
239 | );
240 |
241 | ///
242 | /// Queue user-mode APC to the target thread
243 | ///
244 | /// Target thread
245 | /// APC function
246 | /// Argument 1
247 | /// Argument 2
248 | /// Argument 3
249 | /// If TRUE - force delivery by issuing special kernel APC
250 | /// Status code
251 | NTSTATUS SWIDQueueUserApc(
252 | IN PETHREAD pThread,
253 | IN PVOID pUserFunc,
254 | IN PVOID Arg1,
255 | IN PVOID Arg2,
256 | IN PVOID Arg3,
257 | IN BOOLEAN bForce);
258 |
259 | ///
260 | /// Call arbitrary function
261 | ///
262 | /// Perform call in a separate thread
263 | /// Loader context
264 | /// Routine to call.
265 | /// Number of arguments.
266 | /// Arguments
267 | /// Status code
268 | NTSTATUS SWIDCallRoutine(IN PMMAP_CONTEXT pContext, IN PVOID pRoutine, IN INT argc, ...);
269 |
270 | ///
271 | /// Get directory path name from full path
272 | ///
273 | /// Path
274 | /// Resulting directory path
275 | /// Status code
276 | NTSTATUS SWIDStripFilename(IN PUNICODE_STRING path, OUT PUNICODE_STRING dir);
277 |
278 | ///
279 | /// Check if file exists
280 | ///
281 | /// Fully qualifid path to a file
282 | /// Status code
283 | NTSTATUS SWIDFileExists(IN PUNICODE_STRING path);
284 |
285 | ///
286 | ///Try to resolve image via SxS isolation
287 | ///
288 | /// Loader context.
289 | /// Name to resolve
290 | /// Resolved name if any
291 | /// Status code
292 | NTSTATUS SWIDResolveSxS(
293 | IN PMMAP_CONTEXT pContext,
294 | IN PUNICODE_STRING name,
295 | OUT PUNICODE_STRING resolved
296 | );
297 |
298 |
299 | ///
300 | /// Resolve image name to fully qualified path
301 | ///
302 | /// Loader context
303 | /// Target process. Must be running in the context of this process
304 | /// Flags
305 | /// Image name to resolve
306 | /// Base image name for API SET translation
307 | /// Resolved image path
308 | /// Status code
309 | NTSTATUS SWIDResolveImagePath(
310 | IN PMMAP_CONTEXT pContext,
311 | IN PEPROCESS pProcess,
312 | IN ResolveFlags flags,
313 | IN PUNICODE_STRING path,
314 | IN PUNICODE_STRING baseImage,
315 | OUT PUNICODE_STRING resolved
316 | );
317 |
318 | ///
319 | /// Build injection code for wow64 process
320 | /// Must be running in target process context
321 | ///
322 | /// LdrLoadDll address
323 | /// Path to the dll
324 | /// Code pointer. When not needed, it should be freed with ZwFreeVirtualMemory
325 | PINJECT_BUFFER SWIDGetWow64Code(IN PVOID LdrLoadDll, IN PUNICODE_STRING pPath);
326 |
327 | ///
328 | /// Build injection code for native x64 process
329 | /// Must be running in target process context
330 | ///
331 | /// LdrLoadDll address
332 | /// Path to the dll
333 | /// Code pointer. When not needed it should be freed with ZwFreeVirtualMemory
334 | PINJECT_BUFFER SWIDGetNativeCode(IN PVOID LdrLoadDll, IN PUNICODE_STRING pPath);
335 |
336 | ///
337 | /// Find first thread of the target process
338 | ///
339 | /// Target PID.
340 | /// Found thread. Thread object reference count is increased by 1
341 | /// Status code
342 | NTSTATUS SWIDLookupProcessThread(IN HANDLE pid, OUT PETHREAD* ppThread);
343 |
344 | ///
345 | /// Inject dll using APC
346 | /// Must be running in target process context
347 | ///
348 | /// Injcetion code
349 | /// Target process ID
350 | /// Status code
351 | NTSTATUS SWIDApcInject(IN PINJECT_BUFFER pUserBuf, IN HANDLE pid);
352 |
--------------------------------------------------------------------------------
/communication/application.c:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | #include
3 |
4 | // Device type
5 | #define SIOCTL_TYPE 40000
6 |
7 | // The IOCTL function codes from 0x800 to 0xFFF are for customer use.
8 | #define IOCTL_HELLO\
9 | CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)
10 |
11 | int __cdecl main(int argc, char* argv[])
12 | {
13 | HANDLE hDevice;
14 | char *welcome = "Hello from userland.";
15 | DWORD dwBytesRead = 0;
16 | char ReadBuffer[50] = { 0 };
17 |
18 | hDevice = CreateFile(L"\\\\.\\MyDevice", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
19 | printf("Handle : %p\n", hDevice);
20 |
21 | DeviceIoControl(hDevice, IOCTL_HELLO, welcome, strlen(welcome), ReadBuffer, sizeof(ReadBuffer), &dwBytesRead, NULL);
22 | printf("Message received from kerneland : %s\n", ReadBuffer);
23 | printf("Bytes read : %d\n", dwBytesRead);
24 |
25 | CloseHandle(hDevice);
26 |
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------
/communication/driver.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | #define SIOCTL_TYPE 40000
5 | #define IOCTL_HELLO\
6 | CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)
7 |
8 |
9 | const WCHAR deviceNameBuffer[] = L"\\Device\\MYDEVICE";
10 | const WCHAR deviceSymLinkBuffer[] = L"\\DosDevices\\MyDevice";
11 | PDEVICE_OBJECT g_MyDevice; // Global pointer to our device object
12 |
13 |
14 | NTSTATUS Function_IRP_MJ_CREATE(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
15 | {
16 | DbgPrint("IRP MJ CREATE received.\n");
17 | return STATUS_SUCCESS;
18 | }
19 |
20 |
21 | NTSTATUS Function_IRP_MJ_CLOSE(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
22 | {
23 | DbgPrint("IRP MJ CLOSE received.\n");
24 | return STATUS_SUCCESS;
25 | }
26 |
27 |
28 | NTSTATUS Function_IRP_DEVICE_CONTROL(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
29 | {
30 | PIO_STACK_LOCATION pIoStackLocation;
31 | PCHAR welcome = "Hello from kerneland.";
32 | PVOID pBuf = Irp->AssociatedIrp.SystemBuffer;
33 |
34 | pIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
35 | switch (pIoStackLocation->Parameters.DeviceIoControl.IoControlCode)
36 | {
37 | case IOCTL_HELLO:
38 | DbgPrint("IOCTL HELLO.");
39 | DbgPrint("Message received : %s", pBuf);
40 |
41 | RtlZeroMemory(pBuf, pIoStackLocation->Parameters.DeviceIoControl.InputBufferLength);
42 | RtlCopyMemory(pBuf, welcome, strlen(welcome));
43 |
44 | break;
45 | }
46 |
47 | // Finish the I/O operation by simply completing the packet and returning
48 | // the same status as in the packet itself.
49 | Irp->IoStatus.Status = STATUS_SUCCESS;
50 | Irp->IoStatus.Information = strlen(welcome);
51 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
52 |
53 | return STATUS_SUCCESS;
54 | }
55 |
56 |
57 | VOID OnUnload(IN PDRIVER_OBJECT pDriverObject)
58 | {
59 | UNICODE_STRING symLink;
60 |
61 | RtlInitUnicodeString(&symLink, deviceSymLinkBuffer);
62 |
63 | IoDeleteSymbolicLink(&symLink);
64 | IoDeleteDevice(pDriverObject->DeviceObject);
65 |
66 | DbgPrint("OnUnload called!");
67 | }
68 |
69 |
70 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
71 | IN PUNICODE_STRING pRegistryPath)
72 | {
73 |
74 | NTSTATUS ntStatus = 0;
75 | UNICODE_STRING deviceNameUnicodeString, deviceSymLinkUnicodeString;
76 |
77 | // Normalize name and symbolic link.
78 | RtlInitUnicodeString(&deviceNameUnicodeString, deviceNameBuffer);
79 | RtlInitUnicodeString(&deviceSymLinkUnicodeString, deviceSymLinkBuffer);
80 |
81 | // Create the device.
82 | ntStatus = IoCreateDevice(pDriverObject,
83 | 0, // For driver extension
84 | &deviceNameUnicodeString,
85 | FILE_DEVICE_UNKNOWN,
86 | FILE_DEVICE_UNKNOWN,
87 | FALSE,
88 | &g_MyDevice);
89 |
90 | // Create the symbolic link
91 | ntStatus = IoCreateSymbolicLink(&deviceSymLinkUnicodeString, &deviceNameUnicodeString);
92 |
93 | pDriverObject->DriverUnload = OnUnload;
94 | pDriverObject->MajorFunction[IRP_MJ_CREATE] = Function_IRP_MJ_CREATE;
95 | pDriverObject->MajorFunction[IRP_MJ_CLOSE] = Function_IRP_MJ_CLOSE;
96 | pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Function_IRP_DEVICE_CONTROL;
97 |
98 | DbgPrint("Loading driver\n");
99 |
100 | return STATUS_SUCCESS;
101 | }
102 |
--------------------------------------------------------------------------------
/miniFilter/miniFilter.c:
--------------------------------------------------------------------------------
1 | #include "miniFilter.h"
2 |
3 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
4 | NTSTATUS status;
5 | UNREFERENCED_PARAMETER(RegistryPath);
6 |
7 | status = FltRegisterFilter(DriverObject, &filter_registration, &driver_data.filter);
8 |
9 | if (NT_SUCCESS(status)) {
10 | status = FltStartFiltering(driver_data.filter);
11 |
12 | if (!NT_SUCCESS(status)) {
13 | FltUnregisterFilter(driver_data.filter);
14 | }
15 | DbgPrint("[ miniFilter ] Start Filtering \n");
16 | }
17 |
18 | return status;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/miniFilter/miniFilter.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 |
6 |
7 |
8 | typedef struct {
9 | /* The filter that results from a call to FltRegisterFilter. */
10 | PFLT_FILTER filter;
11 | } DRIVER_DATA;
12 |
13 | static DRIVER_DATA driver_data;
14 |
15 |
16 |
17 |
18 | NTSTATUS InstanceSetup(_In_ PCFLT_RELATED_OBJECTS FltObjects,
19 | _In_ FLT_INSTANCE_SETUP_FLAGS Flags,
20 | _In_ DEVICE_TYPE VolumeDeviceType,
21 | _In_ FLT_FILESYSTEM_TYPE VolumeFilesystemType)
22 | {
23 | UNREFERENCED_PARAMETER(FltObjects);
24 | UNREFERENCED_PARAMETER(Flags);
25 | UNREFERENCED_PARAMETER(VolumeFilesystemType);
26 |
27 | PAGED_CODE();
28 |
29 | return (VolumeDeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) ?
30 | STATUS_SUCCESS :
31 | STATUS_FLT_DO_NOT_ATTACH;
32 | }
33 |
34 |
35 | NTSTATUS InstanceQueryTeardown(_In_ PCFLT_RELATED_OBJECTS FltObjects,
36 | _In_ FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
37 | {
38 | UNREFERENCED_PARAMETER(FltObjects);
39 | UNREFERENCED_PARAMETER(Flags);
40 |
41 | PAGED_CODE();
42 |
43 | return STATUS_SUCCESS;
44 | }
45 |
46 |
47 | BOOLEAN get_file_name_information(PFLT_CALLBACK_DATA data,
48 | PFLT_FILE_NAME_INFORMATION* name_info)
49 | {
50 | /* Get name information. */
51 | if (NT_SUCCESS(FltGetFileNameInformation(
52 | data,
53 | FLT_FILE_NAME_NORMALIZED |
54 | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP,
55 | name_info
56 | ))) {
57 | /* Parse file name information. */
58 | if (NT_SUCCESS(FltParseFileNameInformation(*name_info))) {
59 | return TRUE;
60 | }
61 |
62 | FltReleaseFileNameInformation(*name_info);
63 | }
64 |
65 | return FALSE;
66 | }
67 |
68 |
69 | FLT_PREOP_CALLBACK_STATUS process_irp(PFLT_CALLBACK_DATA Data,
70 | PCFLT_RELATED_OBJECTS FltObjects,
71 | PVOID* CompletionContext,
72 | BOOLEAN bit)
73 | {
74 | PFLT_FILE_NAME_INFORMATION name_info;
75 | PFLT_DEFERRED_IO_WORKITEM work;
76 |
77 | /* Get name information. */
78 | if (get_file_name_information(Data, &name_info)) {
79 | if (bit == TRUE)
80 | DbgPrint("[ miniFilter ] [ Writed ] Filename: '%wZ'.", &name_info->Name);
81 | else if (bit == FALSE)
82 | DbgPrint("[ miniFilter ] [ Deleted ] Filename: '%wZ'.", &name_info->Name);
83 | }
84 |
85 | return FLT_PREOP_SUCCESS_NO_CALLBACK;
86 | }
87 |
88 |
89 | FLT_PREOP_CALLBACK_STATUS
90 | PreOperationCallback(
91 | _Inout_ PFLT_CALLBACK_DATA Data,
92 | _In_ PCFLT_RELATED_OBJECTS FltObjects,
93 | _Flt_CompletionContext_Outptr_ PVOID* CompletionContext
94 | ) {
95 | //DbgPrint("##newDriver [ miniFilter ] PreOperationCallback Called \n");
96 |
97 | if (FLT_IS_IRP_OPERATION(Data)) {
98 | /* Open file? */
99 | if (Data->Iopb->MajorFunction == IRP_MJ_CREATE) {
100 | /* Open file for writing/appending? */
101 | if (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess &
102 | (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
103 | return process_irp(Data, FltObjects, CompletionContext, TRUE);
104 | }
105 | }
106 | else if (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) {
107 | if (Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation) {
108 | if (((FILE_DISPOSITION_INFORMATION*)
109 | Data->Iopb->Parameters.SetFileInformation.InfoBuffer
110 | )->DeleteFile) {
111 | return process_irp(Data, FltObjects, CompletionContext, FALSE);
112 | }
113 | }
114 | }
115 | }
116 |
117 | return FLT_PREOP_SUCCESS_NO_CALLBACK;
118 | }
119 |
120 |
121 | NTSTATUS FilterUnload(_In_ FLT_FILTER_UNLOAD_FLAGS Flags)
122 | {
123 | UNREFERENCED_PARAMETER(Flags);
124 |
125 | PAGED_CODE();
126 |
127 | FltUnregisterFilter(driver_data.filter);
128 | DbgPrint("[ miniFilter ] Stop Filtering \n");
129 |
130 | return STATUS_SUCCESS;
131 | }
132 |
133 |
134 |
135 |
136 | CONST FLT_OPERATION_REGISTRATION callbacks[] = {
137 | { IRP_MJ_CREATE, 0, PreOperationCallback, NULL },
138 | { IRP_MJ_SET_INFORMATION, 0, PreOperationCallback, NULL },
139 | { IRP_MJ_OPERATION_END }
140 | };
141 |
142 |
143 | CONST FLT_REGISTRATION filter_registration = {
144 | sizeof(FLT_REGISTRATION), /* Size. */
145 | FLT_REGISTRATION_VERSION, /* Version. */
146 | 0, /* Flags. */
147 | NULL, /* ContextRegistration. */
148 | callbacks, /* OperationRegistration. */
149 | FilterUnload, /* FilterUnloadCallback. */
150 | InstanceSetup, /* InstanceSetupCallback. */
151 | InstanceQueryTeardown, /* InstanceQueryTeardownCallback. */
152 | NULL, /* InstanceTeardownStartCallback. */
153 | NULL, /* InstanceTeardownCompleteCallback. */
154 | NULL, /* GenerateFileNameCallback. */
155 | NULL, /* NormalizeNameComponentCallback. */
156 | NULL /* NormalizeContextCleanupCallback. */
157 |
158 | #if FLT_MGR_LONGHORN
159 | , NULL /* TransactionNotificationCallback. */
160 | , NULL /* NormalizeNameComponentExCallback. */
161 | #endif /* FLT_MGR_LONGHORN */
162 | #if FLT_MFG_WIN8
163 | , NULL /* SectionNotificationCallback. */
164 | #endif
165 | };
166 |
--------------------------------------------------------------------------------
/threeProtection/PsProtect.h:
--------------------------------------------------------------------------------
1 | VOID ProcessNotifyCallbackEx(
2 | PEPROCESS Process,
3 | HANDLE ProcessId,
4 | PPS_CREATE_NOTIFY_INFO CreateInfo)
5 | {
6 |
7 | UNICODE_STRING ExecutableBlocked[] = {
8 | RTL_CONSTANT_STRING(L"*OLLYDBG*.EXE"),
9 | RTL_CONSTANT_STRING(L"*MSPAINT*.EXE"),
10 | RTL_CONSTANT_STRING(L"*NOTEPAD*.EXE")
11 | };
12 | ULONG ExecutableCount = sizeof(ExecutableBlocked) / sizeof(UNICODE_STRING);
13 |
14 | BOOLEAN Matched = FALSE;
15 | ULONG Idx;
16 |
17 | UNREFERENCED_PARAMETER(ProcessId);
18 | UNREFERENCED_PARAMETER(Process);
19 |
20 | if (CreateInfo) {
21 |
22 | for (Idx = 0; Idx < ExecutableCount; Idx++) {
23 | if (FsRtlIsNameInExpression(&ExecutableBlocked[Idx], (PUNICODE_STRING)CreateInfo->ImageFileName, TRUE, NULL)) {
24 | Matched = TRUE;
25 | break;
26 | }
27 | }
28 |
29 | if (Matched) {
30 | DbgPrint("[ PsProtect ] Preventing Process (%wZ) Execution\n", CreateInfo->ImageFileName);
31 | CreateInfo->CreationStatus = STATUS_ACCESS_DENIED;
32 | }
33 | else {
34 | DbgPrint("[ PsProtect ] Starting Process: %wZ\n", CreateInfo->ImageFileName);
35 | }
36 | }
37 |
38 | return;
39 | }
40 |
41 |
42 | NTSTATUS InstallProcessProtect() {
43 | NTSTATUS Status = STATUS_SUCCESS;
44 |
45 | if (!NT_SUCCESS(Status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallbackEx, FALSE)))
46 | {
47 | DbgPrint("[ PsProtect ] [ ERROR ] PsSetCreateProcessNotifyRoutineEx Resistering Failed : (%x)\n", Status);
48 | return Status;
49 | } else {
50 | DbgPrint("[ PsProtect ] [ SUCCESS ] PsSetCreateProcessNotifyRoutineEx Resistering Success\n");
51 | }
52 |
53 | return STATUS_SUCCESS;
54 |
55 | }
56 |
57 | VOID UnInstallProcessProtect() {
58 |
59 | if (!NT_SUCCESS(Status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallbackEx, TRUE))) {
60 | DbgPrint("[ PsProtect ] [ ERROR ] PsSetCreateProcessNotifyRoutineEx Unresistering Failed : (%x)\n", Status);
61 | } else {
62 | DbgPrint("[ PsProtect ] [ SUCCESS ] PsSetCreateProcessNotifyRoutineEx Unresistering Success\n");
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/threeProtection/RegMonitor.h:
--------------------------------------------------------------------------------
1 | #include "stdio.h"
2 |
3 |
4 | typedef struct _GLOBAL_CONTEXT {
5 | PDRIVER_OBJECT DriverObject;
6 | UNICODE_STRING Altitude;
7 | LARGE_INTEGER Cookie;
8 | } GLOBAL_CONTEXT, *PGLOBAL_CONTEXT;
9 |
10 | GLOBAL_CONTEXT g_GlobalContext = { 0 };
11 |
12 | UNICODE_STRING g_PolicyKeyArray[] = {
13 | RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\System\\CurrentControlSet\\Services\\myDriver"),
14 | RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\System\\ControlSet001\\Services\\myDriver"),
15 | RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\System\\ControlSet002\\Services\\myDriver"),
16 | RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\System\\ControlSet003\\Services\\myDriver")
17 | };
18 | ULONG g_PolicyKeyCount = sizeof(g_PolicyKeyArray) / sizeof(UNICODE_STRING);
19 |
20 |
21 | BOOLEAN
22 | CheckProcess(VOID) {
23 | PEPROCESS Process;
24 | PCHAR ImageFileName;
25 |
26 | Process = PsGetCurrentProcess();
27 |
28 | ImageFileName = PsGetProcessImageFileName(Process);
29 |
30 | if (_stricmp(ImageFileName, "services.exe") == 0) {
31 | return TRUE;
32 | }
33 |
34 | if (_stricmp(ImageFileName, "svchost.exe") == 0) {
35 | return TRUE;
36 | }
37 |
38 | return FALSE;
39 | }
40 |
41 |
42 | BOOLEAN CheckPolicy(PUNICODE_STRING KeyFullPath) {
43 |
44 | BOOLEAN Matched = FALSE;
45 | ULONG Idx;
46 |
47 | for (Idx = 0; Idx < g_PolicyKeyCount; Idx++) {
48 | if (RtlEqualUnicodeString(KeyFullPath, &g_PolicyKeyArray[Idx], TRUE)) {
49 | Matched = TRUE;
50 | break;
51 | }
52 | }
53 |
54 | if (Matched) {
55 | DbgPrint("[ RegMonitor ] pid(%x) and tid(%x) Block %wZ\n",
56 | PsGetCurrentProcessId(), PsGetCurrentThreadId(), KeyFullPath);
57 | }
58 |
59 | return Matched;
60 | }
61 |
62 |
63 | NTSTATUS RegPreDeleteKey(PVOID RootObject, PUNICODE_STRING CompleteName)
64 | {
65 | PUNICODE_STRING RootObjectName;
66 | ULONG_PTR RootObjectID;
67 | BOOLEAN Matched = FALSE;
68 | NTSTATUS Status;
69 | UNICODE_STRING KeyPath = { 0 };
70 |
71 | // CompleteName can have a absolute path or relative path.
72 | // That's why we should do more work.
73 |
74 | // If RootObject is not valid, It means CompleteName has full path.
75 | // If RootObject is valid, we should work more.
76 | if (RootObject) {
77 |
78 | // We store path from RootObject to RootObjectName using CmCallbackGetKeyObjectID()
79 | if (!NT_SUCCESS(Status = CmCallbackGetKeyObjectID(&g_GlobalContext.Cookie, RootObject, &RootObjectID, &RootObjectName)))
80 | {
81 | DbgPrint("[ RegMonitor ] [ ERROR ] CmCallbackGetKeyObjectID : %x\n", Status);
82 | goto Exit;
83 | }
84 |
85 | // If there is valid CompleteName, we should concatenate RootObjectName and CompleteName.
86 | // If there isn't, just use RootObjectName.
87 | if (CompleteName->Length && CompleteName->Buffer) {
88 |
89 | KeyPath.MaximumLength = RootObjectName->Length + CompleteName->Length + (sizeof(WCHAR) * 2);
90 |
91 | KeyPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, KeyPath.MaximumLength, 'pkMC');
92 |
93 | if (!KeyPath.Buffer) {
94 | DbgPrint("[ RegMonitor ] [ Error ] ExAllocatePool() FAIL\n");
95 | goto Exit;
96 | }
97 |
98 | swprintf(KeyPath.Buffer, L"%wZ\\%wZ", RootObjectName, CompleteName);
99 | KeyPath.Length = RootObjectName->Length + CompleteName->Length + (sizeof(WCHAR));
100 |
101 | Matched = CheckPolicy(&KeyPath);
102 | }
103 | else {
104 | Matched = CheckPolicy(RootObjectName);
105 |
106 | }
107 | }
108 | else {
109 | Matched = CheckPolicy(CompleteName);
110 | }
111 |
112 | Exit:
113 | // if a buffer was allocated in KeyPath.Buffer then free it
114 | if (KeyPath.Buffer) {
115 | ExFreePool(KeyPath.Buffer);
116 | }
117 | return Matched;
118 | }
119 |
120 |
121 | NTSTATUS RegistryFilterCallback(
122 | IN PVOID CallbackContext,
123 | IN PVOID Argument1,
124 | IN PVOID Argument2
125 | ) {
126 | NTSTATUS Status = STATUS_SUCCESS;
127 | REG_NOTIFY_CLASS NotifyClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;
128 |
129 | UNREFERENCED_PARAMETER(CallbackContext);
130 |
131 | if (CheckProcess()) {
132 | return STATUS_SUCCESS;
133 | }
134 |
135 | if (RegNtPreCreateKeyEx == NotifyClass || RegNtPreOpenKeyEx == NotifyClass)
136 | {
137 | PREG_CREATE_KEY_INFORMATION RegInformation = (PREG_CREATE_KEY_INFORMATION)Argument2;
138 |
139 | if (RegPreDeleteKey(RegInformation->RootObject, RegInformation->CompleteName))
140 | {
141 | DbgPrint("[ RegMonitor ] Prevent Opening Handle\n");
142 | Status = STATUS_ACCESS_DENIED;
143 | }
144 | }
145 |
146 | return Status;
147 | }
148 |
149 |
150 | NTSTATUS InstallRegMonitor(IN PDRIVER_OBJECT DriverObject)
151 | {
152 | NTSTATUS Status = STATUS_SUCCESS;
153 | RtlInitUnicodeString(&g_GlobalContext.Altitude, L"140831");
154 | g_GlobalContext.DriverObject = DriverObject;
155 |
156 | if (!NT_SUCCESS(Status = CmRegisterCallbackEx(
157 | RegistryFilterCallback,
158 | &g_GlobalContext.Altitude,
159 | DriverObject,
160 | &g_GlobalContext,
161 | &g_GlobalContext.Cookie,
162 | NULL
163 | ))) {
164 | DbgPrint("[ RegMonitor ] [ ERROR ] CmRegisterCallbackEx Failed : (%x)\n", Status);
165 | return Status;
166 | } else {
167 | DbgPrint("[ RegMonitor ] [ SUCCESS ] CmRegisterCallbackEx Success\n");
168 | }
169 |
170 | return STATUS_SUCCESS;
171 | }
172 |
173 |
174 | VOID UnInstallRegMonitor()
175 | {
176 | NTSTATUS Status;
177 |
178 | if (!NT_SUCCESS(Status = CmUnRegisterCallback(g_GlobalContext.Cookie))) {
179 | DbgPrint("[ RegMonitor ] [ ERROR ] CmUnRegisterCallback Failed (%x)\n", Status);
180 | return Status;
181 | } else {
182 | DbgPrint("[ RegMonitor ] [ SUCCESS ] CmUnRegisterCallback Success\n");
183 | }
184 | return STATUS_SUCCESS;
185 | }
186 |
--------------------------------------------------------------------------------
/threeProtection/SelfProtect.h:
--------------------------------------------------------------------------------
1 | #define PROCESS_TERMINATE (0x0001)
2 | #define PROCESS_VM_READ (0x0010)
3 | #define PROCESS_VM_WRITE (0x0020)
4 | #define PROCESS_VM_OPERATION (0x0008)
5 |
6 |
7 | OB_PREOP_CALLBACK_STATUS ObjectPreCallBack(IN PVOID RegistrationContext, IN POB_PRE_OPERATION_INFORMATION OperationInformation);
8 | VOID ObjectPostCallBack(IN PVOID RegistrationContext, IN POB_POST_OPERATION_INFORMATION OperationInformation);
9 | LPSTR GetProcessNameFromPid(HANDLE pid);
10 | NTSTATUS InstallProcessProtect();
11 | VOID UnInstallProcessProtect();
12 |
13 | extern UCHAR *PsGetProcessImageFileName(IN PEPROCESS Process);
14 |
15 | PVOID RegistrationHandle = NULL;
16 | HANDLE ProtectedProcess = NULL;
17 |
18 | PACCESS_MASK thisis = NULL;
19 | ACCESS_MASK thisis2 = 0;
20 |
21 |
22 | OB_PREOP_CALLBACK_STATUS
23 | ObjectPreCallBack(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation) {
24 |
25 | LPSTR ProcssName;
26 |
27 | PACCESS_MASK DesiredAccess = NULL;
28 | ACCESS_MASK OriginalDesiredAccess = 0;
29 |
30 | HANDLE ProcessIdOfTargetThread;
31 |
32 | if (OperationInformation->ObjectType == *PsProcessType) {
33 | if (OperationInformation->Object == PsGetCurrentProcess()) {
34 | //DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,"ObCallbackTest: CBTdPreOperationCallback: ignore process open/duplicate from the protected process itself\n");
35 | return OB_PREOP_SUCCESS;
36 | }
37 | } else if (OperationInformation->ObjectType == *PsThreadType) {
38 | ProcessIdOfTargetThread = PsGetThreadProcessId((PETHREAD)OperationInformation->Object);
39 | if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) {
40 | //DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,"ObCallbackTest: CBTdPreOperationCallback: ignore thread open/duplicate from the protected process itself\n");
41 | return OB_PREOP_SUCCESS;
42 | }
43 | } else {
44 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,"ObCallbackTest: CBTdPreOperationCallback: unexpected object type\n");
45 | return OB_PREOP_SUCCESS;
46 | }
47 |
48 | ProcssName = GetProcessNameFromPid(PsGetProcessId((PEPROCESS)OperationInformation->Object));
49 |
50 | if (OperationInformation->KernelHandle == 1) {
51 | //DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[ SelfProtect ] [ KERNEL ] ObjectPreCallback ----> Process Name [%s] \n", ProcssName);
52 | return OB_PREOP_SUCCESS;
53 | }
54 |
55 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[ SelfProtect ] [ USER ] ObjectPreCallback ----> Process Name [%s] \n", ProcssName);
56 |
57 | if (!_stricmp(ProcssName, "calc.exe")) {
58 | DbgPrint("[ SelfProtect ] It's notepad \n");
59 | if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) {
60 |
61 | DesiredAccess = &OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
62 | OriginalDesiredAccess = OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess;
63 |
64 | if ((OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE) {
65 | *DesiredAccess &= ~PROCESS_TERMINATE;
66 | DbgPrint("[ SelfProtect ] [ CreateHandleInformation ] Disabling terminate \n");
67 | }
68 |
69 | if ((OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION) {
70 | *DesiredAccess &= ~PROCESS_VM_OPERATION;
71 | DbgPrint("[ SelfProtect ] [ CreateHandleInformation ] Disabling vm operation \n");
72 | }
73 | if ((OriginalDesiredAccess & ~PROCESS_VM_READ) == PROCESS_VM_READ) {
74 | *DesiredAccess &= ~PROCESS_VM_READ;
75 | DbgPrint("[ SelfProtect ] [ CreateHandleInformation ] Disabling vm read \n");
76 | }
77 | if ((OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE) {
78 | *DesiredAccess &= ~PROCESS_VM_WRITE;
79 | DbgPrint("[ SelfProtect ] [ CreateHandleInformation ] Disabling vm write \n");
80 | }
81 |
82 | } else if (OperationInformation->Operation == OB_OPERATION_HANDLE_DUPLICATE) {
83 |
84 | DesiredAccess = &OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess;
85 | OriginalDesiredAccess = OperationInformation->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
86 |
87 | if ((OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE) {
88 | *DesiredAccess &= ~PROCESS_TERMINATE;
89 | DbgPrint("[ SelfProtect ] [ DuplicateHandleInformation ] Disabling terminate \n");
90 | }
91 | if ((OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION) {
92 | *DesiredAccess &= ~PROCESS_VM_OPERATION;
93 | DbgPrint("[ SelfProtect ] [ DuplicateHandleInformation ] Disabling vm operation \n");
94 | }
95 | if ((OriginalDesiredAccess & ~PROCESS_VM_READ) == PROCESS_VM_READ) {
96 | *DesiredAccess &= ~PROCESS_VM_READ;
97 | DbgPrint("[ SelfProtect ] [ DuplicateHandleInformation ] Disabling vm read \n");
98 | }
99 | if ((OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE) {
100 | *DesiredAccess &= ~PROCESS_VM_WRITE;
101 | DbgPrint("[ SelfProtect ] [ DuplicateHandleInformation ] Disabling vm write \n");
102 | }
103 |
104 | }
105 | }
106 |
107 | return OB_PREOP_SUCCESS;
108 | }
109 |
110 | VOID ObjectPostCallBack(IN PVOID RegistrationContext, IN POB_POST_OPERATION_INFORMATION OperationInformation) {
111 | }
112 |
113 |
114 | LPSTR GetProcessNameFromPid(HANDLE pid) {
115 |
116 | PEPROCESS Process;
117 |
118 | if (PsLookupProcessByProcessId(pid, &Process) == STATUS_INVALID_PARAMETER) {
119 | return "[ SelfProtect ] [ ERROR ] PID required.";
120 | }
121 |
122 | return (LPSTR)PsGetProcessImageFileName(Process);
123 |
124 | }
125 |
126 |
127 | NTSTATUS InstallSelfProtect() {
128 |
129 | NTSTATUS Status;
130 | OB_CALLBACK_REGISTRATION CallBackRegistration;
131 | OB_OPERATION_REGISTRATION OperationRegistration;
132 |
133 | OperationRegistration.ObjectType = PsProcessType;
134 | OperationRegistration.Operations = OB_OPERATION_HANDLE_CREATE; // For creating handle.
135 | OperationRegistration.PreOperation = ObjectPreCallBack; // Registering Callback function.
136 | OperationRegistration.PostOperation = ObjectPostCallBack;
137 |
138 | RtlInitUnicodeString(&CallBackRegistration.Altitude, L"370000");
139 | CallBackRegistration.Version = OB_FLT_REGISTRATION_VERSION;
140 | CallBackRegistration.OperationRegistrationCount = 1;
141 | CallBackRegistration.RegistrationContext = NULL;
142 | CallBackRegistration.OperationRegistration = &OperationRegistration;
143 |
144 | // [[ ObRegisterCallbacks() ]]
145 | if (!NT_SUCCESS(Status = ObRegisterCallbacks(&CallBackRegistration, &RegistrationHandle))) {
146 | DbgPrint("[ SelfProtect ] [ ERROR ] ObRegisterCallbacks Failed : (%x)\n", Status);
147 | return Status;
148 | } else {
149 | DbgPrint("[ SelfProtect ] [ SUCCESS ] ObRegisterCallbacks Success\n");
150 | }
151 |
152 | return STATUS_SUCCESS;
153 |
154 | }
155 |
156 | VOID UnInstallSelfProtect() {
157 |
158 | if (RegistrationHandle) {
159 | ObUnRegisterCallbacks(RegistrationHandle);
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/threeProtection/myDriver.c:
--------------------------------------------------------------------------------
1 | #include "myDriver.h"
2 | #include "SelfProtect.h"
3 | #include "RegMonitor.h"
4 | #include "PsProtect.h"
5 |
6 | NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
7 | {
8 | NTSTATUS Status = STATUS_SUCCESS;
9 |
10 | DriverObject->DriverUnload = DriverUnload;
11 |
12 | DbgPrint("[ myDriver ] Driver Loaded\n");
13 |
14 | // installing Self Protection
15 | InstallSelfProtect();
16 |
17 | // installing Register Monitor
18 | InstallRegMonitor(DriverObject);
19 |
20 | // installing Process Protection
21 | InstallProcessProtect();
22 |
23 | return Status;
24 | }
25 |
26 |
27 | VOID
28 | DriverUnload(PDRIVER_OBJECT DriverObject)
29 | {
30 | UnInstallSelfProtect();
31 |
32 | UnInstallRegMonitor();
33 |
34 | UnInstallProcessProtect();
35 |
36 | DbgPrint("[ myDriver ] Unloaded\n");
37 | }
38 |
--------------------------------------------------------------------------------
/threeProtection/myDriver.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 |
4 | NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
5 | VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
6 |
7 |
8 | #pragma alloc_text(INIT, DriverEntry)
9 |
--------------------------------------------------------------------------------