Gorstaks Antivirus

 avatar
unknown
powershell
3 months ago
54 kB
10
No Index
# Antivirus.ps1 - Enhanced Complete Edition
# Author: Gorstak
# Enhanced with advanced malware detection capabilities

#Requires -RunAsAdministrator

# Define paths and parameters
$taskName = "Antivirus"
$taskDescription = "Runs the Simple Antivirus script at user logon with admin privileges."
$scriptDir = "C:\Windows\Setup\Scripts\Bin"
$scriptPath = "$scriptDir\Antivirus.ps1"
$quarantineFolder = "C:\Quarantine"
$logFile = "$quarantineFolder\antivirus_log.txt"
$localDatabase = "$quarantineFolder\scanned_files.txt"
$scannedFiles = @{} # Initialize empty hash table

$Base = $quarantineFolder
$QuarantineDir = $quarantineFolder

# Check admin privileges
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
Write-Host "Running as admin: $isAdmin"

$Script:SelfProcessName = $PID
$Script:SelfPath = $PSCommandPath

$Script:ProtectedProcessNames = @(
    "system", "csrss", "wininit", "services", "lsass", "svchost",
    "smss", "winlogon", "explorer", "dwm", "taskmgr", "spoolsv",
    "conhost", "fontdrvhost", "dllhost", "runtimebroker", "sihost",
    "taskhostw", "searchindexer", "searchprotocolhost", "searchfilterhost",
    "registry", "memory compression", "idle"
)

$Script:CriticalSystemProcesses = @(
    "registry", "csrss", "smss", "services", "lsass", "wininit", "winlogon"
)

$Script:EvilStrings = @(
    "mimikatz", "sekurlsa::", "kerberos::", "lsadump::", "wdigest", "tspkg",
    "http-beacon", "https-beacon", "cobaltstrike", "sleepmask", "reflective",
    "amsi.dll", "AmsiScanBuffer", "EtwEventWrite", "MiniDumpWriteDump",
    "VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread",
    "ReflectiveLoader", "sharpchrome", "rubeus", "safetykatz", "sharphound"
)

# Logging Function with Rotation
function Write-Log {
    param ([string]$message)
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] $message"
    Write-Host "Logging: $logEntry"
    if (-not (Test-Path $quarantineFolder)) {
        New-Item -Path $quarantineFolder -ItemType Directory -Force -ErrorAction Stop | Out-Null
        Write-Host "Created folder: $quarantineFolder"
    }
    if ((Test-Path $logFile) -and ((Get-Item $logFile -ErrorAction SilentlyContinue).Length -ge 10MB)) {
        $archiveName = "$quarantineFolder\antivirus_log_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
        Rename-Item -Path $logFile -NewName $archiveName -ErrorAction Stop
        Write-Host "Rotated log to: $archiveName"
    }
    $logEntry | Out-File -FilePath $logFile -Append -Encoding UTF8 -ErrorAction Stop
}

# Initial log with diagnostics
Write-Log "Script initialized. Admin: $isAdmin, User: $env:USERNAME, SID: $([Security.Principal.WindowsIdentity]::GetCurrent().User.Value)"

# Ensure execution policy allows script
if ((Get-ExecutionPolicy) -eq "Restricted") {
    Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force -ErrorAction SilentlyContinue
    Write-Log "Set execution policy to Bypass for current user."
}

function Add-ToStartup {
    try {
        $exePath = $PSCommandPath
        $appName = "MalwareDetector"
        
        $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
        $existing = Get-ItemProperty -Path $regPath -Name $appName -ErrorAction SilentlyContinue
        
        if (!$existing -or $existing.$appName -ne $exePath) {
            Set-ItemProperty -Path $regPath -Name $appName -Value $exePath -Force
            Write-Log "[STARTUP] Added to startup: $exePath"
        } else {
            Write-Log "[STARTUP] Already in startup registry"
        }
    } catch {
        Write-Log "[STARTUP] Failed to add to startup: $($_.Exception.Message)"
    }
}

function Test-CriticalSystemProcess {
    param($Process)
    
    try {
        $procName = $Process.ProcessName.ToLower()
        
        if ($Script:ProtectedProcessNames -contains $procName) {
            return $true
        }
        
        $path = $Process.Path
        if ($path -match "\\windows\\system32\\" -or $path -match "\\windows\\syswow64\\") {
            $signature = Get-AuthenticodeSignature -FilePath $path -ErrorAction SilentlyContinue
            if ($signature -and $signature.SignerCertificate.Subject -match "Microsoft") {
                return $true
            } else {
                Write-Log "[SUSPICIOUS] Unsigned or non-Microsoft binary in System32: $path"
                return $false
            }
        }
        
        return $false
    } catch {
        return $true
    }
}

function Test-ProtectedOrSelf {
    param($Process)
    
    try {
        $procName = $Process.ProcessName.ToLower()
        $procId = $Process.Id
        
        if ($procId -eq $Script:SelfProcessName) {
            return $true
        }
        
        foreach ($protected in $Script:ProtectedProcessNames) {
            if ($procName -eq $protected -or $procName -like "$protected*") {
                return $true
            }
        }
        
        if ($Process.Path -eq $Script:SelfPath) {
            return $true
        }
        
        return $false
    } catch {
        return $false
    }
}

# Load or Reset Scanned Files Database
if (Test-Path $localDatabase) {
    try {
        $scannedFiles.Clear() # Reset hash table before loading
        $lines = Get-Content $localDatabase -ErrorAction Stop
        foreach ($line in $lines) {
            if ($line -match "^([0-9a-f]{64}),(true|false)$") {
                $scannedFiles[$matches[1]] = [bool]$matches[2]
            }
        }
        Write-Log "Loaded $($scannedFiles.Count) scanned file entries from database."
    } catch {
        Write-Log "Failed to load database: $($_.Exception.Message)"
        $scannedFiles.Clear() # Reset on failure
    }
} else {
    $scannedFiles.Clear() # Ensure reset if no database
    New-Item -Path $localDatabase -ItemType File -Force -ErrorAction Stop | Out-Null
    Write-Log "Created new database: $localDatabase"
}

