permanent process remover (NT,W2k,XP)

Share your advanced PureBasic knowledge/code with the community.
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post by thefool »

Thanks :D
Hi-Toro
Enthusiast
Enthusiast
Posts: 269
Joined: Sat Apr 26, 2003 3:23 pm

Post by Hi-Toro »

I posted that code which says it doesn't work on '9x or NT4. Although the code below won't work on NT4 (you will need PSAPI for that), this will list processes on '9x.

(It appears that if you use the Process32First/Next calls inside a function they fail on '9x! You can use the code below in a Gosub/Return though.)

Code: Select all

; -----------------------------------------------------------------------------
; List running processes (9x, ME, 2000 and XP -- not NT4)...
; -----------------------------------------------------------------------------
; james @ hi - toro . com
; -----------------------------------------------------------------------------

; Snapshot requirements...

#TH32CS_SNAPPROCESS = $2

; Library number...

#KERNEL32LIB = 999

; -----------------------------------------------------------------------------
; Structure required...
; -----------------------------------------------------------------------------

Structure PROCESSENTRY32
    dwSize.l
    cntUsage.l
    th32ProcessID.l
    th32DefaultHeapID.l
    th32ModuleID.l
    cntThreads.l
    th32ParentProcessID.l
    pcPriClassBase.l
    dwFlags.l
    szExeFile.b [#MAX_PATH]
EndStructure

; -----------------------------------------------------------------------------
; List all processes. Won't work on NT4 (should use PSAPI)...
; -----------------------------------------------------------------------------

; IMPORTANT: If you try to place this stuff into a function, it will fail on Windows
; 9x for no apparent reason! Using it in Gosub/Return is fine...

If OpenLibrary (#KERNEL32LIB, "kernel32.dll")

    DefType.PROCESSENTRY32 Proc32
    Proc32\dwSize = SizeOf (PROCESSENTRY32)

    ; Get snapshot of running processes...
    
    snap = CallFunction (#KERNEL32LIB, "CreateToolhelp32Snapshot", #TH32CS_SNAPPROCESS, 0)

    If snap

        If CallFunction (#KERNEL32LIB, "Process32First", snap, @Proc32)
            Debug PeekS (@Proc32\szExeFile)
            While CallFunction (#KERNEL32LIB, "Process32Next", snap, @Proc32)
                Debug PeekS (@Proc32\szExeFile)
            Wend
        EndIf    

        CloseHandle_ (snap)

    EndIf

    CloseLibrary (#KERNEL32LIB)

EndIf
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
Max.²
Enthusiast
Enthusiast
Posts: 175
Joined: Wed Jul 28, 2004 8:38 am

Post by Max.² »

Rings wrote:Also is the Kill procedure is not able to kill everything (i mean everything, also services). You have to be in a special mode (security rights),So for the first time i use pskill from sysinternals, but i will investigate more time in that later.
I tried to enhance it a bit so it doesn't rely on pskill anymore to kill the processes. It works for me (I killed anything to a state only a reset worked :wink:) and I hope it does also for the people who are interested.

There are 2 major changes to it:

1.

A procedure AssignDebugPrivileges, that enables the required privilege which is disabled by default for administrators.

Note that there is a difference between non-existent->disabled->enabled. Also by default, that privilege is non-existent for non-administrators and a non-existent privilege cannot be enabled.

Code: Select all

Procedure AssignDebugPrivilege()
  
  
  #TOKEN_QUERY = $8
  #TOKEN_ADJUST_PRIVILEGES = $20
   
  #SE_DEBUG_NAME = "SeDebugPrivilege"
  
  Priv.TOKEN_PRIVILEGES
  PrivOld.TOKEN_PRIVILEGES
  
  cbPriv = SizeOf(PrivOld)
  
  hToken.l
  
  Result = OpenThreadToken_(GetCurrentThread_(), #TOKEN_QUERY|#TOKEN_ADJUST_PRIVILEGES, #True, @hToken.l)
  
  If Result=#False
    If GetLastError_()<>#ERROR_NO_TOKEN
      ProcedureReturn #False
    EndIf
    
    If OpenProcessToken_(GetCurrentProcess_(),#TOKEN_QUERY|#TOKEN_ADJUST_PRIVILEGES,@hToken)=#False
      ProcedureReturn #False
    EndIf 
  EndIf
  
  Priv\PrivilegeCount = 1
  Priv\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED
  LookupPrivilegeValue_(0, #SE_DEBUG_NAME, @Priv\Privileges[0]\Luid)
  
  If AdjustTokenPrivileges_(hToken,#False,@Priv,SizeOf(Priv),@PrivOld,@cbPriv)=#False
    dwError = GetLastError_()
    CloseHandle_(hToken)
    ProcedureReturn SetLastError_(dwError)
  EndIf 
   
  If GetLastError_() = #ERROR_NOT_ALL_ASSIGNED
    CloseHandle_(hToken)
    ProcedureReturn SetLastError_(#ERROR_ACCESS_DENIED)
  EndIf
    
  ProcedureReturn #True
  
EndProcedure
2.

The KillProcess Procedure was renamed to RKillProcedure, to not interfere with existing libraries.

Further, the reference to pskill.exe was removed and substituted by an OpenProcess / TerminateProcess combo.

Code: Select all

Procedure RKillProcess(pID)

  pHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #false, pID)
  Result=TerminateProcess_(pHandle,0)
  
  ProcedureReturn Result

EndProcedure

Minor changes in the main loop, as you can see from the whole code below. File deletion was disabled (commented), which probably is a major change for people who want to try it on system services.
:twisted:

USE AT YOUR OWN RISK!

Code: Select all

; Author: Rings
; Date: 8. July 2004
; List processes on WinNT and kill un-wanted ones. 
; to prevent pc from unwanted trojaners
; (i need that to kill winservicess.ex on customers pc's )
; Works with PSKILL.exe from syst-internals
; download PSKill.exe at http://www.sysinternals.com/files/pskill.zip 
;
; modified 13. January 2005 by Max. 
; KillProcess was renamed to RKillProcess and the reference to PSKILL.exe substituted with API calls
; AssignDebugPrivileges was added so OpenProcess also works on special programs (SYSTEM services e.g.)
; File deletion was commented for safety
; USE AT YOUR OWN RISK!

#PROCESS_QUERY_INFORMATION = $400

#READ_CONTROL = $20000
#STANDARD_RIGHTS_EXECUTE = #READ_CONTROL
#STANDARD_RIGHTS_READ = #READ_CONTROL
#STANDARD_RIGHTS_WRITE = #READ_CONTROL



#TOKEN_ADJUST_DEFAULT = $80
#TOKEN_ADJUST_PRIVILEGES  = $20 
#TOKEN_ADJUST_GROUPS = $40
#TOKEN_ADJUST_SESSIONID = $100
#TOKEN_ASSIGN_PRIMARY = $1
#TOKEN_DUPLICATE = $2
#TOKEN_QUERY = $8 

#TOKEN_EXECUTE = #STANDARD_RIGHTS_EXECUTE

#TOKEN_IMPERSONATE = $4

#TOKEN_QUERY_SOURCE = $10

#TOKEN_READ = #STANDARD_RIGHTS_READ | #TOKEN_QUERY
#TOKEN_WRITE = #STANDARD_RIGHTS_WRITE  | #TOKEN_ADJUST_PRIVILEGES

#TOKEN_ALL_ACCESS = #TOKEN_ADJUST_DEFAULT | #TOKEN_ADJUST_PRIVILEGES | #TOKEN_ADJUST_GROUPS | #TOKEN_ADJUST_SESSIONID | #TOKEN_DUPLICATE | #TOKEN_ASSIGN_PRIMARY | #TOKEN_QUERY | #TOKEN_EXECUTE



Enumeration
  #Window_0
EndEnumeration
Enumeration
  #Listview_0
  #String_0
  #CheckBox_0
  #Text_0
  #Text_1
  #Listview_1
  #Listview_2
EndEnumeration
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 290, 108, 665, 345,  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar , "'NotNeeded' a permanent Process and File Killer by Siegfried Rings")
    If CreateGadgetList(WindowID())
      ListViewGadget(#Listview_0, 10, 30, 220, 60)
      StringGadget(#String_0, 380, 30, 40, 20, "1000", #PB_String_Numeric)
      CheckBoxGadget(#CheckBox_0, 260, 30, 120, 20, "Scan every msecs")
      TextGadget(#Text_0, 10, 10, 230, 20, "Processes to Kill:")
      TextGadget(#Text_1, 10, 90, 230, 20, "Processes that have been killed:")
      ListViewGadget(#Listview_1, 10, 110, 450, 230)
      SetGadgetState(#CheckBox_0,1)
      ListViewGadget(#Listview_2, 460, 10, 200, 330)
    EndIf
  EndIf
EndProcedure

Structure PROCESS_MEMORY_COUNTERS 
   cb.l 
   PageFaultCount.l 
   PeakWorkingSetSize.l 
   WorkingSetSize.l 
   QuotaPeakPagedPoolUsage.l 
   QuotaPagedPoolUsage.l 
   QuotaPeakNonPagedPoolUsage.l 
   QuotaNonPagedPoolUsage.l 
   PageFileUsage.l 
   PeakPagefileUsage.l 
EndStructure 

#OWNER_SECURITY_INFORMATION = $00000001 
#GROUP_SECURITY_INFORMATION = $00000002 
#DACL_SECURITY_INFORMATION  = $00000004 
#SACL_SECURITY_INFORMATION  = $00000008 
#PROCESS_TERMINATE          = $0001 
#PROCESS_CREATE_THREAD      = $0002  
#PROCESS_SET_SESSIONID      = $0004  
#PROCESS_VM_OPERATION       = $0008  
#PROCESS_VM_READ            = $0010  
#PROCESS_VM_WRITE           = $0020  
#PROCESS_DUP_HANDLE         = $0040  
#PROCESS_CREATE_PROCESS     = $0080  
#PROCESS_SET_QUOTA          = $0100  
#PROCESS_SET_INFORMATION    = $0200  
#PROCESS_QUERY_INFORMATION  = $0400  
#PROCESS_ALL_ACCESS         = #STANDARD_RIGHTS_REQUIRED | #SYNCHRONIZE | $FFF 


#NbProcessesMax = 10000 
Dim ProcessesArray(#NbProcessesMax) 

AppPath.s=Space(1024)
GetCurrentDirectory_(1024,@AppPath.s)
Global IniFile.s
Parameter$ = ProgramParameter() 
If Parameter$ <>""
 IniFile=Parameter$
Else
 IniFile=AppPath.s+"\Notneeded.ini"
EndIf
Debug IniFile
NewList NotNeeded.s()
Procedure GetnotNeeded()
 ResetList(NotNeeded())               ; Reset the list index before the first element.
 If ReadFile(1,IniFile)
  While Eof(1)=0
   Text$ = ReadString() 
   If Trim(text$)<>""
    AddElement(NotNeeded())
    NotNeeded()=Trim(LCase(text$))
    AddGadgetItem(#Listview_0,-1,NotNeeded())
   EndIf
  Wend
  CloseFile(1)
 EndIf
EndProcedure


Procedure RKillProcess(pID)
;Max - procedure renamed and rewritten

  pHandle = OpenProcess_(#PROCESS_ALL_ACCESS, #false, pID)
  Result=TerminateProcess_(pHandle,0)
  
  ProcedureReturn Result

EndProcedure

Procedure AssignDebugPrivilege()
;Max - procedure added  
  
  #TOKEN_QUERY = $8
  #TOKEN_ADJUST_PRIVILEGES = $20
   
  #SE_DEBUG_NAME = "SeDebugPrivilege"
  
  Priv.TOKEN_PRIVILEGES
  PrivOld.TOKEN_PRIVILEGES
  
  cbPriv = SizeOf(PrivOld)
  
  hToken.l
  
  Result = OpenThreadToken_(GetCurrentThread_(), #TOKEN_QUERY|#TOKEN_ADJUST_PRIVILEGES, #True, @hToken.l)
  
  If Result=#False
    If GetLastError_()<>#ERROR_NO_TOKEN
      ProcedureReturn #False
    EndIf
    
    If OpenProcessToken_(GetCurrentProcess_(),#TOKEN_QUERY|#TOKEN_ADJUST_PRIVILEGES,@hToken)=#False
      ProcedureReturn #False
    EndIf 
  EndIf
  
  Priv\PrivilegeCount = 1
  Priv\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED
  LookupPrivilegeValue_(0, #SE_DEBUG_NAME, @Priv\Privileges[0]\Luid)
  
  If AdjustTokenPrivileges_(hToken,#False,@Priv,SizeOf(Priv),@PrivOld,@cbPriv)=#False
    dwError = GetLastError_()
    CloseHandle_(hToken)
    ProcedureReturn SetLastError_(dwError)
  EndIf 
   
  If GetLastError_() = #ERROR_NOT_ALL_ASSIGNED
    CloseHandle_(hToken)
    ProcedureReturn SetLastError_(#ERROR_ACCESS_DENIED)
  EndIf
    
  ProcedureReturn #True
  
EndProcedure


Procedure DoProcessListNt() 
  ClearGadgetItemList(#Listview_2) 
  If OpenLibrary(0, "psapi.dll") 
  
    EnumProcesses      = IsFunction(0, "EnumProcesses") 
    EnumProcessModules = IsFunction(0, "EnumProcessModules") 
    GetModuleBaseName  = IsFunction(0, "GetModuleBaseNameA")
    GetModuleBaseNameFull  = IsFunction(0, "GetModuleFileNameExA")  
Debug GetModuleBaseNameFull
    If EnumProcesses And EnumProcessModules And GetModuleBaseName  ; Be sure we have detected all the functions 
      
      CallFunctionFast(EnumProcesses, ProcessesArray(), #NbProcessesMax, @nProcesses) 
      
      For k=1 To nProcesses/4 
        PID=ProcessesArray(k-1)
        hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ, 0, PID) 
        
        If hProcess 
          CallFunctionFast(EnumProcessModules, hProcess, @BaseModule, 4, @cbNeeded) 
          
          Name$ = Space(255) 
          CallFunctionFast(GetModuleBaseName, hProcess, BaseModule, @Name$, Len(Name$)) 
          FullName$=Space(1024)
          CallFunctionFast(GetModuleBaseNameFull,hProcess, BaseModule, @FullName$, Len(FullName$)) 

          Debug Str(PID) +  Name$ 
          Name$=Trim(LCase(Name$))
          CloseHandle_(hProcess) 
          AddGadgetItem(#Listview_2,0,Str(PID) +" "+Name$)
       
          ResetList(NotNeeded())
          While NextElement(NotNeeded()) 
           If NotNeeded()=Name$
            ;Debug "Yes is in List !"
            ;Now kill Process
            If CountGadgetItems(#Listview_1)>200 
             ClearGadgetItemList(#Listview_1) 
            EndIf
;Max. - calling the renamed KillProcess procedure, added a check if it really was killed and changed PID parameter to long
;       from string
            If RKillProcess(PID) ;Name$)
             AddGadgetItem(#Listview_1,0,NotNeeded()+ " has been killed at "+ FormatDate("%hh:%ii:%ss  %dd.%mm.%yy",  Date()))
            EndIf

;Max. - following 2 lines commented
;             SetFileAttributes_(@Fullname$,#FILE_ATTRIBUTE_NORMAL );set attribute to normal
;             Result=DeleteFile(Fullname$)
            If Result
             AddGadgetItem(#Listview_1,0,Fullname$ +" has been killed from disk")
            EndIf
           EndIf
          Wend 

        EndIf 
      Next 
      
    EndIf 
    CloseLibrary(0) 
  EndIf 
      
EndProcedure 

Result = AssignDebugPrivilege()
Open_Window_0()
GetNotNeeded()

Repeat
  Event = WindowEvent()
  t=GetTickCount_()
  Time=Val(GetGadgetText(#String_0))
  If t>(t0+time)
   If GetGadgetState(#Checkbox_0)=1
    DoProcessListNt()
   EndIf
   t0=t
  Else
   Delay(1)
  EndIf
Until Event = #PB_EventCloseWindow
End

;Max. - PSKILL.exe should not be needed anymore
;L1:
;IncludeBinary "PSKill.exe"
;L2:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Sorry Rings,
I must be idiot or something: How to kill a process using your tip?
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Max.²
Enthusiast
Enthusiast
Posts: 175
Joined: Wed Jul 28, 2004 8:38 am

Post by Max.² »

Psychophanta wrote:Sorry Rings,
I must be idiot or something: How to kill a process using your tip?
While not Rings, I hope I can answer your question.

All you need is a textfile notneeded.ini in the app's directory, containing the process names of unwanted stuff (virus, trojan horse, worm, real player :wink:)

The file in Rings' archive looks like this:
---snip
winservicess.ex
winservicess.exe
Test.exe
---snip

For the tests with the above's code I used some others
---snip
qttask.exe
services.exe
winlogon.exe
---snip

Note that the latter two are system services, you cannot end usually. I used them to verify if the AssignDebugPrivilege procedure really gives me access to these processes.

End them at your own risk!

[/i]
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Thanks, but in the box: "processes that have been killed" appears nothing.
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Max.²
Enthusiast
Enthusiast
Posts: 175
Joined: Wed Jul 28, 2004 8:38 am

Post by Max.² »

Psychophanta wrote:Thanks, but in the box: "processes that have been killed" appears nothing.
Did you try to run a program that you previously entered into the notneeded.ini?

What OS are you using?

Is this a problem with my version or with Rings' original or both?
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Max.² wrote: Did you try to run a program that you previously entered into the notneeded.ini?
AHA! I see.
That program should be more careful, for example ask before to shoot :!: :evil:
Max.² wrote:What OS are you using?
XP Pro
Max.² wrote:Is this a problem with my version or with Rings' original or both?
I don't know.
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Max.²
Enthusiast
Enthusiast
Posts: 175
Joined: Wed Jul 28, 2004 8:38 am

Post by Max.² »

[quote="Psychophanta"][/quote]

Lol, use it, don't use it, read the thread to get infos about it or not, whatever. As long as you can't even describe with which version what problem occurs or not, there is no help for you. :roll: /eot
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

I'm sometimes lazy to read :oops:
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: permanent process remover (NT,W2k,XP)

Post by PB »

@Rings: Thanks for your code, but I have a problem here with a part of it:

Code: Select all

CallFunctionFast(GetModuleBaseNameFull,hProcess, BaseModule, @FullName$, Len(FullName$))
On my PC, where I do have admin rights, the above doesn't always give a
full pathname for a given PID. For example, here is what is returned when
I use it in a loop of all running processes:

Code: Select all

; Process,PID,FullPathToProcess
csrss.exe,740,
svchost.exe,1004,C:\WINDOWS\system32\svchost.exe
svchost.exe,1052,
svchost.exe,1092,C:\WINDOWS\System32\svchost.exe
svchost.exe,1196,
svchost.exe,1224,
svchost.exe,1312,C:\WINDOWS\System32\svchost.exe
svchost.exe,1832,C:\WINDOWS\System32\svchost.exe
Sometimes I get the full path returned, but other times, not. Svchost.exe
is located in the System32 folder, so shouldn't the above CallFunctionFast
get it each time for every svchost.exe process? It seems to only get a few.
And why not for csrss.exe? As a clue, I know it's this line causing the failure:

Code: Select all

hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ, 0, PID)
It's returning 0 for hProcess (but only sometimes) and I don't know why.

(PS. While we're here, is there a way to get the RAM usage of a process?).
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Post Reply