Protection process

Share your advanced PureBasic knowledge/code with the community.
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Protection process

Post by User_Russian »

Bring to your attention, one way, to protect the process of terminate. He founded the interception kernel functions such as NtOpenProcess and NtTerminateProcess. This is done by substitution of the addresses in the table SST (SYSTEM SERVICE TABLE). This is possible only, ring 0, operating system, and therefore need a driver.

Code drivers pbNoKill.sys.

Code: Select all

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 KernelDebug(String)
  CompilerIf #Debug = #True
    DbgPrint(@String)
  CompilerEndIf
EndMacro

EnableExplicit

Procedure NewNtOpenProcess(*ProcessHandle, DesiredAccess,
                           *ObjectAttributes, *ClientId.CLIENT_ID)
  Protected ProcessId
  
  If gMyPID<>0
    
;     If *ClientId > *MmUserProbeAddress
;       KernelDebug("*ClientId > *MmUserProbeAddress")
;       ProcedureReturn #STATUS_INVALID_PARAMETER
;     EndIf

    MOV   ebx, *ClientId
    CMP   ebx, *MmUserProbeAddress
    !JBE   newntopenprocess__m1
    KernelDebug("*ClientId > *MmUserProbeAddress")
    ProcedureReturn #STATUS_INVALID_PARAMETER
    !newntopenprocess__m1:
    
    If *ClientId
      ProcessId = *ClientId\UniqueProcess
    Else
      KernelDebug("*ClientId = 0")
      ProcedureReturn #STATUS_INVALID_PARAMETER
    EndIf
    
    If gMyPID = ProcessId
      KernelDebug("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
    KernelDebug("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
Code for works with the driver - a file DrUserModeFramework.pbi.

Code: Select all

Procedure Driver_Start(ServiceName.s) ; Запуск драйвера.
  Protected hSCManager.l, hServ.l, Result
  
  Result=#False
  hSCManager  = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
  If hSCManager = 0
    If GetLastError_() = #ERROR_ACCESS_DENIED
      hSCManager  = OpenSCManager_(#Null, #Null, #GENERIC_READ)
      hServ       = OpenService_(hSCManager, ServiceName, #GENERIC_EXECUTE)
      If StartService_(hServ, 0, #Null)
        Result=#True
      EndIf
    EndIf
    
  Else
    hServ       = OpenService_(hSCManager, ServiceName, #GENERIC_EXECUTE)
    If StartService_(hServ, 0, #Null)
      Result=#True  
    Else
      ErrorCode=GetLastError_()
      If ErrorCode=1056
        Result=#True
      EndIf
    EndIf
  EndIf
  
  If hServ : CloseServiceHandle_(hServ) : EndIf
  If hSCManager : CloseServiceHandle_(hSCManager) : EndIf
  
  ProcedureReturn Result
EndProcedure


Procedure Driver_UnInstall(ServiceName.s) ; Деинсталяция драйвера.
  Protected ServiceStatus.SERVICE_STATUS
  
  hSCManager  = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
  hServ       = OpenService_(hSCManager, ServiceName, #SERVICE_ALL_ACCESS)
  
  If hServ<>#Null
    ControlService=ControlService_(hServ, #SERVICE_CONTROL_STOP, @ServiceStatus)
     DeleteService_(hServ)
  EndIf
  
  If hServ : CloseServiceHandle_(hServ) : EndIf
  If hSCManager : CloseServiceHandle_(hSCManager) : EndIf
EndProcedure

Procedure Driver_Install(FileName.s, ServiceName.s, DisplayName.s) ; Инсталляция драйвера в систему.
  Protected Result, Mgr, Ser, Count
  Result=#False
  Count=0
    
    Driver_Install_M1:
    Mgr = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
    If Mgr
      Ser = CreateService_(Mgr, ServiceName, DisplayName, #SERVICE_ALL_ACCESS, #SERVICE_KERNEL_DRIVER, #SERVICE_SYSTEM_START, #SERVICE_ERROR_NORMAL, FileName, #Null, 0, 0, 0, 0)
      ErrorCode=GetLastError_()
      If Ser 
        Result=#True 
      ElseIf ErrorCode=1073
        Result=#True 
      ElseIf ErrorCode=1072
        If Count=0
          
          If Ser : CloseServiceHandle_(Ser) : EndIf
          If Mgr : CloseServiceHandle_(Mgr) : EndIf
          Driver_UnInstall(ServiceName)
          Count+1
          Goto Driver_Install_M1
        EndIf
      EndIf
    EndIf

  
  If Ser : CloseServiceHandle_(Ser) : EndIf
  If Mgr : CloseServiceHandle_(Mgr) : EndIf
  
  ProcedureReturn Result
EndProcedure

Procedure OpenDriver(FileName.s, DriverName.s, ServiceName.s, DisplayName.s)
  Protected Result, hDriver
  Result=0
  
  hDriver = CreateFile_("\\.\"+DriverName, #GENERIC_READ | #GENERIC_WRITE, 0, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
  If hDriver=#INVALID_HANDLE_VALUE
    If Driver_Install(FileName, ServiceName, DisplayName)
      If Driver_Start(ServiceName)
        hDriver = CreateFile_("\\.\"+DriverName, #GENERIC_READ | #GENERIC_WRITE, 0, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
        If hDriver <> #INVALID_HANDLE_VALUE
          Result=hDriver
        EndIf
      EndIf
    EndIf
  Else
    Result=hDriver
  EndIf
  
  ProcedureReturn Result
EndProcedure
The test code which demonstrates operation of driver.

Code: Select all

XIncludeFile "DrUserModeFramework.pbi"

#IOCTL_NewPid = $200

#DrName = "pbNoKill"

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("", "The program is already running!", #MB_ICONWARNING)
  End
EndIf

hDriver=OpenDriver(GetPathPart(ProgramFilename())+#DrName+".sys", #DrName, #DrName, #DrName)

If hDriver=0 
  Driver_UnInstall(#DrName)
  MessageRequester("", "Failed to load driver")
  End
EndIf

PID = GetCurrentProcessId_()

Code = DeviceIoControl_(hDriver, #IOCTL_NewPid, @PID, 4, 0, 0, @BytesReturned, 0)
If Code 

OpenWindow(0, 0, 0, 222, 200, "Test "+#DrName, #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(0, 4, 10, 210, 30, "Try to complete the process of this program with Task Manager")
ButtonGadget(4, 10,170, 200, 20, "Close")
Repeat 
  Event = WaitWindowEvent()
  If Event = #PB_Event_Gadget
    If EventGadget()=4
      Break
    EndIf
  EndIf
ForEver

Else
  Code = GetLastError_()
  MessageRequester("", "Error "+Str(Code)+" when applying to the driver")
EndIf

CloseHandle_(hDriver)
Driver_UnInstall(#DrName)
CloseHandle_(g_hSemaphore_runonly)
You can not terminate the process the program, using Task Manager.

Download files
Toni6
User
User
Posts: 45
Joined: Mon Apr 23, 2012 1:39 pm

Re: Protection process

Post by Toni6 »

nice work :shock:
It may come in handy in a near future.

Code: Select all

!JBE   newntopenprocess__m1
would be nice to have unsigned integers in pb.
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Protection process

Post by User_Russian »

Toni6 wrote:would be nice to have unsigned integers in pb.
I agree.
I requested about this, but there is no answer. :( :(
http://www.purebasic.fr/english/viewtop ... 38#p414638
http://www.purebasic.fr/english/viewtop ... =3&t=54966
Toni6
User
User
Posts: 45
Joined: Mon Apr 23, 2012 1:39 pm

Re: Protection process

Post by Toni6 »

User_Russian wrote:
Toni6 wrote:would be nice to have unsigned integers in pb.
I agree.
I requested about this, but there is no answer. :( :(
http://www.purebasic.fr/english/viewtop ... 38#p414638
http://www.purebasic.fr/english/viewtop ... =3&t=54966
If it's not added i may try to do a compiler hack and add it myself :mrgreen:
CodeCave
User
User
Posts: 16
Joined: Wed Jun 19, 2013 10:50 pm

Re: Protection process

Post by CodeCave »

"You can not terminate the process the program, using Task Manager."
U can actually achieve the same with a 1 byte patch...
Just patch the TerminateProcess function in the taskmanager so it fails executing... ^^

However a driver enables u to do much much more :>

Some snipped i had in on my hd (dont know the original author):

Code: Select all

Procedure.q getULong(*source.Long)
   ;- Reads 4 bytes from the specified memory address,
   ;  and returns the value as *unsigned* integer
   ;  (minimum = 0, maximum = 4294967295).
   If *source\l < 0
      ProcedureReturn *source\l + $100000000
   Else
      ProcedureReturn *source\l
   EndIf
EndProcedure
 
Procedure setULong(*target.Long, source.q)
   ;- Writes an *unsigned* integer of 4 bytes size
   ;  to the specified memory address.


   If source >= 0 And source <= $FFFFFFFF
      If source > $7FFFFFFF
         *target\l = source - $100000000
      Else
         *target\l = source
      EndIf
   EndIf
EndProcedure

Procedure.q fromULong(source.l)
  ProcedureReturn getULong(@source)
EndProcedure
 
Procedure.l toULong(source.q)
  Define result.l
  setULong(@result, source)
  ProcedureReturn result
EndProcedure
firsttimer
New User
New User
Posts: 2
Joined: Fri Sep 19, 2014 1:09 am

Re: Protection process

Post by firsttimer »

Can made abit more powerful against tools such as kernel detective/process hacker?

Thanks.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Protection process

Post by bbanelli »

It seems to work only on XP; tried on Vista, 7 and 10 but it says "Failed to load driver".
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Protection process

Post by User_Russian »

bbanelli wrote:tried on Vista, 7 and 10 but it says "Failed to load driver".
OS x86 or x64?
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Protection process

Post by bbanelli »

User_Russian wrote:
bbanelli wrote:tried on Vista, 7 and 10 but it says "Failed to load driver".
OS x86 or x64?
Sorry, forgot to mention - x64.

What is the exact procedure to compile drivers on PureBasic? I have quickly glanced through some of your related posts but didn't find any exact cook books... :)
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Re: Protection process

Post by cas »

You can use startup option "disable driver signature enforcement" to test/debug your driver but if you want to release it to other people then you need to buy certificate to sign driver.

More info here: http://msdn.microsoft.com/en-us/library ... s.85).aspx
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Protection process

Post by User_Russian »

Package files for PB x86 only.
Creating x64 drivers in PB is possible, but does not make sense, because for work x64 drivers required digital signature.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Protection process

Post by bbanelli »

User_Russian wrote:Package files for PB x86 only.
Creating x64 drivers in PB is possible, but does not make sense, because for work x64 drivers required digital signature.
Something like this?

Image

Could you try making x64 version so we could see if the proof of concept works? Or does it takes too much rewriting of existing code?
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
ToniPB
User
User
Posts: 13
Joined: Tue Dec 16, 2014 3:44 am

Re: Protection process

Post by ToniPB »

This is not gonna work in x64 without patching Patch Guard (KPP).

Patch Guard (KPP) = http://msdn.microsoft.com/en-us/library ... 85%29.aspx

The best way to do this in x64 without patching Patch Guard is using ObRegisterCallback, which is what most Firewalls, Internet Security Suites use this days.

ObRegisterCallback = http://msdn.microsoft.com/en-us/library ... 85%29.aspx
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Re: Protection process

Post by Rescator »

FIY, for those curious it should be possible to achieve the same using Windows permissions, that way a system admin can prevent users from killing programs. I can't recall exactly where you set these permissions but some else here might now.
Then again, if you make sure a user is a regular user (i.e. create them as a non-admin) then they can't kill admin nor system services anyway.
User avatar
kryptonn
User
User
Posts: 47
Joined: Wed Apr 18, 2007 7:23 pm

Re: Protection process

Post by kryptonn »

User_Russian wrote:Bring to your attention, one way, to protect the process of terminate.
"Bring to your attention one way", how easy kill this process: http://youtu.be/XTo2GsLPxOA
Post Reply