masvil

Persistent script, you can't stop it

10 posts in this topic

#1 ·  Posted (edited)

WHAT
This script restarts an executable (the AutoIT script itself called "cantstopme.exe", in this case) if any attempt of closure is done.

WHY
If you want to preserve critical admin task from potential stop attempts.

HOW
Pure AutoIT method. No batch file(s) are created. It clones itself and creates a self-protecting triangle in this way:
- protector1.exe takes care of cantstopme.exe and protector2.exe
- protector2.exe takes care of protector1.exe

Its goal is to be unstoppable because thanks to auto-restart tecnique no process-trees exist, so conventional process managers can't kill. Furthermore there are no apparent relationships between involved processes. Executables cannot run more than once, so everything stay stable. CPU effort is very low. You can show an administrator alert message, same like I did in the script.

INSTRUCTIONS
You can change $Protector1Dir, $Protector1Name, $Protector2Dir, $Protector2Name as you want.
You can replace the example loop code in "Your script here" section.
Compile and run it.
The only way to stop persistent generated 3 processes will be pressing CTRL+ALT+E or restarting your PC. If latter then you should manually delete Protectors to clean.

SORRY
Because almost no comments in the code. Anyway it's short and simple, and I'm here to explain if needed.

SO
Please test, comment, rate, enhance.
Try to kill it! Do you think it is really bullet-proof?
I hope someone can create an UDF (I'm not enough skilled to do it).

If you like the topic there is one related by @guinness.

#NoTrayIcon

If @Compiled = 0 Then
    MsgBox(1, '"You cant stop it" AutoIT script by MasviL', "You should run it compiled!")
    Exit
EndIf

Local $Protector1Dir = @AppDataDir & "\protector1 dir"
Local $Protector1Name = "protector1.exe"

Local $Protector2Dir = @AppDataDir & "\protector2 dir"
Local $Protector2Name = "protector2.exe"

Persistent()

; ===============================================
; Your script here
While 1
    Sleep(1000)
WEnd
; ===============================================


Func Persistent()
    If @ScriptDir <> $Protector1Dir And @ScriptDir <> $Protector2Dir Then

        If $CmdLine[0] = 0 Then
            Local $aArray = ProcessList(@ScriptName)
            For $i = 1 To $aArray[0][0]
                If $aArray[$i][1] = @AutoItPID Then ContinueLoop
                $Path = _ProcessGetLocation($aArray[$i][1])
                If StringInStr($Path, @ScriptDir) Then
                    Exit
                EndIf
            Next

            FileCopy(@ScriptFullPath, $Protector1Dir & "\" & $Protector1Name, 9)
            Run($Protector1Dir & "\" & $Protector1Name & ' "' & @ScriptDir & '" ' & @ScriptName & " restart", $Protector1Dir)

        EndIf

        If $CmdLine[0] = 1 Then
            Run(@ScriptFullPath & " 1 2", @ScriptDir)
            Exit
        EndIf

        HotKeySet("^!e", "CloseAll")

        If FileExists(@ScriptDir & "\stop") Then FileDelete(@ScriptDir & "\stop") ; maybe useless

        MsgBox(0, '"You cant stop it" AutoIT script by MasviL', 'The only way to stop this script process "' & @ScriptName & '" will be pressing CTRL+ALT+E or restarting your PC.')

    EndIf

    If @ScriptDir = $Protector1Dir Then
        OnAutoItExitRegister("Terminate") ; Maybe useless

        If $CmdLine[0] = 0 Then Exit

        If $CmdLine[0] > 1 Then
            $ExeDir = $CmdLine[1]
            $ExeName = $CmdLine[2]
        EndIf

        If $CmdLine[0] = 3 Then
            Run(@ScriptFullPath & ' "' & $ExeDir & '" ' & $ExeName, @ScriptDir)
            Exit
        EndIf

        While 1
            Sleep(500)
            If FileExists($ExeDir & "\stop") Then Exit
            WinKill("AutoIt Error") ; just in case

            $ExeRunning = 0
            Local $aArray = ProcessList($ExeName)
            For $i = 1 To $aArray[0][0]
                $Path = _ProcessGetLocation($aArray[$i][1])
                If StringInStr($Path, $ExeDir) Then
                    $ExeRunning = 1
                EndIf
            Next
            If $ExeRunning = 0 Then
                FileCopy(@ScriptFullPath, $ExeDir & "\" & $ExeName, 9)
                Run($ExeDir & "\" & $ExeName & " restart", @ScriptDir)
            EndIf

            $Protector2Running = 0
            Local $aArray = ProcessList($Protector2Name)
            For $i = 1 To $aArray[0][0]
                $Path = _ProcessGetLocation($aArray[$i][1])
                If StringInStr($Path, $Protector2Dir) Then
                    $Protector2Running = 1
                EndIf
            Next
            If $Protector2Running = 0 Then
                FileCopy(@ScriptFullPath, $Protector2Dir & "\" & $Protector2Name, 9)
                Run($Protector2Dir & "\" & $Protector2Name & ' "' & $ExeDir & '" ' & $ExeName & " restart", @ScriptDir)
            EndIf

        WEnd
    EndIf

    If @ScriptDir = $Protector2Dir Then
        OnAutoItExitRegister("Terminate") ; Maybe useless

        If $CmdLine[0] = 0 Then Exit

        If $CmdLine[0] > 1 Then
            $ExeDir = $CmdLine[1]
            $ExeName = $CmdLine[2]
        EndIf

        If $CmdLine[0] = 3 Then
            Run(@ScriptFullPath & ' "' & $ExeDir & '" ' & $ExeName, @ScriptDir)
            Exit
        EndIf

        While 1
            Sleep(500)
            If FileExists($ExeDir & "\stop") Then Exit
            WinKill("AutoIt Error") ; just in case

            $Protector1Running = 0
            Local $aArray = ProcessList($Protector1Name)
            For $i = 1 To $aArray[0][0]
                $Path = _ProcessGetLocation($aArray[$i][1])
                If StringInStr($Path, $Protector1Dir) Then
                    $Protector1Running = 1
                EndIf
            Next
            If $Protector1Running = 0 Then
                FileCopy(@ScriptFullPath, $Protector1Dir & "\" & $Protector1Name, 9)
                Run($Protector1Dir & "\" & $Protector1Name & ' "' & $ExeDir & '" ' & $ExeName & " restart", @ScriptDir)
            EndIf

        WEnd

    EndIf
EndFunc   ;==>Persistent

Func Terminate()
    Exit
EndFunc   ;==>Terminate

Func CloseAll()
    $Stop = FileOpen(@ScriptDir & "\stop", 1)
    FileClose($Stop)

    Local $aArray = ProcessList($Protector1Name)
    For $i = 1 To $aArray[0][0]
        $Path = _ProcessGetLocation($aArray[$i][1])
        If StringInStr($Path, $Protector1Dir) Then
            ProcessWaitClose($aArray[$i][1])
        EndIf
    Next

    Local $aArray = ProcessList($Protector2Name)
    For $i = 1 To $aArray[0][0]
        $Path = _ProcessGetLocation($aArray[$i][1])
        If StringInStr($Path, $Protector2Dir) Then
            ProcessWaitClose($aArray[$i][1])
        EndIf
    Next

    FileDelete(@ScriptDir & "\stop")
    DirRemove($Protector1Dir, 1)
    DirRemove($Protector2Dir, 1)
    MsgBox(262144, '"You cant stop it" AutoIT script by MasviL', 'Done! You got rid of it.')
    Exit
EndFunc   ;==>CloseAll

Func _ProcessGetLocation($iPID)
    Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', BitOR(0x0400, 0x0010), 'int', 0, 'int', $iPID)
    If $aProc[0] = 0 Then Return SetError(1, 0, '')
    Local $vStruct = DllStructCreate('int[1024]')
    DllCall('psapi.dll', 'int', 'EnumProcessModules', 'hwnd', $aProc[0], 'ptr', DllStructGetPtr($vStruct), 'int', DllStructGetSize($vStruct), 'int_ptr', 0)
    Local $aReturn = DllCall('psapi.dll', 'int', 'GetModuleFileNameEx', 'hwnd', $aProc[0], 'int', DllStructGetData($vStruct, 1), 'str', '', 'int', 2048)
    If StringLen($aReturn[3]) = 0 Then Return SetError(2, 0, '')
    Return $aReturn[3]
EndFunc   ;==>_ProcessGetLocation

 

 

cantstopme.au3

Edited by masvil
Improvement
1 person likes this

Share this post


Link to post
Share on other sites



nice, but you could just suspend protect1 and protect2 and then close the real script, and afterwards protect1 and protect2 :P but what is the purpose of a persistence process?

1 person likes this

Share this post


Link to post
Share on other sites
11 hours ago, legend said:

nice, but you could just suspend protect1 and protect2 and then close the real script, and afterwards protect1 and protect2 :P but what is the purpose of a persistence process?

I agree with legend.  If this script is meant to be used in a live environment where end users are going to potentially try to stop the execution of the script, then you might want to include "Opt("TrayAutoPause", 0)" at the beginning so that clicking the toolbar icon does not pause the execution of the scripts, so that the vulnerability described by legend cannot take place

1 person likes this

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

You're right, script updated.

I added "#NoTrayIcon" instead of " Opt("TrayAutoPause", 0)", so the trick stay more hidden.

Edited by masvil

Share this post


Link to post
Share on other sites

took me less than 5 seconds to close it :) you can't really prevent me from suspending the process.

and even if you did I could remove the permissions of the running procceses, or i could use the SYSTEM account to close it.

If your serious about preventing the user from from closing the process you run the script as the SYSTEM account, and then you set the process to be critical,

but then again, it would begin to look suspicious, and i wouldn't see the purpose in doing that.

 

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

7 minutes ago, legend said:

took me less than 5 seconds to close it :) you can't really prevent me from suspending the process.

If you don't know how the script works (let's pretend it) how can you know which process(es) to suspend? There is no process-tree.

Edited by masvil

Share this post


Link to post
Share on other sites

yes, but i'm not gonna do that, since it can be used for bad minds.

if you want to hide the tray icon, use #notrayicon in top of your script

Share this post


Link to post
Share on other sites
3 minutes ago, legend said:

yes, but i'm not gonna do that, since it can be used for bad minds.

Do you think I should delete the post?

Quote

if you want to hide the tray icon, use #notrayicon in top of your script

Done.

Share this post


Link to post
Share on other sites

No I think it's ok, but that's not up to me to decide.

1 person likes this

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

What I would do is, instead of having other processes keep the main process open, maybe you should just make a single service that does this.  There are quite a few udfs available to create services with autoit.  This way, the user needs to have admin rights in order to even access the service snap-in console, and wouldn't have permissions to change its state.  Plus, the cool thing about services is that you can customize their permissions, and make it so that nobody has rights to change it.

 

Edited by MattHiggs
1 person likes this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now