Этот драйвер позволяет защитить процесс от закрытия через диспетчер задач и другие подобные программы. Защита происходит на уровне ядра операционной системы методом перехвата функций ядра ОС, таких как 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.