# Take Ownership and Modify Permissions (Aggressive)
function Set-FileOwnershipAndPermissions {
    param ([string]$filePath)
    try {
        takeown /F $filePath /A | Out-Null
        icacls $filePath /reset | Out-Null
        icacls $filePath /grant "Administrators:F" /inheritance:d | Out-Null
        Write-Log "Forcibly set ownership and permissions for $filePath"
        return $true
    } catch {
        Write-Log "Failed to set ownership/permissions for ${filePath}: $($_.Exception.Message)"
        return $false
    }
}

# Calculate File Hash and Signature
function Calculate-FileHash {
    param ([string]$filePath)
    try {
        $signature = Get-AuthenticodeSignature -FilePath $filePath -ErrorAction Stop
        $hash = Get-FileHash -Path $filePath -Algorithm SHA256 -ErrorAction Stop
        Write-Log "Signature status for ${filePath}: $($signature.Status) - $($signature.StatusMessage)"
        return [PSCustomObject]@{
            Hash = $hash.Hash.ToLower()
            Status = $signature.Status
            StatusMessage = $signature.StatusMessage
        }
    } catch {
        Write-Log "Error processing ${filePath}: $($_.Exception.Message)"
        return $null
    }
}

function Get-SHA256Hash {
    param([string]$FilePath)
    
    try {
        $hash = Get-FileHash -Path $FilePath -Algorithm SHA256
        return $hash.Hash.ToLower()
    } catch {
        return $null
    }
}

# Quarantine File (Crash-Proof) - Original version
function Quarantine-File {
    param ([string]$filePath)
    try {
        $quarantinePath = Join-Path -Path $quarantineFolder -ChildPath (Split-Path $filePath -Leaf)
        Move-Item -Path $filePath -Destination $quarantinePath -Force -ErrorAction Stop
        Write-Log "Quarantined file: $filePath to $quarantinePath"
    } catch {
        Write-Log "Failed to quarantine ${filePath}: $($_.Exception.Message)"
    }
}

function Invoke-QuarantineFile {
    param(
        [string]$FilePath,
        [string]$ProcessName,
        [int]$ProcessId,
        [string]$Reason
    )
    
    try {
        if ($FilePath -eq $Script:SelfPath) {
            return $false
        }
        
        if (!(Test-Path $FilePath)) {
            Write-Log "[QUARANTINE] File not found: $FilePath"
            return $false
        }
        
        $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
        $fileName = Split-Path $FilePath -Leaf
        $quarantinePath = Join-Path $Script:QuarantineDir "${timestamp}_${ProcessName}_${ProcessId}_${fileName}"
        
        Copy-Item -Path $FilePath -Destination $quarantinePath -Force
        
        $quarantineInfo = @{
            Timestamp = $timestamp
            OriginalPath = $FilePath
            QuarantinePath = $quarantinePath
            ProcessName = $ProcessName
            ProcessId = $ProcessId
            DetectionReason = $Reason
        } | ConvertTo-Json -Compress
        
        Add-Content -Path (Join-Path $Script:QuarantineDir "quarantine.log") -Value $quarantineInfo -Encoding UTF8
        Write-Log "[QUARANTINE] File quarantined: $FilePath -> $quarantinePath"
        
        try {
            Remove-Item -Path $FilePath -Force -ErrorAction Stop
            Write-Log "[QUARANTINE] Original file deleted: $FilePath"
        } catch {
            Write-Log "[QUARANTINE] Could not delete original file (may be in use): $FilePath"
        }
        
        return $true
    } catch {
        Write-Log "[QUARANTINE] Failed to quarantine: $($_.Exception.Message)"
        return $false
    }
}

# Stop Processes Using DLL (Aggressive)
function Stop-ProcessUsingDLL {
    param ([string]$filePath)
    try {
        $processes = Get-Process | Where-Object { ($_.Modules | Where-Object { $_.FileName -eq $filePath }) }
        foreach ($process in $processes) {
            Stop-Process -Id $process.Id -Force -ErrorAction Stop
            Write-Log "Stopped process $($process.Name) (PID: $($process.Id)) using $filePath"
        }
    } catch {
        Write-Log "Error stopping processes for ${filePath}: $($_.Exception.Message)"
        try {
            $processes = Get-Process | Where-Object { ($_.Modules | Where-Object { $_.FileName -eq $filePath }) }
            foreach ($process in $processes) {
                taskkill /PID $process.Id /F | Out-Null
                Write-Log "Force-killed process $($process.Name) (PID: $($process.Id)) using taskkill"
            }
        } catch {
            Write-Log "Fallback process kill failed for ${filePath}: $($_.Exception.Message)"
        }
    }
}

function Stop-ProcessesUsingFile {
    param([string]$FilePath)
    
    try {
        if ($FilePath -eq $Script:SelfPath) {
            return
        }
        
        Get-Process | Where-Object {
            try {
                $_.Path -eq $FilePath -and !(Test-ProtectedOrSelf $_) -and !(Test-CriticalSystemProcess $_)
            } catch { $false }
        } | ForEach-Object {
            try {
                $_.Kill()
                Write-Log "[KILL] Terminated process using file: $($_.ProcessName) (PID: $($_.Id))"
                Start-Sleep -Milliseconds 100
            } catch {}
        }
    } catch {}
}

function Should-ExcludeFile {
    param ([string]$filePath)
    $lowerPath = $filePath.ToLower()
    
    # Exclude assembly folders
    if ($lowerPath -like "*\assembly\*") {
        Write-Log "Excluding assembly folder file: $filePath"
        return $true
    }
    
    # Exclude ctfmon-related files
    if ($lowerPath -like "*ctfmon*" -or $lowerPath -like "*msctf.dll" -or $lowerPath -like "*msutb.dll") {
        Write-Log "Excluding ctfmon-related file: $filePath"
        return $true
    }
    
    return $false
}

