All currently running processes are implicitly white-listed on first run, and by default only user mode applications will be managed, set sysModeToo := True to manage all processes.
Anytime a new (unknown) process is launched process is suspended & user's prompted to:
- Whitelist, where application will always be allowed to run unimpeded (default selection)
Terminate, need i say more...
Blacklist, where application will never be allowed to run, being terminated if detected
...&...
'A', to allow for current session,such that if script is restarted, application needs to be allowed again
>The First Letter of MsgBox buttons 'W', 'T', 'B' can be used for a quick reply to prompt.
The prompt can additionally either 'Timeout' or 'Loose Focus', both of which will terminate waiting process.
Ctrl+Ins Provides Folder,then File Selection to allow you to WHITELIST/BLACKLIST contents of a folder,such as to whitelist your entire steam library or blacklist that folder that contains your malware 'samples'.
By default it can react to a new process with in no less than 75ms of execution, modify SetTimer, OnNewProc, 75 accordingly if you're on a particularly low end system & it's using up over 1% of CPU while monitoring.
EDIT: Added Path Whitelisting(MANUAL-InScript) as i don't recommend it otherwise, and Did a Bunch Of Optimizations.
Code: Select all
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
#SingleInstance, Force
ListLines, Off
SetBatchLines, -1
Process, Priority,, High
whiteListedPaths := "C:\Program Files|C:\Program Files (x86)|A:\" ;any process in these paths will be automatically whitelisted. '|' delimited.
trayNotification := true
debug := False ;turn on to test with no files written, Whitelists & Blacklists in memory.
sysModeToo := False ;will also perform whitelisting on system processes,like windows services, by default it's userMode processes only that are managed.
If !debug{
IfNotExist, %A_ScriptName%.WHITELIST.log ;initialise with every active process in white list on first run
for i, v in WTSEnumerateProcessesEx(){
whiteList .= "," v.ProcessName
FileAppend, %whiteList%, %A_ScriptName%.WHITELIST.log
}
FileRead, whiteList, %A_ScriptName%.WHITELIST.log
FileRead, blackList, %A_ScriptName%.BLACKLIST.log
}Else{
for i, v in WTSEnumerateProcessesEx() ;whitelist every active process...
whiteList .= "," v.ProcessName
;Init base list with all currently active processes
List := ""
for i, v in WTSEnumerateProcessesEx()
List .= v.ProcessName "|" v.ProcessID "|" v.SessionID "`n"
}
SetTimer, OnNewProc, 75
Return
OnNewProc(){
Static
processCount := EnumProcesses(pidlist)
If (processCount != lastCount) || ListGetDifference(pidlist, lastPidlist, diff, "|") || diff{
Gosub Monitor
lastCount := processCount, lastPidlist := pidlist
}
}
Monitor:
for i, v in WTSEnumerateProcessesEx(){
thisProcess := v.ProcessName "|" v.ProcessID "|" v.SessionID "`n", thisPID := v.ProcessID, thisName := v.ProcessName
If InStr(Allow4Now, v.ProcessName) && !InStr(blackList, v.ProcessName) ;whitelist exemption for process...
Continue
If (v.SessionID = 1) || sysModeToo{ ;if user mode application only - by default
If (InStr(whiteList, v.ProcessName) AND !InStr(blackList, v.ProcessName) AND !InStr(List, thisProcess)){ ;if white listed process allow this session
List .= thisProcess
}Else If InStr(blackList, v.ProcessName){
If trayNotification
TrayTip, ProcessWhiteList, % "Terminating: `n" v.ProcessName
Process, Close, % v.ProcessID
}Else If !InStr(List,thisProcess) && !IsInWhitelistedPath(){
vEx := ProcessCommandLineByPID(v.ProcessID)
,thisCommandLine := vEx.CommandLine
,thisExecutablePath := vEx.ExecutablePath
If !debug
ProcSus(v.ProcessID)
;Get Process Attributes
thisAttrib := ""
,Props := ["Path","Copyright","File description","File version","Language","Product name","Product version","Company", "System.OriginalFileName"]
For k,v in Filexpro( thisExecutablePath ? thisExecutablePath : GetModuleFileNameEx(thisPID), "Program", Props* )
thisAttrib .= v "`n`n"
SoundBeep, ,50
Gui +OwnDialogs
SetTimer, OnWinChangeMsgBoxOff, 100 ;if Notification Msgbox doesn't have focus,new process that triggered alert will be terminated.
If trayNotification
TrayTip, ProcessWhiteList, Press 'A' to Allow For Current Session Only!
OnMessage(0x44, "OnMsgBox")
MsgBox 0x40033, New Process Warning Alert!, Process Is In Suspension Awaiting Approval to Run? `n`n %thisProcess% `n %thisExecutablePath% `n`n-------------------------`n`n %thisAttrib% `n`n-------------------------`n Press 'A' to Allow For Current Session Only!, 10
OnMessage(0x44, "")
IfMsgBox Yes, { ;whitelist
If InStr(Allow4Now, thisName){ ;Allow4Now Override
ProcRes(thisPiD)
Continue
}
List .= thisProcess
whiteList .= "," thisName
If trayNotification
TrayTip, ProcessWhiteList, % "White Listed: `n" thisName
If !debug{
ProcRes(thisPiD)
FileDelete, %A_ScriptName%.WHITELIST.log
FileAppend, %whiteList%, %A_ScriptName%.WHITELIST.log
}
} Else IfMsgBox No, { ;terminate
If InStr(Allow4Now, thisName){ ;Allow4Now Override
ProcRes(thisPiD)
Continue
}
If trayNotification
TrayTip, ProcessWhiteList, % "Terminating: `n" thisName
FormatTime, DATE, R
If !debug
FileAppend, % DATE " [TERMINATED] " thisName " <> " thisCommandLine "`n`n", %A_ScriptName%.TERMINATED.log
Process, Close, % thisPiD
Sleep 250 ;to give process enough time to gracefully exit
Process, Exist, % thisPiD
If ErrorLevel
RunWait % comspec " /c taskkill /f /t /pid " thisPiD,, Hide
} Else IfMsgBox Cancel, { ;blackList
If InStr(Allow4Now, thisName){ ;Allow4Now Override
ProcRes(thisPiD)
Continue
}
Process, Close, % thisPiD
blackList .= "," thisName
If trayNotification
TrayTip, ProcessBlackList, % "Black Listed & Terminating: `n" thisName
If !debug{
FileDelete, %A_ScriptName%.BLACKLIST.log
FileAppend, %blackList%, %A_ScriptName%.BLACKLIST.log
}
} Else IfMsgBox Timeout , { ;terminate
If trayNotification
TrayTip, ProcessWhiteList, % "Terminating: `n" thisName
FormatTime, DATE, R
If !debug
FileAppend, % DATE " [TimeOut-Terminated] " thisName " <> " thisCommandLine "`n`n", %A_ScriptName%.TERMINATED.log
Process, Close, % thisPID
Sleep 250 ;to give process enough time to gracefully exit
Process, Exist, % thisPiD
If ErrorLevel
RunWait % comspec " /c taskkill /f /t /pid " thisPID,, Hide
}
}
}
}
Return
IsInWhitelistedPath(){ ;returns true & whitelists process so as not to evaluate the same process more than once...
Global
Local thisPath
thisPath := ProcessCommandLineByPID(v.ProcessID).ExecutablePath
,thisPath := thisPath ? thisPath : GetModuleFileNameEx(v.ProcessID) ;failsafe incase null is returned...
Loop, Parse, whiteListedPaths, |
If InStr(thisPath, A_LoopField){
; FileAppend, % "," v.ProcessName, %A_ScriptName%.WHITELIST.log
; FileRead, whiteList, %A_ScriptName%.WHITELIST.log
Allow4Now .= "," thisName
If trayNotification
TrayTip, ProcessWhiteList, % "White Listed: `n" thisPath
Return true
}
}
#IfWinActive New Process Warning Alert!
a::
If trayNotification
TrayTip, ProcessWhiteList, % "Process Whitelisted For Current Session Only: `n" thisName
Allow4Now .= "," thisName
WinKill, New Process Warning Alert!
Return
#IfWinActive
^Ins:: ;to add executables from directories in bulk from trusted locations such as to whitelist all executables in your entire steam directory.
FileSelectFolder, selFolder,,, Select Folder Wherein,`nAll Contained Executables Will Be Whitelisted!
IfEqual, selFolder,, MsgBox, 0x40010, %A_ScriptName%, No Folder Selected`, Aborting`, TryAgain!
IfEqual, selFolder,, Return
Loop, %selFolder%\*.exe,,1
exeList .= !Instr(exeList, A_LoopFileName) ? "," A_LoopFileName : ""
FileSelectFile, selFile, s, %A_ScriptDir%\%A_ScriptName%.WHITELIST.log, Select File To Append Exe List Into`, i.e WHITELIST/BLACKLIST file, *.log
IfEqual, selFile,, MsgBox, 0x40010, %A_ScriptName%, No File Selected`, Aborting`, TryAgain!
IfEqual, selFile,, Return
FileAppend, % exeList, % selFile
Reload
Return
OnWinChangeMsgBoxOff(){
IfWinNotActive, New Process Warning Alert!
IfWinNotActive, ahk_class #32770 ahk_exe AutoHotkey.exe
ControlClick, Button2, ahk_class #32770 ahk_exe AutoHotkey.exe ;No/Terminate
}
OnMsgBox() {
DetectHiddenWindows, On
Process, Exist
If (WinExist("ahk_class #32770 ahk_pid " . ErrorLevel)) {
ControlSetText Button1, &WhiteList
ControlSetText Button2, &Terminate
ControlSetText Button3, &BlackList
}
}
ProcSus(PID_or_Name)
{
If InStr(PID_or_Name, ".") {
Process, Exist, %PID_or_Name%
PID_or_Name := ErrorLevel
}
If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name))
Return -1
DllCall("ntdll.dll\NtSuspendProcess", "Int", h), DllCall("CloseHandle", "Int", h)
}
ProcRes(PID_or_Name)
{
If InStr(PID_or_Name, ".") {
Process, Exist, %PID_or_Name%
PID_or_Name := ErrorLevel
}
If !(h := DllCall("OpenProcess", "uInt", 0x1F0FFF, "Int", 0, "Int", PID_or_Name))
Return -1
DllCall("ntdll.dll\NtResumeProcess", "Int", h), DllCall("CloseHandle", "Int", h)
}
WTSEnumerateProcessesEx()
{
static hWTSAPI := DllCall("LoadLibrary", "str", "wtsapi32.dll", "ptr")
if !(DllCall("wtsapi32\WTSEnumerateProcessesEx", "ptr", 0, "uint*", 0, "uint", -2, "ptr*", buf, "uint*", TTL))
throw Exception("WTSEnumerateProcessesEx failed", -1)
addr := buf, WTS_PROCESS_INFO := []
loop % TTL
{
WTS_PROCESS_INFO[A_Index, "SessionID"] := NumGet(addr+0, "uint")
WTS_PROCESS_INFO[A_Index, "ProcessID"] := NumGet(addr+4, "uint")
WTS_PROCESS_INFO[A_Index, "ProcessName"] := StrGet(NumGet(addr+8, "ptr"))
WTS_PROCESS_INFO[A_Index, "UserSID"] := NumGet(addr+8+A_PtrSize, "ptr")
addr += 8 + (A_PtrSize * 2)
}
if !(DllCall("wtsapi32\WTSFreeMemoryEx", "int", 0, "ptr", buf, "uint", TTL))
throw Exception("WTSFreeMemoryEx failed", -1)
return WTS_PROCESS_INFO
}
ProcessCommandLineByPID(PID){
for process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where ProcessId=" . PID)
Return {Name:process.Name, CommandLine:process.CommandLine, ExecutablePath:process.ExecutablePath, SessionID:process.SessionId,ParentProcessId:process.ParentProcessId}
}
GetModuleFileNameEx( p_pid ) ; by shimanov - www.autohotkey.com/forum/viewtopic.php?t=9000
{
h_process := DllCall( "OpenProcess", "uint", 0x10|0x400, "int", false, "uint", p_pid )
if ( ErrorLevel or h_process = 0 )
return
name_size := 255
,VarSetCapacity( name, name_size )
,result := DllCall( "psapi.dll\GetModuleFileNameExW", "uint", h_process, "uint", 0, "str", name, "uint", name_size )
,DllCall( "CloseHandle", h_process )
Return name
}
EnumProcesses(byref Var) { ;SKAN
IfEqual, A_OSType, WIN32_WINDOWS, Return 0
List_Sz := VarSetCapacity(Pid_List, 4000)
Res := DllCall("psapi.dll\EnumProcesses", UInt,&Pid_List
, Int,List_Sz, "UInt *",PID_List_Actual)
IfLessOrEqual,Res,0, Return, Res
_a := &PID_List
Var :=
Loop, % (PID_List_Actual//4) {
Var := Var "|" (*(_a)+(*(_a+1)<<8)+(*(_a+2)<<16)+(*(_a+3)<<24))
_a += 4
}
StringTrimLeft, Var, Var, 1
Return, (PID_List_Actual//4)
}
;evaluates the number of occurrences in one but not the other to get difference instead of checking using InStr().
ListGetDifference(ByRef a,ByRef b,ByRef diff,delim:="`n"){ ;returns difference between lists using same delims as original lists
diff := ""
Loop, parse, a, %delim%
diff .= ( StringCharCount(a,A_LoopField) <> StringCharCount(b,A_LoopField) AND !InStr(diff, A_LoopField) ? A_LoopField . delim : "" )
Loop, parse, b, %delim%
diff .= ( StringCharCount(a,A_LoopField) <> StringCharCount(b,A_LoopField) AND !InStr(diff, A_LoopField) ? A_LoopField . delim : "" )
}
;Returns the number of ooccurrences of a character in a string
StringCharCount(string, char){
StringReplace, string, string, %char%, %char%, UseErrorLevel
Return ErrorLevel
}
Filexpro( sFile := "", Kind := "", P* ) { ; v.90 By SKAN on D1CC @ goo.gl/jyXFo9
Local
Static xDetails
If ( sFile = "" )
{ ; Deinit static variable
xDetails := ""
Return
}
fex := {}, _FileExt := ""
Loop, Files, % RTrim(sfile,"\*/."), DF
{
If not FileExist( sFile:=A_LoopFileLongPath )
{
Return
}
SplitPath, sFile, _FileExt, _Dir, _Ext, _File, _Drv
If ( p[p.length()] = "xInfo" ) ; Last parameter is xInfo
{
p.Pop() ; Delete parameter
fex.SetCapacity(11) ; Make room for Extra info
fex["_Attrib"] := A_LoopFileAttrib
fex["_Dir"] := _Dir
fex["_Drv"] := _Drv
fex["_Ext"] := _Ext
fex["_File"] := _File
fex["_File.Ext"] := _FileExt
fex["_FilePath"] := sFile
fex["_FileSize"] := A_LoopFileSize
fex["_FileTimeA"] := A_LoopFileTimeAccessed
fex["_FileTimeC"] := A_LoopFileTimeCreated
fex["_FileTimeM"] := A_LoopFileTimeModified
}
Break
}
If Not ( _FileExt ) ; Filepath not resolved
{
Return
}
objShl := ComObjCreate("Shell.Application")
objDir := objShl.NameSpace(_Dir)
objItm := objDir.ParseName(_FileExt)
If ( VarSetCapacity(xDetails) = 0 ) ; Init static variable
{
i:=-1, xDetails:={}, xDetails.SetCapacity(309)
While ( i++ < 309 )
{
xDetails[ objDir.GetDetailsOf(0,i) ] := i
}
xDetails.Delete("")
}
If ( Kind and Kind <> objDir.GetDetailsOf(objItm,11) ) ; File isn't desired kind
{
Return
}
i:=0, nParams:=p.Count(), fex.SetCapacity(nParams + 11)
While ( i++ < nParams )
{
Prop := p[i]
If ( (Dot:=InStr(Prop,".")) and (Prop:=(Dot=1 ? "System":"") . Prop) )
{
fex[Prop] := objItm.ExtendedProperty(Prop)
Continue
}
If ( PropNum := xDetails[Prop] ) > -1
{
fex[Prop] := ObjDir.GetDetailsOf(objItm,PropNum)
Continue
}
}
fex.SetCapacity(-1)
Return fex
} ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -