├── 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 | --------------------------------------------------------------------------------