# Remove Unsigned DLLs (Exclude Problem Folders)
function Remove-UnsignedDLLs {
    Write-Log "Starting unsigned DLL/WINMD scan."
    $drives = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DriveType -in (2, 3, 4) }
    foreach ($drive in $drives) {
        $root = $drive.DeviceID + "\"
        Write-Log "Scanning drive: $root"
        try {
            $dllFiles = Get-ChildItem -Path $root -Include *.dll,*.winmd -Recurse -File -Exclude @($quarantineFolder, "C:\Windows\System32\config") -ErrorAction Stop
            foreach ($dll in $dllFiles) {
                try {
                    if (Should-ExcludeFile -filePath $dll.FullName) {
                        continue
                    }
                    
                    $fileHash = Calculate-FileHash -filePath $dll.FullName
                    if ($fileHash) {
                        if ($scannedFiles.ContainsKey($fileHash.Hash)) {
                            Write-Log "Skipping already scanned file: $($dll.FullName) (Hash: $($fileHash.Hash))"
                            if (-not $scannedFiles[$fileHash.Hash]) {
                                if (Set-FileOwnershipAndPermissions -filePath $dll.FullName) {
                                    Stop-ProcessUsingDLL -filePath $dll.FullName
                                    Quarantine-File -filePath $dll.FullName
                                }
                            }
                        } else {
                            $isValid = $fileHash.Status -eq "Valid" # Only "Valid" is safe
                            $scannedFiles[$fileHash.Hash] = $isValid
                            "$($fileHash.Hash),$isValid" | Out-File -FilePath $localDatabase -Append -Encoding UTF8 -ErrorAction Stop
                            Write-Log "Scanned new file: $($dll.FullName) (Valid: $isValid)"
                            if (-not $isValid) {
                                if (Set-FileOwnershipAndPermissions -filePath $dll.FullName) {
                                    Stop-ProcessUsingDLL -filePath $dll.FullName
                                    Quarantine-File -filePath $dll.FullName
                                }
                            }
                        }
                    }
                } catch {
                    Write-Log "Error processing file $($dll.FullName): $($_.Exception.Message)"
                }
            }
        } catch {
            Write-Log "Scan failed for drive ${root} $($_.Exception.Message)"
        }
    }
    # Explicit System32 Scan
    Write-Log "Starting explicit System32 scan."
    try {
        $system32Files = Get-ChildItem -Path "C:\Windows\System32" -Include *.dll,*.winmd -File -ErrorAction Stop
        foreach ($dll in $system32Files) {
            try {
                if (Should-ExcludeFile -filePath $dll.FullName) {
                    continue
                }
                
                $fileHash = Calculate-FileHash -filePath $dll.FullName
                if ($fileHash) {
                    if ($scannedFiles.ContainsKey($fileHash.Hash)) {
                        Write-Log "Skipping already scanned System32 file: $($dll.FullName) (Hash: $($fileHash.Hash))"
                        if (-not $scannedFiles[$fileHash.Hash]) {
                            if (Set-FileOwnershipAndPermissions -filePath $dll.FullName) {
                                Stop-ProcessUsingDLL -filePath $dll.FullName
                                Quarantine-File -filePath $dll.FullName
                            }
                        }
                    } else {
                        $isValid = $fileHash.Status -eq "Valid"
                        $scannedFiles[$fileHash.Hash] = $isValid
                        "$($fileHash.Hash),$isValid" | Out-File -FilePath $localDatabase -Append -Encoding UTF8 -ErrorAction Stop
                        Write-Log "Scanned new System32 file: $($dll.FullName) (Valid: $isValid)"
                        if (-not $isValid) {
                            if (Set-FileOwnershipAndPermissions -filePath $dll.FullName) {
                                Stop-ProcessUsingDLL -filePath $dll.FullName
                                Quarantine-File -filePath $dll.FullName
                            }
                        }
                    }
                }
            } catch {
                Write-Log "Error processing System32 file $($dll.FullName): $($_.Exception.Message)"
            }
        }
    } catch {
        Write-Log "System32 scan failed: $($_.Exception.Message)"
    }
}

# File System Watcher (Throttled and Crash-Proof)
$drives = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object { $_.DriveType -in (2, 3, 4) }
foreach ($drive in $drives) {
    $monitorPath = $drive.DeviceID + "\"
    try {
        $fileWatcher = New-Object System.IO.FileSystemWatcher
        $fileWatcher.Path = $monitorPath
        $fileWatcher.Filter = "*.*"
        $fileWatcher.IncludeSubdirectories = $true
        $fileWatcher.EnableRaisingEvents = $true
        $fileWatcher.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor [System.IO.NotifyFilters]::LastWrite
 
        $action = {
            param($sender, $e)
            try {
                if ($e.ChangeType -in "Created", "Changed" -and $e.FullPath -notlike "$quarantineFolder*" -and ($e.FullPath -like "*.dll" -or $e.FullPath -like "*.winmd")) {
                    if (Should-ExcludeFile -filePath $e.FullPath) {
                        return
                    }
                    
                    Write-Log "Detected file change: $($e.FullPath)"
                    $fileHash = Calculate-FileHash -filePath $e.FullPath
                    if ($fileHash) {
                        if ($scannedFiles.ContainsKey($fileHash.Hash)) {
                            Write-Log "Skipping already scanned file: $($e.FullPath) (Hash: $($fileHash.Hash))"
                            if (-not $scannedFiles[$fileHash.Hash]) {
                                if (Set-FileOwnershipAndPermissions -filePath $e.FullPath) {
                                    Stop-ProcessUsingDLL -filePath $e.FullPath
                                    Quarantine-File -filePath $e.FullPath
                                }
                            }
                        } else {
                            $isValid = $fileHash.Status -eq "Valid"
                            $scannedFiles[$fileHash.Hash] = $isValid
                            "$($fileHash.Hash),$isValid" | Out-File -FilePath $localDatabase -Append -Encoding UTF8 -ErrorAction Stop
                            Write-Log "Added new file to database: $($e.FullPath) (Valid: $isValid)"
                            if (-not $isValid) {
                                if (Set-FileOwnershipAndPermissions -filePath $e.FullPath) {
                                    Stop-ProcessUsingDLL -filePath $e.FullPath
                                    Quarantine-File -filePath $e.FullPath
                                }
                            }
                        }
                    }
                    Start-Sleep -Milliseconds 500 # Throttle to prevent event flood
                }
            } catch {
                Write-Log "Watcher error for $($e.FullPath): $($_.Exception.Message)"
            }
        }
 
        Register-ObjectEvent -InputObject $fileWatcher -EventName Created -Action $action -ErrorAction Stop
        Register-ObjectEvent -InputObject $fileWatcher -EventName Changed -Action $action -ErrorAction Stop
        Write-Log "FileSystemWatcher set up for $monitorPath"
    } catch {
        Write-Log "Failed to set up watcher for ${monitorPath} $($_.Exception.Message)"
    }
}

