Этот драйвер позволяет защитить процесс от закрытия через диспетчер задач и другие подобные программы. Защита происходит на уровне ядра операционной системы методом перехвата функций ядра ОС, таких как NtOpenProcess() и NtTerminateProcess(). Работает в винде от Windows 2000 до Windows 8 включительно.
Код предназначен для компиляции в среде программирования PureBasic 5.11.
Declare DriverEntry(*DriverObject, *RegistryPath) ; Объявляем прототип True функции для перехватываемой функции. Prototype pNtOpenProcess(*ProcessHandle, DesiredAccess, *ObjectAttributes, *ClientId) Prototype.i pNtTerminateProcess(ProcessHandle.i, ExitStatus.i) Global TrueNtOpenProcess.pNtOpenProcess=0 ; Оригинальная функция из ядра. Global TrueNtTerminateProcess.pNtTerminateProcess=0 ; Оригинальная функция из ядра. Global gOpenProcId=0, gTerminateProcId=0, gMyPID.l=0 *A=@DriverEntry() !jmp [p_A] #Debug = #False ; #True IncludePath #PB_Compiler_Home+"DDK\" XIncludeFile "ntddk.pbi" XIncludeFile "ntstatus.pbi" XIncludeFile "ntfunct.pbi" Import "ntoskrnl.lib" *KeServiceDescriptorTable.SERVICE_DESCRIPTOR_TABLE As "__imp__KeServiceDescriptorTable" *NtBuildNumber.Unicode As "__imp__NtBuildNumber" *MmUserProbeAddress As "__imp__MmUserProbeAddress" EndImport #IOCTL_NewPid = $200 Macro NTCALL(_function) *KeServiceDescriptorTable\ntoskrnl\ServiceTable\ar[_function] EndMacro Macro CernelDebug(String) CompilerIf #Debug = #True DbgPrint(@String) CompilerEndIf EndMacro EnableExplicit EnableASM Procedure NewNtOpenProcess(*ProcessHandle, DesiredAccess, *ObjectAttributes, *ClientId.CLIENT_ID) Protected ProcessId If gMyPID<>0 MOV ebx, *ClientId CMP ebx, *MmUserProbeAddress JBE l_newntopenprocess_m1 CernelDebug("*ClientId > *MmUserProbeAddress") ProcedureReturn #STATUS_INVALID_PARAMETER m1: If *ClientId ProcessId = *ClientId\UniqueProcess Else CernelDebug("*ClientId = 0") ProcedureReturn #STATUS_INVALID_PARAMETER EndIf If gMyPID = ProcessId CernelDebug("My Process") ProcedureReturn #STATUS_ACCESS_DENIED Else Goto m2 EndIf Else m2: If TrueNtOpenProcess ProcedureReturn TrueNtOpenProcess(*ProcessHandle, DesiredAccess, *ObjectAttributes, *ClientId) Else ProcedureReturn #STATUS_INVALID_ADDRESS EndIf EndIf EndProcedure Procedure GetPID(ProcessHandle) Protected *obj, ProcessId ProcessId = $FFFFFFFF If ObReferenceObjectByHandle(ProcessHandle, 0 ,0, #KernelMode, @*obj,#Null) = #STATUS_SUCCESS ProcessId = PsGetProcessId(*obj) ObDereferenceObject(*obj) EndIf ProcedureReturn ProcessId EndProcedure Procedure.i NewNtTerminateProcess(ProcessHandle.i, ExitStatus.i) If gMyPID<> 0 And GetPID(ProcessHandle) = gMyPID CernelDebug("Terminate my process") ProcedureReturn #STATUS_ACCESS_DENIED Else If TrueNtTerminateProcess ProcedureReturn TrueNtTerminateProcess(ProcessHandle, ExitStatus) Else ProcedureReturn #STATUS_INVALID_ADDRESS EndIf EndIf EndProcedure Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP) Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION Protected inBuffersize, outBuffersize, CtrlBuff.l Protected Code *Stack = *pIrp\Tail\Overlay\CurrentStackLocation inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength If inBuffersize>=4 CtrlBuff = PeekL(*pIrp\SystemBuffer) Code = *Stack\Parameters\DeviceIoControl\IoControlCode ntStatus = #STATUS_SUCCESS Select Code Case #IOCTL_NewPid gMyPID = CtrlBuff Default ntStatus = #STATUS_UNSUCCESSFUL EndSelect Else ntStatus = #STATUS_BUFFER_TOO_SMALL EndIf *pIrp\IoStatus\Information = 0 *pIrp\IoStatus\Status = ntStatus IoCompleteRequest(*pIrp, #IO_NO_INCREMENT) ProcedureReturn ntStatus EndProcedure Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP) *pIrp\IoStatus\Information = 0 *pIrp\IoStatus\Status = #STATUS_SUCCESS IoCompleteRequest(*pIrp, #IO_NO_INCREMENT) ProcedureReturn #STATUS_SUCCESS EndProcedure Macro UnInterception() CLI ; запрещаем прерывания MOV eax, cr0 MOV CR0Reg,eax AND eax,$FFFEFFFF ; сбросить WP bit MOV cr0, eax If TrueNtOpenProcess NTCALL(gOpenProcId) = TrueNtOpenProcess EndIf If TrueNtTerminateProcess NTCALL(gTerminateProcId) = TrueNtTerminateProcess EndIf MOV eax, CR0Reg MOV cr0, eax ; востановить содержимое CR0 STI ; разрешаем прерывания EndMacro Procedure DriverUnload(*DriverObject.DRIVER_OBJECT) Protected uniDOSString.UNICODE_STRING Protected CR0Reg.i UnInterception() RtlInitUnicodeString(@uniDOSString, ?DosDevices) IoDeleteSymbolicLink (@uniDOSString) IoDeleteDevice(*DriverObject\DeviceObject) EndProcedure Macro Interception() Select *NtBuildNumber\u Case 2195 ; Win 2000 gOpenProcId = $06A gTerminateProcId = 0 ; Не перехватывать, т. к. в ядре отсутствует Native фукнция PsGetProcessId()! Case 2600 ; Win XP gOpenProcId = $07A gTerminateProcId = $101 Case 3790 ; Win 2003. gOpenProcId = $80 gTerminateProcId = $10A Case 6000, ; Win Vista RTM. 6001, ; Win Vista SP1 и Win Server 2008 RTM. 6002 ; Win Vista SP2 и Win Server 2008 SP2. gOpenProcId = $C2 If *NtBuildNumber\u=6000 gTerminateProcId = $152 Else gTerminateProcId = $14e EndIf Case 7600, ; Win 7 RTM и Win Server 2008 R2 RTM. 7601 ; Win 7 SP1 и Win Server 2008 R2 SP1. gOpenProcId = $BE gTerminateProcId = $172 Case 9200 ; Win 8. gOpenProcId = 0 ; Не перехватывать, т. к. BSoD. gTerminateProcId = $23 Default ProcedureReturn #STATUS_NOT_IMPLEMENTED EndSelect ; Устанавливаем перехваты. If gOpenProcId>0 TrueNtOpenProcess = NTCALL(gOpenProcId) If TrueNtOpenProcess = 0 ProcedureReturn #STATUS_INVALID_ADDRESS EndIf Else TrueNtOpenProcess = 0 EndIf If gTerminateProcId>0 TrueNtTerminateProcess = NTCALL(gTerminateProcId) If TrueNtTerminateProcess = 0 ProcedureReturn #STATUS_INVALID_ADDRESS EndIf Else TrueNtTerminateProcess = 0 EndIf CLI ; запрещаем прерывания MOV eax, cr0 MOV CR0Reg,eax AND eax,$FFFEFFFF ; сбросить WP bit MOV cr0, eax If gOpenProcId>0 NTCALL(gOpenProcId) = @NewNtOpenProcess() EndIf If gTerminateProcId>0 NTCALL(gTerminateProcId) = @NewNtTerminateProcess() EndIf MOV eax, CR0Reg MOV cr0, eax ; востановить содержимое CR0 STI ; разрешаем прерывания EndMacro Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING) Protected deviceObject.DEVICE_OBJECT Protected uniNameString.UNICODE_STRING Protected uniDOSString.UNICODE_STRING, status Protected CR0Reg.i If *KeServiceDescriptorTable And *NtBuildNumber Interception() RtlInitUnicodeString(@uniNameString, ?Device) RtlInitUnicodeString(@uniDOSString, ?DosDevices) status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject) If status <> #STATUS_SUCCESS UnInterception() ProcedureReturn status EndIf status = IoCreateSymbolicLink(@uniDOSString, @uniNameString) If status <> #STATUS_SUCCESS IoDeleteDevice(@deviceObject) ; Мы должны сами убирать "хвосты" в режиме ядра! UnInterception() ProcedureReturn status EndIf *DriverObject\DriverUnload = @DriverUnload() *DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch() *DriverObject\MajorFunction[#IRP_MJ_CLOSE] = @CreateDispatch() *DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl() ProcedureReturn #STATUS_SUCCESS Else ProcedureReturn #STATUS_INVALID_SYSTEM_SERVICE EndIf EndProcedure DataSection CompilerSelect #PB_Compiler_Processor CompilerCase #PB_Processor_x86 Device: !du '\Device\pbNoKill', 0, 0 DosDevices: !du '\DosDevices\pbNoKill', 0, 0 CompilerCase #PB_Processor_x64 Device: !du '\Device\pbNoKill_x64', 0, 0 DosDevices: !du '\DosDevices\pbNoKill_x64', 0, 0 CompilerEndSelect EndDataSection
Код этого драйвера и его модификации можно найти в папке "Examples\Driver\pbNoKill" среды программирования PureBasic 5.11.
Пример защиты приложения используя этот драйвер.
XIncludeFile "DrUserModeFramework.pbi" #IOCTL_NewPid = $200 #IOCTL_DelPid = $400 SetCurrentDirectory(GetPathPart(ProgramFilename())) g_hSemaphore_runonly = CreateSemaphore_(#Null,0,1,"pbNoKilltest_runs") If g_hSemaphore_runonly And GetLastError_()=#ERROR_ALREADY_EXISTS CloseHandle_(g_hSemaphore_runonly) MessageRequester("", "Программа уже работает!", #MB_ICONWARNING) End EndIf OSv = OSVersion() If OSv<#PB_OS_Windows_2000 Or OSv>#PB_OS_Windows_8 MessageRequester("", "ОС не поддерживается") End EndIf hDriver=OpenDriver(GetPathPart(ProgramFilename())+"pbNoKill.sys", "pbNoKill", "pbNoKill", "pbNoKill") If hDriver=0 Driver_UnInstall("pbNoKill") MessageRequester("", "Не удалось загрузть драйвер") End EndIf PID = GetCurrentProcessId_() Code = DeviceIoControl_(hDriver, #IOCTL_NewPid, @PID, 4, 0, 0, @BytesReturned, 0) If Code OpenWindow(0, 0, 0, 222, 200, "ButtonGadgets", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) TextGadget(0, 4, 10, 210, 30, "Попробуй завершить процесс этой проги с помощью диспетчера задач") ButtonGadget(4, 10,170, 200, 20, "Закрыть") Repeat Event = WaitWindowEvent() If Event = #PB_Event_Gadget If EventGadget()=4 Break EndIf EndIf ForEver Else Code = GetLastError_() MessageRequester("", "Ошибка "+Str(Code)+" при обращении к драйверу") EndIf CloseHandle_(hDriver) Driver_UnInstall("pbNoKill") CloseHandle_(g_hSemaphore_runonly)
Найти этот пример, а так же файл DrUserModeFramework.pbi можно в папке "Examples\Driver\pbNoKill\NtOpenProcess и NtTerminateProcess" среды программирования PureBasic 5.11.