$ApiConfig = @{
    CirclHashLookupUrl   = "https://hashlookup.circl.lu/lookup/sha256"
    CymruApiUrl          = "https://api.malwarehash.cymru.com/v1/hash"
    MalwareBazaarApiUrl  = "https://mb-api.abuse.ch/api/v1/"
}

# ============================================
# HASH-BASED THREAT DETECTION
# ============================================
function Check-FileHash {
    param(
        [string]$FilePath,
        [string]$ProcessName,
        [int]$ProcessId
    )
    
    try {
        if (-not (Test-Path $FilePath)) {
            Write-Log "[HASH] File not found for hash check: $FilePath"
            return $false
        }
        
        $hash = (Get-FileHash -Path $FilePath -Algorithm SHA256).Hash
        Write-Log "[HASH] Checking hash for $ProcessName (PID: $ProcessId): $hash"
        
        $isMalicious = $false
        
        # Check CIRCL Hash Lookup
        try {
            $circlUrl = "$($ApiConfig.CirclHashLookupUrl)/$hash"
            $circlResponse = Invoke-RestMethod -Uri $circlUrl -Method Get -TimeoutSec 5 -ErrorAction Stop
            if ($circlResponse -and $circlResponse.KnownMalicious) {
                Write-Log "[HASH] CIRCL reports malicious: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] CIRCL lookup failed or no result"
        }
        
        # Check Team Cymru
        try {
            $cymruUrl = "$($ApiConfig.CymruApiUrl)/$hash"
            $cymruResponse = Invoke-RestMethod -Uri $cymruUrl -Method Get -TimeoutSec 5 -ErrorAction Stop
            if ($cymruResponse -and $cymruResponse.malicious -eq $true) {
                Write-Log "[HASH] Cymru reports malicious: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] Cymru lookup failed or no result"
        }
        
        # Check MalwareBazaar
        try {
            $mbBody = @{ query = "get_info"; hash = $hash } | ConvertTo-Json
            $mbResponse = Invoke-RestMethod -Uri $ApiConfig.MalwareBazaarApiUrl -Method Post -Body $mbBody -ContentType "application/json" -TimeoutSec 5 -ErrorAction Stop
            if ($mbResponse -and $mbResponse.query_status -eq "ok") {
                Write-Log "[HASH] MalwareBazaar reports known malware: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] MalwareBazaar lookup failed or no result"
        }
        
        return $isMalicious
        
    } catch {
        Write-Log "[HASH] Error during hash check: $_"
        return $false
    }
}

function Test-FileHash {
    param(
        [string]$FilePath,
        [string]$ProcessName,
        [int]$ProcessId
    )
    
    try {
        if (!(Test-Path $FilePath)) {
            Write-Log "[HASH] File not found for hash check: $FilePath"
            return $false
        }
        
        $hash = Get-SHA256Hash -FilePath $FilePath
        Write-Log "[HASH] Checking hash for $ProcessName (PID: $ProcessId): $hash"
        
        $isMalicious = $false
        
        # Check CIRCL Hash Lookup
        try {
            $circlUrl = "https://hashlookup.circl.lu/lookup/sha256/$hash"
            $response = Invoke-RestMethod -Uri $circlUrl -Method Get -ErrorAction Stop
            if ($response.KnownMalicious -eq $true) {
                Write-Log "[HASH] CIRCL reports malicious: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] CIRCL lookup failed or no result"
        }
        
        # Check Team Cymru
        try {
            $cymruUrl = "https://api.malwarehash.cymru.com/v1/hash/$hash"
            $response = Invoke-RestMethod -Uri $cymruUrl -Method Get -ErrorAction Stop
            if ($response.malicious -eq $true) {
                Write-Log "[HASH] Cymru reports malicious: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] Cymru lookup failed or no result"
        }
        
        # Check MalwareBazaar
        try {
            $body = @{
                query = "get_info"
                hash = $hash
            } | ConvertTo-Json
            
            $response = Invoke-RestMethod -Uri "https://mb-api.abuse.ch/api/v1/" -Method Post -Body $body -ContentType "application/json" -ErrorAction Stop
            if ($response.query_status -eq "ok") {
                Write-Log "[HASH] MalwareBazaar reports known malware: $ProcessName"
                $isMalicious = $true
            }
        } catch {
            Write-Log "[HASH] MalwareBazaar lookup failed or no result"
        }
        
        return $isMalicious
    } catch {
        Write-Log "[HASH] Error during hash check: $($_.Exception.Message)"
        return $false
    }
}

# ============================================
# THREAT KILLING
# ============================================
function Kill-Threat {
    param(
        [int]$ProcessId,
        [string]$ProcessName,
        [string]$Reason
    )
    
    try {
        if (Get-Process -Id $ProcessId -ErrorAction SilentlyContinue) {
            Write-Log "[KILL] Terminating process: $ProcessName (PID: $ProcessId) - Reason: $Reason"
            Stop-Process -Id $ProcessId -Force -ErrorAction Stop
            Write-Log "[KILL] Successfully terminated PID: $ProcessId"
            return $true
        } else {
            Write-Log "[KILL] Process already terminated: PID $ProcessId"
            return $false
        }
    } catch {
        Write-Log "[KILL] Failed to terminate PID $ProcessId : $_"
        return $false
    }
}

function Stop-ThreatProcess {
    param(
        [int]$ProcessId,
        [string]$ProcessName,
        [string]$Reason
    )
    
    try {
        $proc = Get-Process -Id $ProcessId -ErrorAction Stop
        
        if (Test-CriticalSystemProcess $proc) {
            Write-Log "[PROTECTION] Refusing to kill critical system process: $ProcessName (PID: $ProcessId)"
            return $false
        }
        
        if (Test-ProtectedOrSelf $proc) {
            Write-Log "[PROTECTION] Refusing to kill protected process: $ProcessName (PID: $ProcessId)"
            return $false
        }
        
        $proc.Kill()
        Write-Log "[KILL] Terminated: $ProcessName (PID: $ProcessId) - Reason: $Reason"
        return $true
    } catch {
        Write-Log "[ERROR] Failed to terminate PID ${ProcessId}: $($_.Exception.Message)"
        return $false
    }
}

function Invoke-ProcessKill {
    param(
        [int]$ProcessId,
        [string]$ProcessName,
        [string]$Reason
    )
    
    try {
        $proc = Get-Process -Id $ProcessId -ErrorAction Stop
        
        if ($ProcessId -eq $Script:SelfProcessName) {
            Write-Log "[PROTECTION] Refusing to kill self"
            return $false
        }
        
        if (Test-ProtectedOrSelf $proc) {
            Write-Log "[PROTECTION] Refusing to kill protected process: $ProcessName (PID: $ProcessId)"
            return $false
        }
        
        $proc.Kill()
        Write-Log "[KILL] Terminated: $ProcessName (PID: $ProcessId) - Reason: $Reason"
        return $true
    } catch {
        $errorMsg = $_.Exception.Message
        Write-Log "[ERROR] Failed to terminate PID ${ProcessId}: $errorMsg"
        return $false
    }
}

function Invoke-QuarantineProcess {
    param(
        $Process,
        [string]$Reason
    )
    
    try {
        Write-Log "Quarantining process $($Process.ProcessName) (PID: $($Process.Id)) due to: $Reason"
        
        if ($Process.Path -and (Test-Path $Process.Path) -and !(Test-ProtectedOrSelf $Process)) {
            Invoke-QuarantineFile -FilePath $Process.Path -ProcessName $Process.ProcessName -ProcessId $Process.Id -Reason $Reason
        }
        
        $Process.Kill()
        Write-Log "Killed malicious process: $($Process.ProcessName) (PID: $($Process.Id))"
    } catch {
        Write-Log "[ERROR] Failed to quarantine process $($Process.ProcessName) (PID: $($Process.Id)): $($_.Exception.Message)"
    }
}

# ============================================
# FILELESS MALWARE DETECTION
# ============================================
function Detect-FilelessMalware {
    # Monitor for common fileless techniques
    $filelessIndicators = @{
        "PowerShellWithoutFile" = {
            Get-Process -Name powershell -ErrorAction SilentlyContinue |
            Where-Object {
                $_.MainWindowTitle -match "encodedcommand|enc|iex|invoke-expression" -or
                $_.Modules | Where-Object { 
                    $_.ModuleName -eq "" -or $_.FileName -eq ""
                }
            }
        }
        "WMIEventSubscriptions" = {
            Get-WmiObject -Namespace root\Subscription -Class __EventFilter -ErrorAction SilentlyContinue |
            Where-Object { $_.Query -match "powershell|vbscript|javascript" }
        }
        "RegistryScripts" = {
            $suspiciousKeys = @(
                "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
                "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
            )
            $results = @()
            foreach ($key in $suspiciousKeys) {
                if (Test-Path $key) {
                    Get-ItemProperty -Path $key -ErrorAction SilentlyContinue |
                        ForEach-Object {
                        $_.PSObject.Properties | Where-Object {
                            $_.Value -match "powershell.*-enc|mshta|regsvr32.*scrobj"
                        } | ForEach-Object {
                            $results += $_
                        }
                    }
                }
            }
            return $results
        }
    }
    
    $detections = @()
    foreach ($indicator in $filelessIndicators.Keys) {
        $results = & $filelessIndicators[$indicator]
        if ($results) {
            $detections += [PSCustomObject]@{
                Indicator = $indicator
                Details = $results
            }
            Write-Log "[ALERT] Fileless malware detected: $indicator"
            
            if ($indicator -eq "PowerShellWithoutFile") {
                foreach ($proc in $results) {
                    # Check hash if file path exists
                    if ($proc.Path) {
                        $hashMalicious = Check-FileHash -FilePath $proc.Path -ProcessName $proc.Name -ProcessId $proc.Id
                        if ($hashMalicious) {
                            Invoke-QuarantineFile -FilePath $proc.Path -ProcessName $proc.Name -ProcessId $proc.Id -Reason "Malicious hash + Fileless PowerShell"
                        }
                    }
                    Kill-Threat -ProcessId $proc.Id -ProcessName $proc.Name -Reason "Fileless PowerShell execution"
                }
            }
            elseif ($indicator -eq "WMIEventSubscriptions") {
                foreach ($subscription in $results) {
                    try {
                        Write-Log "[ACTION] Removing malicious WMI event filter: $($subscription.Name)"
                        Remove-WmiObject -InputObject $subscription -ErrorAction Stop
                        
                        # Also remove associated consumers and bindings
                        $consumers = Get-WmiObject -Namespace root\Subscription -Class __EventConsumer -Filter "Name='$($subscription.Name)'" -ErrorAction SilentlyContinue
                        $bindings = Get-WmiObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "Filter='$($subscription.__RELPATH)'" -ErrorAction SilentlyContinue
                        
                        foreach ($consumer in $consumers) {
                            Remove-WmiObject -InputObject $consumer -ErrorAction SilentlyContinue
                            Write-Log "[ACTION] Removed associated WMI consumer: $($consumer.Name)"
                        }
                        foreach ($binding in $bindings) {
                            Remove-WmiObject -InputObject $binding -ErrorAction SilentlyContinue
                            Write-Log "[ACTION] Removed WMI binding"
                        }
                    } catch {
                        Write-Log "[ERROR] Failed to remove WMI subscription: $_"
                    }
                }
            }
            elseif ($indicator -eq "RegistryScripts") {
                foreach ($regEntry in $results) {
                    try {
                        $keyPath = $regEntry.PSPath
                        $valueName = $regEntry.Name
                        Write-Log "[ACTION] Removing malicious registry entry: $keyPath\$valueName"
                        Remove-ItemProperty -Path $keyPath -Name $valueName -Force -ErrorAction Stop
                    } catch {
                        Write-Log "[ERROR] Failed to remove registry entry: $_"
                    }
                }
            }
        }
    }
    
    return $detections
}

# ============================================
# MEMORY SCANNER
# ============================================
Write-Log "[+] Starting PowerShell memory scanner"
Start-Job -ScriptBlock {
    $log = "$using:Base\ps_memory_hits.log"
    $QuarantineDir = $using:QuarantineDir
    $Base = $using:Base
    
    ${function:Check-FileHash} = ${using:function:Check-FileHash}
    ${function:Kill-Threat} = ${using:function:Kill-Threat}
    ${function:Invoke-QuarantineFile} = ${using:function:Invoke-QuarantineFile}
    ${function:Write-Log} = ${using:function:Write-Log}
    $ApiConfig = $using:ApiConfig
    $logFile = $using:logFile
    $Script:logFile = $logFile
    
    $EvilStrings = @(
        'mimikatz','sekurlsa::','kerberos::','lsadump::','wdigest','tspkg',
        'http-beacon','https-beacon','cobaltstrike','sleepmask','reflective',
        'amsi.dll','AmsiScanBuffer','EtwEventWrite','MiniDumpWriteDump',
        'VirtualAllocEx','WriteProcessMemory','CreateRemoteThread',
        'ReflectiveLoader','sharpchrome','rubeus','safetykatz','sharphound'
    )
    while ($true) {
        Start-Sleep -Seconds 2
        Get-Process | Where-Object {
            $_.WorkingSet64 -gt 100MB -or $_.Name -match 'powershell|wscript|cscript|mshta|rundll32|regsvr32|msbuild|cmstp|excel|word|outlook'
        } | ForEach-Object {
            $hit = $false
            try {
                $_.Modules | ForEach-Object {
                    if ($EvilStrings | Where-Object { $_.ModuleName -match $_ -or $_.FileName -match $_ }) {
                        $hit = $true
                    }
                }
            } catch {}
            if ($hit) {
                "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | PS MEMORY HIT → $($_.Name) ($($_.Id))" | Out-File $log -Append
                
                if ($_.Path) {
                    $hashMalicious = Check-FileHash -FilePath $_.Path -ProcessName $_.Name -ProcessId $_.Id
                    if ($hashMalicious) {
                        Invoke-QuarantineFile -FilePath $_.Path -ProcessName $_.Name -ProcessId $_.Id -Reason "Malicious strings in memory"
                    }
                }
                Kill-Threat -ProcessId $_.Id -ProcessName $_.Name -Reason "Malicious strings in memory"
            }
        }
    }
} | Out-Null

# ============================================
# REFLECTIVE PAYLOAD DETECTOR
# ============================================
Write-Log "[+] Starting reflective payload detector"
Start-Job -ScriptBlock {
    $log = "$using:Base\manual_map_hits.log"
    $QuarantineDir = $using:QuarantineDir
    $Base = $using:Base
    
    ${function:Check-FileHash} = ${using:function:Check-FileHash}
    ${function:Kill-Threat} = ${using:function:Kill-Threat}
    ${function:Invoke-QuarantineFile} = ${using:function:Invoke-QuarantineFile}
    ${function:Write-Log} = ${using:function:Write-Log}
    $ApiConfig = $using:ApiConfig
    $logFile = $using:logFile
    $Script:logFile = $logFile
    
    while ($true) {
        Start-Sleep -Seconds 2
        Get-Process | Where-Object { $_.WorkingSet64 -gt 40MB } | ForEach-Object {
            $p = $_
            $sus = $false
            if (-not $p.Path -or $p.Path -eq '' -or $p.Path -match '$$Unknown$$') { $sus = $true }
            if ($p.Modules | Where-Object { $_.FileName -eq '' -or $_.ModuleName -eq '' }) { $sus = $true }
            if ($sus) {
                "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | REFLECTIVE PAYLOAD → $($p.Name) ($($p.Id)) Path='$($p.Path)'" | Out-File $log -Append
                
                if ($p.Path) {
                    $hashMalicious = Check-FileHash -FilePath $p.Path -ProcessName $p.Name -ProcessId $p.Id
                    if ($hashMalicious) {
                        Invoke-QuarantineFile -FilePath $p.Path -ProcessName $p.Name -ProcessId $p.Id -Reason "Reflective payload detected"
                    }
                }
                Kill-Threat -ProcessId $p.Id -ProcessName $p.Name -Reason "Reflective payload detected"
            }
        }
    }
} | Out-Null

# ============================================
# ============================================
function Start-MemoryScanner {
    Start-Job -ScriptBlock {
        param($LogFile, $QuarantineDir, $EvilStrings, $ProtectedProcessNames, $SelfProcessName, $SelfPath)
        
        $Script:LogFile = $LogFile
        $Script:QuarantineDir = $QuarantineDir
        
        while ($true) {
            try {
                Get-Process | Where-Object {
                    try {
                        $procName = $_.ProcessName.ToLower()
                        $procId = $_.Id
                        
                        if ($procId -eq $SelfProcessName) { return $false }
                        if ($ProtectedProcessNames -contains $procName) { return $false }
                        
                        $_.WorkingSet64 -lt 500MB
                    } catch { $false }
                } | ForEach-Object {
                    try {
                        $proc = $_
                        
                        foreach ($module in $proc.Modules) {
                            $modulePath = $module.FileName.ToLower()
                            
                            if ($modulePath -match "\\temp\\" -or $modulePath -match "\\appdata\\local\\temp\\") {
                                Add-Content -Path $LogFile -Value "SUSPICIOUS: Process $($proc.ProcessName) loaded module from temp: $($module.FileName)" -Encoding UTF8
                                $proc.Kill()
                                Add-Content -Path $LogFile -Value "[KILL] Terminated suspicious process: $($proc.ProcessName) (PID: $($proc.Id))" -Encoding UTF8
                                break
                            }
                            
                            foreach ($evil in $EvilStrings) {
                                if ($modulePath -match $evil) {
                                    Add-Content -Path $LogFile -Value "THREAT DETECTED: $evil in process $($proc.ProcessName)" -Encoding UTF8
                                    $proc.Kill()
                                    Add-Content -Path $LogFile -Value "[KILL] Terminated malicious process: $($proc.ProcessName) (PID: $($proc.Id))" -Encoding UTF8
                                    break
                                }
                            }
                        }
                    } catch {}
                }
                
                Start-Sleep -Seconds 45
            } catch {}
        }
    } -ArgumentList $Script:logFile, $Script:QuarantineDir, $Script:EvilStrings, $Script:ProtectedProcessNames, $Script:SelfProcessName, $Script:SelfPath | Out-Null
    
    Write-Log "[+] Enhanced memory scanner started"
}

# ============================================
# ============================================
function Start-ReflectivePayloadDetector {
    Start-Job -ScriptBlock {
        param($LogFile, $ProtectedProcessNames, $SelfProcessName)
        
        $Script:LogFile = $LogFile
        
        while ($true) {
            try {
                Get-Process | Where-Object {
                    try {
                        $procName = $_.ProcessName.ToLower()
                        $procId = $_.Id
                        
                        if ($procId -eq $SelfProcessName) { return $false }
                        if ($ProtectedProcessNames -contains $procName) { return $false }
                        
                        $true
                    } catch { $false }
                } | ForEach-Object {
                    try {
                        $proc = $_
                        $commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)" -ErrorAction SilentlyContinue).CommandLine
                        
                        if ($commandLine) {
                            $isSuspicious = $false
                            $pattern = ""
                            
                            if ($commandLine -match "invoke-expression|iex ") {
                                $isSuspicious = $true
                                $pattern = "Invoke-Expression"
                            } elseif ($commandLine -match "downloadstring|downloaddata") {
                                $isSuspicious = $true
                                $pattern = "Download and Execute"
                            } elseif ($commandLine -match "reflection\.assembly.*load") {
                                $isSuspicious = $true
                                $pattern = "Reflective Assembly Load"
                            } elseif ($commandLine -match "-encodedcommand|-enc ") {
                                $isSuspicious = $true
                                $pattern = "Encoded Command"
                            }
                            
                            if ($isSuspicious) {
                                Add-Content -Path $LogFile -Value "[REFLECTIVE PAYLOAD] $pattern detected in process $($proc.ProcessName) (PID: $($proc.Id)) - Terminating" -Encoding UTF8
                                $proc.Kill()
                                Add-Content -Path $LogFile -Value "[KILL] Terminated process: $($proc.ProcessName) (PID: $($proc.Id)) - Reason: Reflective payload detected" -Encoding UTF8
                            }
                        }
                    } catch {}
                }
                
                Start-Sleep -Seconds 40
            } catch {}
        }
    } -ArgumentList $Script:logFile, $Script:ProtectedProcessNames, $Script:SelfProcessName | Out-Null
    
    Write-Log "[+] Enhanced reflective payload detector started"
}

# ============================================
# BEHAVIOR MONITOR
# ============================================
function Start-BehaviorMonitor {
    $suspiciousBehaviors = @{
        "ProcessHollowing" = {
            param($Process)
            # Check for process hollowing indicators
            $procPath = $Process.Path
            $modules = Get-Process -Id $Process.Id -Module -ErrorAction SilentlyContinue
            return ($modules -and $procPath -and ($modules[0].FileName -ne $procPath))
        }
        "CredentialAccess" = {
            param($Process)
            # Check for credential dumping tools
            $cmdline = (Get-CimInstance Win32_Process -Filter "ProcessId=$($Process.Id)" -ErrorAction SilentlyContinue).CommandLine
            return ($cmdline -match "mimikatz|procdump|sekurlsa|lsadump" -or 
                    $Process.ProcessName -match "vaultcmd|cred")
        }
        "LateralMovement" = {
            param($Process)
            # Detect lateral movement attempts
            $connections = Get-NetTCPConnection -OwningProcess $Process.Id -ErrorAction SilentlyContinue
            $remoteIPs = $connections | Where-Object { 
                $_.RemoteAddress -notmatch "^(127\.|192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)" -and
                $_.RemoteAddress -ne "0.0.0.0" -and
                $_.RemoteAddress -ne "::"
            }
            return ($remoteIPs.Count -gt 5)
        }
    }
    
    Start-Job -ScriptBlock {
        $behaviors = $using:suspiciousBehaviors
        $logFile = "$using:Base\behavior_detections.log"
        $Base = $using:Base
        $QuarantineDir = $using:QuarantineDir
        
        ${function:Check-FileHash} = ${using:function:Check-FileHash}
        ${function:Kill-Threat} = ${using:function:Kill-Threat}
        ${function:Invoke-QuarantineFile} = ${using:function:Invoke-QuarantineFile}
        ${function:Write-Log} = ${using:function:Write-Log}
        $ApiConfig = $using:ApiConfig
        $Script:logFile = $using:logFile
        
        while ($true) {
            Start-Sleep -Seconds 5
            Get-Process | ForEach-Object {
                $process = $_
                foreach ($behavior in $behaviors.Keys) {
                    try {
                        if (& $behaviors[$behavior] $process) {
                            $msg = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') | BEHAVIOR DETECTED: $behavior | " +
                                   "Process: $($process.Name) PID: $($process.Id) " +
                                   "Path: $($process.Path)"
                            $msg | Out-File $logFile -Append
                            
                            if ($behavior -in @("ProcessHollowing", "CredentialAccess")) {
                                if ($process.Path) {
                                    $hashMalicious = Check-FileHash -FilePath $process.Path -ProcessName $process.Name -ProcessId $process.Id
                                    if ($hashMalicious) {
                                        Invoke-QuarantineFile -FilePath $process.Path -ProcessName $process.Name -ProcessId $process.Id -Reason "Suspicious behavior: $behavior"
                                    }
                                }
                                Kill-Threat -ProcessId $process.Id -ProcessName $process.Name -Reason "Suspicious behavior: $behavior"
                            }
                        }
                    } catch {
                        # Silently continue on errors
                    }
                }
            }
        }
    } | Out-Null
}

function Start-EnhancedBehaviorMonitor {
    Start-Job -ScriptBlock {
        param($LogFile, $ProtectedProcessNames, $SelfProcessName, $QuarantineDir)
        
        $Script:LogFile = $LogFile
        $Script:QuarantineDir = $QuarantineDir
        
        while ($true) {
            try {
                Get-Process | Where-Object {
                    try {
                        $procName = $_.ProcessName.ToLower()
                        $procId = $_.Id
                        
                        if ($procId -eq $SelfProcessName) { return $false }
                        if ($ProtectedProcessNames -contains $procName) { return $false }
                        
                        $true
                    } catch { $false }
                } | ForEach-Object {
                    try {
                        $proc = $_
                        $threadCount = $proc.Threads.Count
                        $handleCount = $proc.HandleCount
                        
                        if ($threadCount -gt 100 -or $handleCount -gt 10000) {
                            Add-Content -Path $LogFile -Value "SUSPICIOUS BEHAVIOR: High thread/handle count in $($proc.ProcessName) (Threads: $threadCount, Handles: $handleCount)" -Encoding UTF8
                        }
                        
                        # Check for suspicious process name
                        if ($proc.ProcessName -match "^[a-z0-9]{32}$") {
                            Add-Content -Path $LogFile -Value "SUSPICIOUS BEHAVIOR: Random process name: $($proc.ProcessName)" -Encoding UTF8
                        }
                    } catch {}
                }
                
                Start-Sleep -Seconds 30
            } catch {}
        }
    } -ArgumentList $Script:logFile, $Script:ProtectedProcessNames, $Script:SelfProcessName, $Script:QuarantineDir | Out-Null
    
    Write-Log "[+] Enhanced behavior monitor started"
}

# ============================================
# ============================================
function Start-COMControlMonitor {
    Start-Job -ScriptBlock {
        param($LogFile, $QuarantineDir)
        
        $Script:LogFile = $LogFile
        $Script:QuarantineDir = $QuarantineDir
        
        while ($true) {
            try {
                $basePaths = @(
                    "HKLM:\SOFTWARE\WOW6432Node\Classes\CLSID",
                    "HKLM:\SOFTWARE\Classes\CLSID"
                )
                
                foreach ($basePath in $basePaths) {
                    if (Test-Path $basePath) {
                        Get-ChildItem -Path $basePath | Where-Object {
                            $_.PSChildName -match "\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"
                        } | ForEach-Object {
                            $clsid = $_.PSChildName
                            $clsidPath = Join-Path $basePath $clsid
                            
                            @("InProcServer32", "InprocHandler32") | ForEach-Object {
                                $subKeyPath = Join-Path $clsidPath $_
                                
                                if (Test-Path $subKeyPath) {
                                    $dllPath = (Get-ItemProperty -Path $subKeyPath -Name "(Default)" -ErrorAction SilentlyContinue)."(Default)"
                                    
                                    if ($dllPath -and (Test-Path $dllPath)) {
                                        if ($dllPath -match "\\temp\\|\\downloads\\|\\public\\" -or (Get-Item $dllPath).Length -lt 100KB) {
                                            Add-Content -Path $LogFile -Value "REMOVING malicious COM control: $dllPath" -Encoding UTF8
                                            Remove-Item -Path $clsidPath -Recurse -Force -ErrorAction SilentlyContinue
                                            Remove-Item -Path $dllPath -Force -ErrorAction SilentlyContinue
                                            Add-Content -Path $LogFile -Value "Deleted COM control and DLL: $dllPath" -Encoding UTF8
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                
                Start-Sleep -Seconds 60
            } catch {}
        }
    } -ArgumentList $Script:logFile, $Script:QuarantineDir | Out-Null
    
    Write-Log "[+] COM control monitor started"
}

function Invoke-MalwareScan {
    try {
        Get-Process | Where-Object {
            try {
                !(Test-ProtectedOrSelf $_) -and !(Test-CriticalSystemProcess $_)
            } catch { $false }
        } | ForEach-Object {
            try {
                $proc = $_
                $procName = $proc.ProcessName.ToLower()
                
                # Fileless malware detection
                if ($procName -match "powershell|cmd") {
                    $commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)" -ErrorAction SilentlyContinue).CommandLine
                    
                    if ($commandLine -and ($commandLine -match "-encodedcommand|-enc|invoke-expression|downloadstring|iex|-executionpolicy bypass")) {
                        Write-Log "[DETECTED] Fileless malware: $($proc.ProcessName) (PID: $($proc.Id))"
                        Write-Log "    Suspicious command: $commandLine"
                        Invoke-QuarantineProcess -Process $proc -Reason "Fileless malware execution"
                    }
                }
            } catch {}
        }
    } catch {}
}

function Invoke-LogRotation {
    try {
        if ((Get-Item $Script:logFile -ErrorAction SilentlyContinue).Length -gt 50MB) {
            $backupLog = "$($Script:logFile).old"
            if (Test-Path $backupLog) {
                Remove-Item $backupLog -Force
            }
            Move-Item $Script:logFile $backupLog -Force
            Write-Log "[*] Log rotated due to size"
        }
    } catch {}
}

# ============================================
# MAIN EXECUTION
# ============================================

Write-Log "[+] Starting all detection modules"

Add-ToStartup

# Initial scan
Remove-UnsignedDLLs

Start-BehaviorMonitor
Start-MemoryScanner
Start-ReflectivePayloadDetector
Start-EnhancedBehaviorMonitor
Start-COMControlMonitor

Write-Log "Initial scan completed. All monitoring modules started."
 
# Keep script running with crash protection
Write-Host "Antivirus running. Press [Ctrl] + [C] to stop."
try {
    while ($true) {
        # Run fileless malware detection every 10 seconds
        Start-Sleep -Seconds 10
        Detect-FilelessMalware | Out-Null
        
        # Run additional malware scan every 30 seconds
        Invoke-MalwareScan
        
        # Rotate logs if needed
        Invoke-LogRotation
    }
} finally {
    # Cleanup on exit
    Write-Log "=== Stopping detection modules ==="
    Get-Job | Stop-Job
    Get-Job | Remove-Job
    Write-Log "=== Detection stopped ==="
}
Editor is loading...
Leave a Comment