Gorstaks Antivirus
unknown
powershell
2 months ago
75 kB
17
No Index
<#
.SYNOPSIS
EDR / Antivirus — single PowerShell script; auto-installs and persists. Use -Uninstall to remove.
.DESCRIPTION
Runs detection jobs in background. No tray or dashboard. Install and persistence are automatic.
.PARAMETER Uninstall
Remove persistence and delete install folder, then exit.
.NOTES
Author: Gorstak
#>
param([switch]$Uninstall)
#Requires -Version 5.1
# --- Config (matches C# EdrConfig) ---
$script:EDRName = 'MalwareDetector'
$script:InstallPath = 'C:\ProgramData\AntivirusProtection'
$script:LogPath = 'C:\ProgramData\AntivirusProtection\Logs'
$script:QuarantinePath= 'C:\ProgramData\AntivirusProtection\Quarantine'
$script:ReportsPath = 'C:\ProgramData\AntivirusProtection\Reports'
$script:DataPath = 'C:\ProgramData\AntivirusProtection\Data'
$script:YaraSubFolder = 'Yara'
$script:YaraExeName = 'yara.exe'
$script:YaraRulesFileName = 'rules.yar'
$script:AutoKillThreats = $true
$script:AutoQuarantine = $true
$script:CirclHashLookupUrl = 'https://hashlookup.circl.lu/lookup/sha256'
$script:CymruApiUrl = 'https://api.malwarehash.cymru.com/v1/hash'
$script:MalwareBazaarApiUrl = 'https://mb-api.abuse.ch/api/v1/'
# --- State ---
# PowerShell 5.1 has no ?? operator; use this instead
function script:NullCoalesce { param($Value, $Default = ''); if ($null -eq $Value) { $Default } else { $Value } }
$script:ThreatCount = 0
$script:FilesQuarantined = 0
$script:ProcessesTerminated = 0
# --- Logging ---
$script:EdrLogLock = [object]::new()
function Write-EdrLog {
param([string]$Source, [string]$Message, [string]$Level = 'INFO', [string]$LogFile)
$line = "[{0:yyyy-MM-dd HH:mm:ss}] [{1}] [{2}] {3}" -f (Get-Date), $Level, $Source, $Message
[System.Threading.Monitor]::Enter($script:EdrLogLock)
try {
if (-not (Test-Path -LiteralPath $script:LogPath)) { New-Item -ItemType Directory -Path $script:LogPath -Force | Out-Null }
$fileName = if ($LogFile) { $LogFile } else { "edr_$(Get-Date -Format 'yyyy-MM-dd').log" }
$path = Join-Path $script:LogPath $fileName
Add-Content -LiteralPath $path -Value $line
} finally { [System.Threading.Monitor]::Exit($script:EdrLogLock) }
}
# --- Install / Persistence (script-based) ---
$script:PersistenceValueName = 'AntivirusProtection'
$script:RunKeyPath = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
function Get-CurrentScriptPath {
if ($PSCommandPath) { return $PSCommandPath }
return $MyInvocation.MyCommand.Path
}
function Get-InstalledScriptPath {
return Join-Path $script:InstallPath 'Antivirus.ps1'
}
function Test-EdrInstalled {
return Test-Path -LiteralPath (Get-InstalledScriptPath)
}
function Install-Edr {
$src = Get-CurrentScriptPath
if (-not $src -or -not (Test-Path -LiteralPath $src)) { return 'Current script not found.' }
try {
if (-not (Test-Path -LiteralPath $script:InstallPath)) { New-Item -ItemType Directory -Path $script:InstallPath -Force | Out-Null }
foreach ($sub in @('Logs','Quarantine','Reports','Data',$script:YaraSubFolder)) {
$d = Join-Path $script:InstallPath $sub
if (-not (Test-Path -LiteralPath $d)) { New-Item -ItemType Directory -Path $d -Force | Out-Null }
}
$dest = Get-InstalledScriptPath
Copy-Item -LiteralPath $src -Destination $dest -Force
$baseDir = [System.IO.Path]::GetDirectoryName($src)
$yaraSrc = Join-Path $baseDir $script:YaraExeName
if (Test-Path -LiteralPath $yaraSrc) {
$yaraDest = Join-Path (Join-Path $script:InstallPath $script:YaraSubFolder) $script:YaraExeName
$yaraDir = [System.IO.Path]::GetDirectoryName($yaraDest)
if (-not (Test-Path -LiteralPath $yaraDir)) { New-Item -ItemType Directory -Path $yaraDir -Force | Out-Null }
Copy-Item -LiteralPath $yaraSrc -Destination $yaraDest -Force
}
$rulesSrc = Join-Path $baseDir $script:YaraRulesFileName
if (Test-Path -LiteralPath $rulesSrc) {
$rulesDest = Join-Path $script:InstallPath $script:YaraRulesFileName
Copy-Item -LiteralPath $rulesSrc -Destination $rulesDest -Force
}
Write-EdrLog -Source 'EdrInstall' -Message "Installed to $($script:InstallPath)" -Level INFO
return $null
} catch {
Write-EdrLog -Source 'EdrInstall' -Message "Install failed: $($_.Exception.Message)" -Level ERROR
return "Install failed: $($_.Exception.Message)"
}
}
function Test-EdrPersisted {
try {
$v = Get-ItemProperty -Path $script:RunKeyPath -Name $script:PersistenceValueName -ErrorAction SilentlyContinue
return $null -ne $v -and $null -ne $v.($script:PersistenceValueName)
} catch { return $false }
}
function Enable-EdrPersistence {
if (-not (Test-EdrInstalled)) {
$err = Install-Edr
if ($err) { return $err }
}
$ps1Path = Get-InstalledScriptPath
$arg = "-WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -File `"$ps1Path`""
try {
Set-ItemProperty -Path $script:RunKeyPath -Name $script:PersistenceValueName -Value "powershell.exe $arg" -Type String
Write-EdrLog -Source 'EdrInstall' -Message 'Persistence enabled (HKCU Run).' -Level INFO
return $null
} catch {
Write-EdrLog -Source 'EdrInstall' -Message "Enable persistence failed: $($_.Exception.Message)" -Level ERROR
return "Persistence enable failed: $($_.Exception.Message)"
}
}
function Disable-EdrPersistence {
try {
Remove-ItemProperty -Path $script:RunKeyPath -Name $script:PersistenceValueName -ErrorAction SilentlyContinue
Write-EdrLog -Source 'EdrInstall' -Message 'Persistence disabled (HKCU Run removed).' -Level INFO
return $null
} catch {
Write-EdrLog -Source 'EdrInstall' -Message "Disable persistence failed: $($_.Exception.Message)" -Level ERROR
return "Persistence disable failed: $($_.Exception.Message)"
}
}
function Uninstall-Edr {
Disable-EdrPersistence | Out-Null
try {
if (Test-Path -LiteralPath $script:InstallPath) {
Remove-Item -LiteralPath $script:InstallPath -Recurse -Force
}
return $null
} catch {
try { Write-EdrLog -Source 'EdrInstall' -Message "Uninstall delete failed: $($_.Exception.Message)" -Level ERROR } catch { }
return "Uninstall failed (folder in use?): $($_.Exception.Message)"
}
}
# --- Helpers (PowerShell equivalents of EdrFile, EdrWhitelist, EdrQuarantine, EdrProcess, CleanGuard, GlobalRules, etc.) ---
$script:SuspiciousExtensions = @('.exe', '.dll', '.scr', '.vbs', '.ps1', '.bat', '.cmd')
$script:WhitelistNames = @('explorer.exe', 'explorer', 'Antivirus.exe', 'Antivirus.ps1', 'dllhost.exe', 'conhost.exe', 'sihost.exe', 'fontdrvhost.exe', 'SearchHost.exe', 'RuntimeBroker.exe', 'StartMenuExperienceHost.exe', 'SystemSettings.exe', 'ApplicationFrameHost.exe', 'Taskmgr.exe', 'msiexec.exe', 'TrustedInstaller.exe')
function Get-SuspiciousScanPaths {
$localApp = [Environment]::GetFolderPath('LocalApplicationData')
$appData = [Environment]::GetFolderPath('ApplicationData')
$userProfile = [Environment]::GetEnvironmentVariable('USERPROFILE', 'User')
$win = [Environment]::GetFolderPath('Windows')
@(
[System.IO.Path]::GetTempPath(),
$appData,
(Join-Path $localApp 'Temp'),
(Join-Path $win 'Temp'),
(Join-Path $userProfile 'Downloads')
) | Where-Object { $_ }
}
function Get-SuspiciousFiles {
$list = [System.Collections.Generic.List[string]]::new()
foreach ($basePath in Get-SuspiciousScanPaths) {
if (-not $basePath -or -not (Test-Path -LiteralPath $basePath)) { continue }
try {
foreach ($ext in $script:SuspiciousExtensions) {
Get-ChildItem -LiteralPath $basePath -Filter "*$ext" -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object { $list.Add($_.FullName) }
}
} catch { }
}
return $list
}
function Get-FileSha256 {
param([string]$Path)
try {
$fs = [System.IO.File]::OpenRead($Path)
try {
$sha = [System.Security.Cryptography.SHA256]::Create()
$bytes = $sha.ComputeHash($fs)
return [BitConverter]::ToString($bytes).Replace('-', '').ToLowerInvariant()
} finally { $fs.Close() }
} catch { return $null }
}
function Measure-FileEntropy {
param([string]$Path)
try {
$fs = [System.IO.File]::OpenRead($Path)
$toRead = [Math]::Min(4097, $fs.Length)
$bytes = New-Object byte[] $toRead
$r = $fs.Read($bytes, 0, $toRead)
$fs.Close()
if ($r -le 0) { return 0 }
if ($r -lt $bytes.Length) { $bytes = $bytes[0..($r - 1)] }
$freq = @{}
foreach ($b in $bytes) { $freq[$b] = ($freq[$b] + 1) }
$n = $bytes.Length
$ent = 0.0
foreach ($c in $freq.Values) { $p = $c / $n; $ent -= $p * [Math]::Log($p, 2) }
return $ent
} catch { return 0 }
}
function Get-FileLength { param([string]$Path) try { return (Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue).Length } catch { return 0 } }
function Test-SuspiciousDllPath {
param([string]$Path)
if (-not $Path) { return $false }
$p = $Path.ToUpperInvariant()
if ($p -match '\\TEMP\\' -or $p -match '\\TEMP"') { return $true }
if ($p -match '\\APPDATA\\' -or $p -match '\\LOCALAPPDATA\\' -or $p -match '\\DOWNLOAD' -or $p -match '\\DESKTOP') { return $true }
return $false
}
function Test-WhitelistedPath {
param([string]$Path)
if (-not $Path) { return $true }
$name = [System.IO.Path]::GetFileName($Path)
if (-not $name) { return $false }
foreach ($n in $script:WhitelistNames) { if ($name -eq $n) { return $true } }
return $false
}
function Move-ToQuarantine {
param([string]$FilePath, [string]$Reason)
if (-not $FilePath -or -not (Test-Path -LiteralPath $FilePath)) { return $false }
try {
if (-not (Test-Path -LiteralPath $script:QuarantinePath)) { New-Item -ItemType Directory -Path $script:QuarantinePath -Force | Out-Null }
$fileName = [System.IO.Path]::GetFileName($FilePath)
$dest = Join-Path $script:QuarantinePath ("{0}_{1}" -f [DateTime]::UtcNow.Ticks, $fileName)
Move-Item -LiteralPath $FilePath -Destination $dest -Force
$script:FilesQuarantined++
Write-EdrLog -Source 'EdrQuarantine' -Message "Quarantined: $FilePath (Reason: $Reason)" -Level THREAT
return $true
} catch {
Write-EdrLog -Source 'EdrQuarantine' -Message "Quarantine failed for $FilePath : $($_.Exception.Message)" -Level ERROR
return $false
}
}
function Get-ProcessesWmi {
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
$searcher = New-Object System.Management.ManagementObjectSearcher 'SELECT ProcessId,Name,CommandLine,ExecutablePath,ParentProcessId FROM Win32_Process'
foreach ($o in $searcher.Get()) {
$list.Add([PSCustomObject]@{
ProcessId = [int]$o['ProcessId']
Name = [string]$o['Name']
CommandLine = [string]$o['CommandLine']
ExecutablePath = [string]$o['ExecutablePath']
ParentProcessId = [int]$o['ParentProcessId']
})
}
} catch { Write-EdrLog -Source 'EdrProcess' -Message "GetProcesses error: $($_.Exception.Message)" -Level ERROR }
return $list
}
function Get-ParentProcess { param($Child, $All) if (-not $Child -or -not $All) { return $null }; foreach ($p in $All) { if ($p.ProcessId -eq $Child.ParentProcessId) { return $p } }; return $null }
function Get-ProcessExecutablePathWmi { param([int]$ProcessId) try { $s = New-Object System.Management.ManagementObjectSearcher ("SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = {0}" -f $ProcessId); foreach ($o in $s.Get()) { $p = [string]$o['ExecutablePath']; if ($p) { return $p } } } catch { }; return $null }
function Get-ProcessOwnerWmi { param([int]$ProcessId); try { $q = "SELECT * FROM Win32_Process WHERE ProcessId = $ProcessId"; $s = New-Object System.Management.ManagementObjectSearcher $q; foreach ($o in $s.Get()) { $argList = @('', ''); $o.InvokeMethod('GetOwner', $argList) | Out-Null; return ($argList[1], $argList[0]) } } catch { }; return ($null, $null) }
function Stop-ThreatProcess {
param([int]$ProcessId, [string]$ProcessName)
if ($ProcessId -eq $pid) { return }
try {
$proc = Get-Process -Id $ProcessId -ErrorAction Stop
$proc.Kill()
$script:ProcessesTerminated++
Write-EdrLog -Source 'EdrProcess' -Message "Terminated threat process: $ProcessName (PID: $ProcessId)" -Level ACTION
} catch { Write-EdrLog -Source 'EdrProcess' -Message "Failed to terminate $ProcessName : $($_.Exception.Message)" -Level ERROR }
}
$script:CleanGuardCirclTrustThreshold = 50
$script:CleanGuardSelfHash = $null
function Get-CleanGuardSelfHash {
if ($null -ne $script:CleanGuardSelfHash) { return $script:CleanGuardSelfHash }
try {
$selfPath = (Get-Process -Id $pid).Path
if ($selfPath -and (Test-Path -LiteralPath $selfPath)) { $script:CleanGuardSelfHash = Get-FileSha256 -Path $selfPath }
} catch { }
return $script:CleanGuardSelfHash
}
function Test-CleanGuardMalicious {
param([string]$Path, [string]$Sha256)
if (-not $Path -or -not (Test-Path -LiteralPath $Path)) { return $false }
if (Test-WhitelistedPath -Path $Path) { return $false }
$hash = if ($Sha256) { $Sha256 } else { Get-FileSha256 -Path $Path }
if (-not $hash) { return $false }
$sh = Get-CleanGuardSelfHash
if ($sh -and $hash -eq $sh) { return $false }
try {
$url = $script:CirclHashLookupUrl.TrimEnd('/') + '/' + $hash
$json = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 8 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Content
if ($json -match 'hashlookup:trust["\s]*:\s*(\d+)') { $trust = [int]$Matches[1]; if ($trust -ge $script:CleanGuardCirclTrustThreshold) { return $false } }
} catch { }
try {
$body = '{"query":"get_info","hash":"' + $hash + '"}'
$r = Invoke-WebRequest -Uri $script:MalwareBazaarApiUrl -Method POST -Body $body -ContentType 'application/json' -UseBasicParsing -TimeoutSec 12 -ErrorAction SilentlyContinue
if ($r.Content -match 'hash_found') { return $true }
} catch { }
try {
$url = $script:CymruApiUrl.TrimEnd('/') + '/' + $hash
$body = (Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 8 -ErrorAction SilentlyContinue).Content
if ($body -match '"malware":\s*true') { return $true }
} catch { }
return $false
}
function Move-QuarantineIfAllowed {
param([string]$Path, [string]$Reason)
if (-not $script:AutoQuarantine) { return $false }
if (-not (Test-CleanGuardMalicious -Path $Path)) { return $false }
return (Move-ToQuarantine -FilePath $Path -Reason $Reason)
}
function Stop-ProcessIfAllowed {
param([int]$ProcessId, [string]$ProcessName, [string]$ExePath, [switch]$Fileless)
if (-not $script:AutoKillThreats) { return }
$path = if ($ExePath) { $ExePath } else { Get-ProcessExecutablePathWmi -ProcessId $ProcessId }
if (-not $path -or -not (Test-Path -LiteralPath $path)) { return }
if (Test-WhitelistedPath -Path $path) { return }
# Fileless: no file to hash (payload in memory/command line); kill on detection without API check
if ($Fileless) { Stop-ThreatProcess -ProcessId $ProcessId -ProcessName $ProcessName; return }
$hash = Get-FileSha256 -Path $path
if (-not $hash) { return }
$sh = Get-CleanGuardSelfHash
if ($sh -and $hash -eq $sh) { return }
if (-not (Test-CleanGuardMalicious -Path $path -Sha256 $hash)) { return }
Stop-ThreatProcess -ProcessId $ProcessId -ProcessName $ProcessName
}
function Get-RunEntriesRegistry {
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
foreach ($hive in @('HKLM', 'HKCU')) {
foreach ($sub in @('Run', 'RunOnce')) {
$keyPath = "${hive}:\SOFTWARE\Microsoft\Windows\CurrentVersion\$sub"
if (-not (Test-Path -LiteralPath $keyPath)) { continue }
Get-ItemProperty -Path $keyPath -ErrorAction SilentlyContinue | ForEach-Object {
$_.PSObject.Properties | Where-Object { $_.Name -notmatch '^(PSPath|PSParentPath|PSChildName|PSDrive|PSProvider)' } | ForEach-Object {
$list.Add([PSCustomObject]@{ KeyName = "$hive\...\$sub"; ValueName = $_.Name; Value = [string]$_.Value })
}
}
}
}
} catch { Write-EdrLog -Source 'EdrRegistry' -Message "GetRunEntries error: $($_.Exception.Message)" -Level ERROR }
return $list
}
function Test-AmsiDisabledRegistry {
try {
$k = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\AMSI' -ErrorAction SilentlyContinue
if (-not $k) { return $false }
$v = $k.DisableAMSI
if ($null -eq $v) { return $false }
if ($v -is [int]) { return $v -ne 0 }
return ([string]$v) -eq '1'
} catch { return $false }
}
function Get-WmiEventFilters {
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
$s = New-Object System.Management.ManagementObjectSearcher 'root\subscription', 'SELECT * FROM __EventFilter'
foreach ($o in $s.Get()) { $list.Add([PSCustomObject]@{ Name = [string]$o['Name']; Query = [string]$o['Query'] }) }
} catch { Write-EdrLog -Source 'EdrWmi' -Message "GetEventFilters error: $($_.Exception.Message)" -Level ERROR }
return $list
}
function Get-WmiCommandLineConsumers {
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
$s = New-Object System.Management.ManagementObjectSearcher 'root\subscription', 'SELECT * FROM CommandLineEventConsumer'
foreach ($o in $s.Get()) { $list.Add([PSCustomObject]@{ Name = [string]$o['Name']; CommandLineTemplate = [string]$o['CommandLineTemplate'] }) }
} catch { Write-EdrLog -Source 'EdrWmi' -Message "GetCommandLineConsumers error: $($_.Exception.Message)" -Level ERROR }
return $list
}
function Get-ScheduledTasksList {
$list = [System.Collections.Generic.List[PSCustomObject]]::new()
try {
$out = & schtasks /query /fo LIST /v 2>$null
$cur = [PSCustomObject]@{ TaskName = ''; State = ''; RunAsUser = ''; Execute = '' }
foreach ($line in $out) {
if ($line -match '^TaskName:\s*(.+)') { $cur.TaskName = $Matches[1].Trim() }
elseif ($line -match '^Status:\s*(.+)') { $cur.State = $Matches[1].Trim() }
elseif ($line -match '^Run As User:\s*(.+)') { $cur.RunAsUser = $Matches[1].Trim() }
elseif ($line -match '^Task To Run:\s*(.+)') { $cur.Execute = $Matches[1].Trim(); $list.Add($cur); $cur = [PSCustomObject]@{ TaskName = ''; State = ''; RunAsUser = ''; Execute = '' } }
}
} catch { Write-EdrLog -Source 'EdrScheduledTask' -Message "QueryTasks error: $($_.Exception.Message)" -Level ERROR }
return $list
}
function Test-ScheduledTaskSuspicious { param($t); if (-not $t.Execute) { return $false }; $exe = $t.Execute.ToLower(); if ($exe -notmatch 'powershell|cmd|wscript|cscript|mshta') { return $false }; $user = (NullCoalesce $t.RunAsUser).ToLower(); if ($user -match 'system|administrator') { return $false }; if ((NullCoalesce $t.TaskName) -match '^AntivirusAutoRestart_|^AntivirusProtection$') { return $false }; return $true }
function Get-BrowserRoots {
$local = [Environment]::GetFolderPath('LocalApplicationData')
$app = [Environment]::GetFolderPath('ApplicationData')
if (-not $local) { $local = [Environment]::GetEnvironmentVariable('LOCALAPPDATA', 'User') }
if (-not $app) { $app = [Environment]::GetEnvironmentVariable('APPDATA', 'User') }
$entries = @(
(Join-Path $local 'Google\Chrome\User Data'), (Join-Path $local 'Microsoft\Edge\User Data'), (Join-Path $local 'BraveSoftware\Brave-Browser\User Data'),
(Join-Path $local 'Opera Software\Opera Stable'), (Join-Path $local 'Opera Software\Opera GX Stable'), (Join-Path $local 'Vivaldi\User Data'),
(Join-Path $local 'Yandex\YandexBrowser\User Data'), (Join-Path $app 'Mozilla\Firefox\Profiles'), (Join-Path $local 'Mozilla\Firefox\Profiles'),
(Join-Path $local 'Chromium\User Data')
)
$entries | Where-Object { $_ -and (Test-Path -LiteralPath $_) }
}
function Get-ElfDllsInBrowsers {
$out = [System.Collections.Generic.List[string]]::new()
foreach ($root in Get-BrowserRoots) {
try { Get-ChildItem -LiteralPath $root -Filter '*_elf.dll' -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object { $out.Add($_.FullName) } } catch { }
}
return $out
}
# --- Job functions (PowerShell implementations; no C#) ---
function Invoke-JobHashDetection {
$files = Get-SuspiciousFiles
foreach ($path in $files) {
try {
if (Test-WhitelistedPath -Path $path) { continue }
if (Move-QuarantineIfAllowed -Path $path -Reason 'HashDetection') {
$hash = Get-FileSha256 -Path $path
Write-EdrLog -Source 'HashDetection' -Message ("THREAT (CleanGuard): {0} | Hash: {1}" -f $path, $hash) -Level THREAT -LogFile 'hash_detections.log'
$script:ThreatCount++
} else {
$ent = Measure-FileEntropy -Path $path
$len = Get-FileLength -Path $path
if ($ent -gt 7.5 -and $len -gt 0 -and $len -lt 1MB) { Write-EdrLog -Source 'HashDetection' -Message ("High entropy: {0} | Entropy: {1:N2}" -f $path, $ent) -Level WARNING -LogFile 'hash_detections.log' }
}
} catch { Write-EdrLog -Source 'HashDetection' -Message "Error scanning $path : $($_.Exception.Message)" -Level ERROR -LogFile 'hash_detections.log' }
}
}
function Invoke-JobLOLBinDetection {
$self = $pid
$procs = Get-ProcessesWmi
$lolBins = @(
@{ Name = 'certutil'; Patterns = @('-decode', '-urlcache', '-verifyctl', '-encode'); Severity = 'HIGH'; Description = 'Certutil abuse' },
@{ Name = 'bitsadmin'; Patterns = @('transfer', 'addfile', '/download'); Severity = 'HIGH'; Description = 'BITS abuse' },
@{ Name = 'mshta'; Patterns = @('http://', 'https://', 'javascript:', 'vbscript:'); Severity = 'CRITICAL'; Description = 'MSHTA remote code execution' },
@{ Name = 'regsvr32'; Patterns = @('scrobj.dll', '/s', '/u', 'http://', 'https://'); Severity = 'HIGH'; Description = 'Regsvr32 squiblydoo' },
@{ Name = 'rundll32'; Patterns = @('javascript:', 'http://', 'https://', 'shell32.dll,Control_RunDLL'); Severity = 'MEDIUM'; Description = 'Rundll32 proxy execution' },
@{ Name = 'wmic'; Patterns = @('process call create', '/node:', 'format:"http', 'xsl:http'); Severity = 'HIGH'; Description = 'WMIC remote/XSL abuse' },
@{ Name = 'powershell'; Patterns = @('-enc ', '-encodedcommand', 'downloadstring', 'iex ', 'invoke-expression', '-nop', '-w hidden', 'bypass'); Severity = 'HIGH'; Description = 'PowerShell obfuscation' },
@{ Name = 'sc'; Patterns = @('create', 'config', 'binpath='); Severity = 'MEDIUM'; Description = 'Service manipulation' },
@{ Name = 'msiexec'; Patterns = @('/quiet', '/q', 'http://', 'https://'); Severity = 'MEDIUM'; Description = 'Silent MSI from remote' }
)
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$cmd = (NullCoalesce $p.CommandLine)
if (-not $cmd) { continue }
$pname = ((NullCoalesce $p.Name)).Replace('.exe', '').Replace('.EXE', '')
foreach ($lb in $lolBins) {
if ($pname -notmatch $lb.Name) { continue }
$matched = @(); foreach ($pat in $lb.Patterns) { if ($cmd -match [regex]::Escape($pat)) { $matched += $pat } }
if ($matched.Count -eq 0) { continue }
Write-EdrLog -Source 'LOLBinDetection' -Message ("LOLBin [{0}] Process: {1} (PID: {2}) | {3} | Patterns: {4} | {5}" -f $lb.Severity, $p.Name, $p.ProcessId, $lb.Description, ($matched -join ', '), $cmd) -Level THREAT -LogFile 'behavior_detections.log'
$script:ThreatCount++
if ($lb.Severity -in @('HIGH', 'CRITICAL')) { Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath }
break
}
}
}
function Invoke-JobProcessAnomalyDetection {
$self = $pid
$procs = Get-ProcessesWmi
foreach ($proc in $procs) {
if ($proc.ProcessId -eq $self) { continue }
$score = 0; $anomalies = @()
$parent = Get-ParentProcess -Child $proc -All $procs
if ($parent) {
if (((NullCoalesce $parent.Name)) -match 'winword|excel|powerpnt|outlook' -and ((NullCoalesce $proc.Name)) -match 'powershell|cmd|wscript|cscript') { $score += 5; $anomalies += 'OfficeSpawnScript' }
if (((NullCoalesce $parent.Name)) -eq 'explorer.exe' -and ((NullCoalesce $proc.CommandLine)) -match '-w hidden|-windowstyle hidden|-nop|-enc') { $score += 4; $anomalies += 'ExplorerHiddenScript' }
if (((NullCoalesce $parent.Name)) -eq 'svchost.exe') { $n = ((NullCoalesce $proc.Name)).ToLower(); if ($n -notmatch 'dllhost|conhost|rundll32') { $score += 3; $anomalies += 'SvchostUnexpectedChild' } }
}
$path = (NullCoalesce $proc.ExecutablePath)
if ($path -and $path -match 'Users\\.*\\AppData|Users\\.*\\Downloads|Users\\.*\\Desktop' -and ((NullCoalesce $proc.Name)) -match '\.exe$') { $score += 2; $anomalies += 'UserDirExecution' }
foreach ($sys in @('svchost.exe', 'lsass.exe', 'csrss.exe', 'smss.exe')) {
if (((NullCoalesce $proc.Name)) -eq $sys -and $path -notmatch '\\Windows\\System32') { $score += 6; $anomalies += 'SystemBinaryWrongLocation'; break }
}
$cmd = (NullCoalesce $proc.CommandLine)
if ($cmd -match '-enc |-encodedcommand |FromBase64String') { $score += 3; $anomalies += 'Base64Encoding' }
if ($cmd -match '-exec bypass|-executionpolicy bypass|-ep bypass') { $score += 2; $anomalies += 'ExecutionPolicyBypass' }
if ($cmd -match 'DownloadString|DownloadFile|WebClient|Invoke-WebRequest|wget |curl ') { $score += 3; $anomalies += 'DownloadCradle' }
if ($score -ge 6) {
Write-EdrLog -Source 'ProcessAnomalyDetection' -Message ("CRITICAL process anomaly - {0} (PID: {1}) | Parent: {2} | Score: {3} | {4} | {5} | {6}" -f $proc.Name, $proc.ProcessId, ((NullCoalesce $parent.Name)), $score, ($anomalies -join ', '), $path, $cmd) -Level THREAT -LogFile 'behavior_detections.log'
$script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $proc.ProcessId -ProcessName $proc.Name -ExePath $proc.ExecutablePath
} elseif ($score -ge 3) { Write-EdrLog -Source 'ProcessAnomalyDetection' -Message ("Process anomaly - {0} (PID: {1}) | Score: {2} | {3}" -f $proc.Name, $proc.ProcessId, $score, ($anomalies -join ', ')) -Level WARNING -LogFile 'behavior_detections.log' }
}
}
function Invoke-JobAMSIBypassDetection {
$bypassPatterns = @('AmsiUtils', 'AmsiScanBuffer', 'amsiInitFailed', 'Bypass', 'amsi.dll', 'PatchAmsi', 'DisableAmsi', 'Remove-Amsi', 'Invoke-AmsiBypass', 'AMSI.*bypass', 'bypass.*AMSI', '-nop.*-w.*hidden.*-enc', 'amsi.*off', 'amsi.*disable', 'Set-Amsi', 'Override.*AMSI', 'System.Management.Automation.AmsiUtils')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$name = ((NullCoalesce $p.Name)).ToLower()
if ($name -notmatch 'powershell|pwsh|wscript|cscript') { continue }
$cmd = (NullCoalesce $p.CommandLine); if (-not $cmd) { continue }
foreach ($pat in $bypassPatterns) { if ($cmd -match $pat) { Write-EdrLog -Source 'AMSIBypassDetection' -Message ("AMSI BYPASS: {0} (PID: {1}) - {2}" -f $p.Name, $p.ProcessId, $pat) -Level THREAT -LogFile 'amsi_bypass_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath -Fileless; break } }
if ($cmd -match '-enc' -and $cmd -match '-encodedcommand' -and $cmd.Length -gt 500) { Write-EdrLog -Source 'AMSIBypassDetection' -Message ("AMSI BYPASS (obfuscated): {0} (PID: {1}) long encoded command" -f $p.Name, $p.ProcessId) -Level THREAT -LogFile 'amsi_bypass_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath -Fileless }
}
if (Test-AmsiDisabledRegistry) { Write-EdrLog -Source 'AMSIBypassDetection' -Message 'AMSI BYPASS: Registry tampering HKLM\SOFTWARE\Microsoft\AMSI DisableAMSI' -Level THREAT -LogFile 'amsi_bypass_detections.log'; $script:ThreatCount++ }
}
function Invoke-JobCredentialDumpDetection {
$self = $pid; $procs = Get-ProcessesWmi
$credTools = @('mimikatz', 'sekurlsa', 'pwdump', 'gsecdump', 'wce', 'procdump', 'dumpert', 'nanodump', 'lsassy', 'lsadump', 'cachedump')
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$cmd = ((NullCoalesce $p.CommandLine)).ToLower(); $pname = ((NullCoalesce $p.Name)).ToLower()
if ($cmd -match 'lsass') { Write-EdrLog -Source 'CredentialDumpDetection' -Message ("LSASS access - {0} (PID: {1}) | {2}" -f $p.Name, $p.ProcessId, $p.CommandLine) -Level THREAT -LogFile 'credential_dumping_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; continue }
if ($cmd -match 'reg' -and ($cmd -match 'save' -or $cmd -match 'export') -and ($cmd -match 'sam' -or $cmd -match 'security' -or $cmd -match 'system')) { Write-EdrLog -Source 'CredentialDumpDetection' -Message ("Registry credential hive access - {0} (PID: {1}) | {2}" -f $p.Name, $p.ProcessId, $p.CommandLine) -Level THREAT -LogFile 'credential_dumping_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; continue }
if ($cmd -match 'minidump|createdump|\.dmp') { Write-EdrLog -Source 'CredentialDumpDetection' -Message ("Memory dump creation - {0} (PID: {1}) | {2}" -f $p.Name, $p.ProcessId, $p.CommandLine) -Level WARNING -LogFile 'credential_dumping_detections.log'; continue }
foreach ($tool in $credTools) { if ($pname -match $tool -or $cmd -match $tool) { Write-EdrLog -Source 'CredentialDumpDetection' -Message ("Credential dumping tool - {0} | {1} (PID: {2}) | {3}" -f $tool, $p.Name, $p.ProcessId, $p.CommandLine) -Level THREAT -LogFile 'credential_dumping_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobCredentialProtection {
try {
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -Name 'RunAsPPL' -Value 1 -Type DWord -ErrorAction SilentlyContinue
Write-EdrLog -Source 'CredentialProtection' -Message 'Enabled LSASS as Protected Process Light. Reboot required.' -Level INFO -LogFile 'credential_protection.log'
} catch { Write-EdrLog -Source 'CredentialProtection' -Message "RunAsPPL: $($_.Exception.Message)" -Level ERROR -LogFile 'credential_protection.log' }
try { & schtasks /delete /tn "GenerateRandomPassword" /f 2>$null } catch { }
$scriptPath = Join-Path [Environment]::GetFolderPath('CommonApplicationData') 'PasswordTasks.ps1'
if (Test-Path -LiteralPath $scriptPath) { Remove-Item -LiteralPath $scriptPath -Force -ErrorAction SilentlyContinue }
$cmdkeyPath = Join-Path $env:SystemRoot 'System32\cmdkey.exe'
if (Test-Path -LiteralPath $cmdkeyPath) { try { $o = & $cmdkeyPath /list 2>$null; if ($o) { Write-EdrLog -Source 'CredentialProtection' -Message 'Cleared cached credentials.' -Level INFO -LogFile 'credential_protection.log' } } catch { Write-EdrLog -Source 'CredentialProtection' -Message "cmdkey: $($_.Exception.Message)" -Level ERROR -LogFile 'credential_protection.log' } }
try { Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name 'CachedLogonsCount' -Value '0' -Type String -ErrorAction SilentlyContinue; Write-EdrLog -Source 'CredentialProtection' -Message 'Disabled credential caching.' -Level INFO -LogFile 'credential_protection.log' } catch { Write-EdrLog -Source 'CredentialProtection' -Message "CachedLogonsCount: $($_.Exception.Message)" -Level ERROR -LogFile 'credential_protection.log' }
try { & auditpol /set /subcategory:"Credential Validation" /success:enable /failure:enable 2>$null; Write-EdrLog -Source 'CredentialProtection' -Message 'Enabled auditing for credential validation.' -Level INFO -LogFile 'credential_protection.log' } catch { Write-EdrLog -Source 'CredentialProtection' -Message "auditpol: $($_.Exception.Message)" -Level ERROR -LogFile 'credential_protection.log' }
}
function Invoke-JobWMIPersistenceDetection {
foreach ($f in Get-WmiEventFilters) { Write-EdrLog -Source 'WMIPersistenceDetection' -Message ("WMI Event filter: {0} | Query: {1}" -f $f.Name, $f.Query) -Level INFO -LogFile 'wmi_persistence.log' }
foreach ($c in Get-WmiCommandLineConsumers) { Write-EdrLog -Source 'WMIPersistenceDetection' -Message ("WMI Command consumer: {0} | Command: {1}" -f $c.Name, $c.CommandLineTemplate) -Level INFO -LogFile 'wmi_persistence.log' }
}
function Invoke-JobScheduledTaskDetection {
foreach ($t in Get-ScheduledTasksList) {
if (-not (Test-ScheduledTaskSuspicious $t)) { continue }
Write-EdrLog -Source 'ScheduledTaskDetection' -Message ("SUSPICIOUS ScheduledTask: {0} | Action: {1} | User: {2}" -f $t.TaskName, $t.Execute, $t.RunAsUser) -Level THREAT -LogFile 'scheduled_task_detections.log'
$script:ThreatCount++
}
}
function Invoke-JobRegistryPersistenceDetection {
$suspicious = @('powershell.*-enc', 'cmd.*/c.*powershell', 'https?://', '\.vbs|\.js|\.bat|\.cmd', 'wscript|cscript|mshta', 'rundll32.*\.dll', 'regsvr32.*\.dll')
foreach ($e in Get-RunEntriesRegistry) {
$v = (NullCoalesce $e.Value)
if (-not $v) { continue }
foreach ($r in $suspicious) { if ($v -match $r) { Write-EdrLog -Source 'RegistryPersistenceDetection' -Message ("REGISTRY PERSISTENCE: {0} | {1} | {2}" -f $e.KeyName, $e.ValueName, $v) -Level THREAT -LogFile 'registry_persistence_detections.log'; $script:ThreatCount++; break } }
}
}
function Invoke-JobDLLHijackingDetection {
$self = $pid
Get-Process -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Id -eq $self) { return }
try {
foreach ($m in $_.Modules) {
$path = $m.FileName
if (-not $path -or $path -notmatch '\.dll') { continue }
if (-not (Test-SuspiciousDllPath -Path $path)) { continue }
Write-EdrLog -Source 'DLLHijackingDetection' -Message ("DLL HIJACKING: Suspicious DLL | {0} (PID: {1}) | {2}" -f $_.ProcessName, $_.Id, $path) -Level THREAT -LogFile 'dll_hijacking_detections.log'
$script:ThreatCount++
Stop-ProcessIfAllowed -ProcessId $_.Id -ProcessName $_.ProcessName -ExePath (Get-ProcessExecutablePathWmi -ProcessId $_.Id)
break
}
} catch { } finally { $_.Dispose() }
}
}
function Invoke-JobTokenManipulationDetection {
$self = $pid; $win = [Environment]::GetFolderPath('Windows')
Get-Process -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.Id -eq $self) { return }
try {
$path = $_.Path
if (-not $path) { return }
$domain, $user = Get-ProcessOwnerWmi -ProcessId $_.Id
if (-not $domain -or $domain -notmatch 'NT AUTHORITY') { return }
if ($path -like "$win*") { return }
Write-EdrLog -Source 'TokenManipulationDetection' -Message ("SUSPICIOUS: Non-system binary as SYSTEM | {0} | {1}" -f $_.ProcessName, $path) -Level THREAT -LogFile 'token_manipulation.log'
$script:ThreatCount++
Stop-ProcessIfAllowed -ProcessId $_.Id -ProcessName $_.ProcessName -ExePath $path
} catch { } finally { $_.Dispose() }
}
}
function Invoke-JobProcessHollowingDetection {
$suspParents = @('explorer.exe', 'winlogon.exe', 'services.exe')
$suspChildren = @('notepad.exe', 'calc.exe', 'cmd.exe', 'powershell.exe', 'wmic.exe', 'rundll32.exe')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$path = (NullCoalesce $p.ExecutablePath); if (-not $path) { continue }
$parent = Get-ParentProcess -Child $p -All $procs
if ($parent -and $parent.Name -and ($suspParents -contains $parent.Name) -and $p.Name -and ($suspChildren -contains $p.Name)) {
Write-EdrLog -Source 'ProcessHollowingDetection' -Message ("PROCESS HOLLOWING: Suspicious parent-child | {0} (PID: {1}) | Parent: {2}" -f $p.Name, $p.ProcessId, $parent.Name) -Level THREAT -LogFile 'process_hollowing_detections.log'
$script:ThreatCount++
Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath
}
}
}
function Invoke-JobKeyloggerDetection {
$patterns = @('keylogger', 'keylog', 'keystroke', 'keyboard.*hook', 'GetAsyncKeyState', 'SetWindowsHookEx', 'WH_KEYBOARD')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$cmd = ((NullCoalesce $p.CommandLine)) + ' ' + ((NullCoalesce $p.Name))
foreach ($pat in $patterns) { if ($cmd -match $pat) { Write-EdrLog -Source 'KeyloggerDetection' -Message ("KEYLOGGER: {0} (PID: {1}) | {2}" -f $p.Name, $p.ProcessId, $pat) -Level THREAT -LogFile 'keylogger_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobRansomwareDetection {
$patterns = @('vssadmin delete shadows', 'vssadmin.exe delete', 'wbadmin delete catalog', 'bcdedit', 'shadow copy', 'shadowcopy', 'cryptolocker', 'wannacry', '.encrypted', '.locked', '.crypto')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$cmd = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($pat in $patterns) { if ($cmd -match $pat) { Write-EdrLog -Source 'RansomwareDetection' -Message ("RANSOMWARE: {0} (PID: {1}) | {2}" -f $p.Name, $p.ProcessId, $pat) -Level THREAT -LogFile 'ransomware_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobNetworkAnomalyDetection {
try {
$suspPorts = @(4444, 5555, 6666, 8080, 31337, 12345)
$conns = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetActiveTcpConnections()
foreach ($c in $conns) {
if ($c.State -ne [System.Net.NetworkInformation.TcpState]::Established) { continue }
$remotePort = $c.RemoteEndPoint.Port
if ($suspPorts -contains $remotePort) { Write-EdrLog -Source 'NetworkAnomalyDetection' -Message ("Suspicious remote port {0} | Local: {1} -> {2}" -f $remotePort, $c.LocalEndPoint, $c.RemoteEndPoint) -Level WARNING -LogFile 'network_anomaly.log'; $script:ThreatCount++ }
}
} catch { Write-EdrLog -Source 'NetworkAnomalyDetection' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'network_anomaly.log' }
}
function Invoke-JobNetworkTrafficMonitoring {
try {
$props = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
$listeners = $props.GetActiveTcpListeners().Count
$conns = $props.GetActiveTcpConnections().Count
Write-EdrLog -Source 'NetworkTrafficMonitoring' -Message "Listeners: $listeners | TCP connections: $conns" -Level INFO -LogFile 'network_traffic.log'
} catch { Write-EdrLog -Source 'NetworkTrafficMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'network_traffic.log' }
}
function Invoke-JobRootkitDetection {
try {
$s = New-Object System.Management.ManagementObjectSearcher "SELECT Name,PathName,State FROM Win32_Service WHERE State = 'Running'"
foreach ($o in $s.Get()) {
$path = [string]$o['PathName']
if (-not $path) { continue }
if ($path -match 'system32' -or $path -match 'windows') { continue }
Write-EdrLog -Source 'RootkitDetection' -Message ("Non-standard running service: {0} | {1}" -f $o['Name'], $path) -Level WARNING -LogFile 'rootkit_detections.log'
}
} catch { Write-EdrLog -Source 'RootkitDetection' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'rootkit_detections.log' }
}
function Invoke-JobCOMMonitoring {
try {
$s = New-Object System.Management.ManagementObjectSearcher 'SELECT Caption,Status FROM Win32_COMApplication'
$n = 0; foreach ($o in $s.Get()) { $n++ }
Write-EdrLog -Source 'COMMonitoring' -Message "COM applications enumerated: $n" -Level INFO -LogFile 'com_monitoring.log'
} catch { Write-EdrLog -Source 'COMMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'com_monitoring.log' }
}
function Invoke-JobShadowCopyMonitoring {
try {
$o = & vssadmin list shadows 2>&1 | Out-String
if ($o -match 'No items found') { Write-EdrLog -Source 'ShadowCopyMonitoring' -Message 'No shadow copies found (potential deletion attempt)' -Level WARNING -LogFile 'shadow_copy.log' }
else { Write-EdrLog -Source 'ShadowCopyMonitoring' -Message 'Shadow copy check completed' -Level INFO -LogFile 'shadow_copy.log' }
} catch { Write-EdrLog -Source 'ShadowCopyMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'shadow_copy.log' }
}
function Invoke-JobUSBMonitoring {
try {
$s = New-Object System.Management.ManagementObjectSearcher "SELECT Caption,DeviceID FROM Win32_DiskDrive WHERE InterfaceType = 'USB'"
foreach ($o in $s.Get()) { Write-EdrLog -Source 'USBMonitoring' -Message ("USB drive: {0} | {1}" -f $o['Caption'], $o['DeviceID']) -Level INFO -LogFile 'usb_monitoring.log' }
} catch { Write-EdrLog -Source 'USBMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'usb_monitoring.log' }
}
function Invoke-JobMobileDeviceMonitoring {
try {
$s = New-Object System.Management.ManagementObjectSearcher "SELECT Caption,DeviceID FROM Win32_PnPEntity WHERE Caption LIKE '%portable%' OR Caption LIKE '%USB%' OR Caption LIKE '%MTP%'"
$n = 0; foreach ($o in $s.Get()) { $n++ }
if ($n -gt 0) { Write-EdrLog -Source 'MobileDeviceMonitoring' -Message "Portable/MTP devices: $n" -Level INFO -LogFile 'mobile_device_monitoring.log' }
} catch { Write-EdrLog -Source 'MobileDeviceMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'mobile_device_monitoring.log' }
}
function Invoke-JobAttackToolsDetection {
$tools = @('mimikatz', 'pwdump', 'procdump', 'wce', 'gsecdump', 'cain', 'john', 'hashcat', 'hydra', 'medusa', 'nmap', 'metasploit', 'armitage')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$n = ((NullCoalesce $p.Name)).ToLower(); $c = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($t in $tools) { if ($n -match $t -or $c -match $t) { Write-EdrLog -Source 'AttackToolsDetection' -Message ("Attack tool: {0} | {1} (PID: {2})" -f $t, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'attack_tools_detection.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobAdvancedThreatDetection {
$paths = @('C:\Windows\Temp', 'C:\Windows\System32\Tasks')
$ext = @('.exe', '.dll', '.ps1', '.vbs')
foreach ($basePath in $paths) {
if (-not (Test-Path -LiteralPath $basePath)) { continue }
try {
foreach ($e in $ext) {
Get-ChildItem -LiteralPath $basePath -Filter "*$e" -File -ErrorAction SilentlyContinue | ForEach-Object {
$ent = Measure-FileEntropy -Path $_.FullName
if ($ent -le 7.5) { return }
if (Move-QuarantineIfAllowed -Path $_.FullName -Reason 'AdvancedThreat') {
Write-EdrLog -Source 'AdvancedThreatDetection' -Message ("High-entropy file (CleanGuard): {0} | Entropy: {1:N2}" -f $_.FullName, $ent) -Level THREAT -LogFile 'advanced_threat_detection.log'
$script:ThreatCount++
}
}
}
} catch { Write-EdrLog -Source 'AdvancedThreatDetection' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'advanced_threat_detection.log' }
}
}
function Invoke-JobEventLogMonitoring {
try {
$log = New-Object System.Diagnostics.EventLog 'Application', '.'
$n = $log.Entries.Count
if ($n -gt 0) { $e = $log.Entries[$n - 1]; Write-EdrLog -Source 'EventLogMonitoring' -Message ("Last Application event: {0} | {1} | {2}" -f $e.TimeGenerated, $e.Source, $e.InstanceId) -Level INFO -LogFile 'eventlog_monitoring.log' }
} catch { Write-EdrLog -Source 'EventLogMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'eventlog_monitoring.log' }
}
function Invoke-JobFirewallRuleMonitoring {
try {
$o = & netsh advfirewall firewall show rule name=all 2>&1 | Out-String
$n = 0; foreach ($line in ($o -split "`n")) { if ($line.TrimStart() -match '^Rule Name:') { $n++ } }
Write-EdrLog -Source 'FirewallRuleMonitoring' -Message "Firewall rules enumerated: $n" -Level INFO -LogFile 'firewall_monitoring.log'
} catch { Write-EdrLog -Source 'FirewallRuleMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'firewall_monitoring.log' }
}
function Invoke-JobServiceMonitoring {
try {
$s = New-Object System.Management.ManagementObjectSearcher "SELECT Name,State,PathName FROM Win32_Service WHERE State = 'Running'"
$n = 0; foreach ($o in $s.Get()) { $n++ }
Write-EdrLog -Source 'ServiceMonitoring' -Message "Running services: $n" -Level INFO -LogFile 'service_monitoring.log'
} catch { Write-EdrLog -Source 'ServiceMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'service_monitoring.log' }
}
function Invoke-JobFilelessDetection {
$indicators = @('-enc ', '-encodedcommand', 'iex(', 'invoke-expression', 'frombase64string', 'scriptblock', 'reflection.assembly')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$n = ((NullCoalesce $p.Name)).ToLower(); if ($n -notmatch 'powershell|pwsh|wscript|cscript') { continue }
$c = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($pat in $indicators) { if ($c -match $pat) { Write-EdrLog -Source 'FilelessDetection' -Message ("Fileless indicator: {0} | {1} (PID: {2})" -f $pat, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'fileless_detection.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath -Fileless; break } }
}
}
function Invoke-JobMemoryScanning {
try {
$total = 0
Get-Process -ErrorAction SilentlyContinue | ForEach-Object { try { $total += $_.WorkingSet64 } catch { } }
Write-EdrLog -Source 'MemoryScanning' -Message ("Total working set (all processes): {0} MB" -f ([Math]::Round($total / 1MB))) -Level INFO -LogFile 'memory_scanning.log'
} catch { Write-EdrLog -Source 'MemoryScanning' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'memory_scanning.log' }
}
function Invoke-JobNamedPipeMonitoring {
$suspiciousPatterns = @('paexec', 'psexec', 'cobalt', 'mimikatz', 'remcom', 'evil', 'backdoor', 'shell', 'meterpreter', 'beacon', 'c2', 'lateral', 'dcom', 'wmi.*pipe', 'winlogon', 'lsass.*pipe', 'dcsync')
try {
$pipeNames = [System.IO.Directory]::GetFiles('\\.\pipe\')
$total = $pipeNames.Count
$suspicious = @()
foreach ($full in $pipeNames) {
$name = [System.IO.Path]::GetFileName($full)
if (-not $name) { continue }
$lower = $name.ToLower()
foreach ($pat in $suspiciousPatterns) {
if ($lower -match $pat) { $suspicious += $name; break }
}
}
if ($suspicious.Count -gt 0) {
foreach ($s in $suspicious) {
Write-EdrLog -Source 'NamedPipeMonitoring' -Message "SUSPICIOUS named pipe: $s" -Level THREAT -LogFile 'named_pipe.log'
$script:ThreatCount++
}
Write-EdrLog -Source 'NamedPipeMonitoring' -Message "Pipes: $total total | Suspicious: $($suspicious.Count) | $($suspicious -join ', ')" -Level WARNING -LogFile 'named_pipe.log'
} else { Write-EdrLog -Source 'NamedPipeMonitoring' -Message "Pipes: $total total | No suspicious names" -Level INFO -LogFile 'named_pipe.log' }
} catch { Write-EdrLog -Source 'NamedPipeMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'named_pipe.log' }
}
function Invoke-JobDNSExfiltrationDetection {
try {
$stats = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetUdpIPv4Statistics()
Write-EdrLog -Source 'DNSExfiltrationDetection' -Message ("UDP stats (DNS proxy): Received {0} Sent {1}" -f $stats.DatagramsReceived, $stats.DatagramsSent) -Level INFO -LogFile 'dns_exfiltration.log'
} catch { Write-EdrLog -Source 'DNSExfiltrationDetection' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'dns_exfiltration.log' }
}
function Invoke-JobBeaconDetection {
try {
$beaconPorts = @(4444, 5555, 6666, 8080, 443, 80)
$conns = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetActiveTcpConnections()
foreach ($c in $conns) {
if ($c.State -ne [System.Net.NetworkInformation.TcpState]::Established) { continue }
$remotePort = $c.RemoteEndPoint.Port
if ($beaconPorts -contains $remotePort) { Write-EdrLog -Source 'BeaconDetection' -Message ("Potential beacon port {0} | {1}" -f $remotePort, $c.RemoteEndPoint) -Level WARNING -LogFile 'beacon_detections.log'; $script:ThreatCount++ }
}
} catch { Write-EdrLog -Source 'BeaconDetection' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'beacon_detections.log' }
}
function Invoke-JobCodeInjectionDetection {
$patterns = @('VirtualAllocEx', 'WriteProcessMemory', 'CreateRemoteThread', 'NtCreateThreadEx', 'RtlCreateUserThread', 'QueueUserAPC')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$c = (NullCoalesce $p.CommandLine)
foreach ($pat in $patterns) { if ($c -match $pat) { Write-EdrLog -Source 'CodeInjectionDetection' -Message ("CODE INJECTION: {0} | {1} (PID: {2})" -f $pat, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'code_injection_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobDataExfiltrationDetection {
$patterns = @('upload', 'exfil', 'pastebin', 'transfer.*http', 'webclient.*upload', 'ftp.*put', 'scp ', 'curl.*-T')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$c = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($pat in $patterns) { if ($c -match $pat) { Write-EdrLog -Source 'DataExfiltrationDetection' -Message ("Data exfiltration: {0} | {1} (PID: {2})" -f $pat, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'data_exfiltration_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobFileEntropyDetection {
foreach ($basePath in Get-SuspiciousScanPaths) {
if (-not (Test-Path -LiteralPath $basePath)) { continue }
try {
Get-ChildItem -LiteralPath $basePath -Filter '*.exe' -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
$e = Measure-FileEntropy -Path $_.FullName
$len = Get-FileLength -Path $_.FullName
if ($e -gt 7.5 -and $len -lt (5 * 1024 * 1024)) { Write-EdrLog -Source 'FileEntropyDetection' -Message ("High entropy: {0} | {1:N2}" -f $_.FullName, $e) -Level WARNING -LogFile 'file_entropy_detections.log' }
}
} catch { }
}
}
function Invoke-JobHoneypotMonitoring {
$path = Join-Path $script:InstallPath 'Data\honeypot'
try {
if (-not (Test-Path -LiteralPath $path)) { return }
$n = (Get-ChildItem -LiteralPath $path -File -ErrorAction SilentlyContinue).Count
if ($n -gt 0) { Write-EdrLog -Source 'HoneypotMonitoring' -Message "Honeypot files: $n" -Level INFO -LogFile 'honeypot.log' }
} catch { Write-EdrLog -Source 'HoneypotMonitoring' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'honeypot.log' }
}
function Invoke-JobLateralMovementDetection {
$patterns = @('psexec', 'wmic /node:', 'winrs ', 'sc \\\\', 'schtasks /s ', 'at \\\\', 'copy \\\\', 'net use')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$c = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($pat in $patterns) { if ($c -match $pat) { Write-EdrLog -Source 'LateralMovementDetection' -Message ("Lateral movement: {0} | {1} (PID: {2})" -f $pat, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'lateral_movement.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobProcessCreationDetection {
$procs = Get-ProcessesWmi
Write-EdrLog -Source 'ProcessCreationDetection' -Message ("Process count: {0}" -f $procs.Count) -Level INFO -LogFile 'process_creation_detections.log'
}
function Invoke-JobQuarantineManagement {
try {
if (-not (Test-Path -LiteralPath $script:QuarantinePath)) { return }
$n = (Get-ChildItem -LiteralPath $script:QuarantinePath -File -ErrorAction SilentlyContinue).Count
Write-EdrLog -Source 'QuarantineManagement' -Message "Quarantine count: $n" -Level INFO -LogFile 'quarantine_management.log'
} catch { Write-EdrLog -Source 'QuarantineManagement' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'quarantine_management.log' }
}
function Invoke-JobReflectiveDLLInjectionDetection {
$patterns = @('ReflectiveLoader', 'LoadLibraryR', 'LdrLoadDll', 'NtMapViewOfSection', 'VirtualAllocEx', 'WriteProcessMemory')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$c = (NullCoalesce $p.CommandLine)
foreach ($pat in $patterns) { if ($c -match $pat) { Write-EdrLog -Source 'ReflectiveDLLInjectionDetection' -Message ("Reflective DLL: {0} | {1} (PID: {2})" -f $pat, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'reflective_dll_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobSimpleAntivirus {
foreach ($path in Get-ElfDllsInBrowsers) {
try {
if (-not (Test-Path -LiteralPath $path)) { continue }
Remove-Item -LiteralPath $path -Force -ErrorAction Stop
Write-EdrLog -Source 'SimpleAntivirus' -Message "Removed ELF from browser: $path" -Level ACTION -LogFile 'simple_antivirus.log'
$script:ThreatCount++
} catch {
if (Move-QuarantineIfAllowed -Path $path -Reason 'ELF') { Write-EdrLog -Source 'SimpleAntivirus' -Message "ELF remove failed, quarantined: $path | $($_.Exception.Message)" -Level WARNING -LogFile 'simple_antivirus.log' }
}
}
$ext = @('.dll', '.winmd'); $maxUnsigned = 50; $unsignedCount = 0
foreach ($basePath in Get-SuspiciousScanPaths) {
if (-not (Test-Path -LiteralPath $basePath) -or $unsignedCount -ge $maxUnsigned) { break }
try {
foreach ($e in $ext) {
Get-ChildItem -LiteralPath $basePath -Filter "*$e" -File -ErrorAction SilentlyContinue | ForEach-Object {
if ($unsignedCount -ge $maxUnsigned) { return }
if (-not (Test-Path -LiteralPath $_.FullName)) { return }
if (Test-WhitelistedPath -Path $_.FullName) { return }
if (Move-QuarantineIfAllowed -Path $_.FullName -Reason 'SimpleAntivirus') { Write-EdrLog -Source 'SimpleAntivirus' -Message "Malicious (API): $($_.FullName)" -Level THREAT -LogFile 'simple_antivirus.log'; $script:ThreatCount++; $unsignedCount++ }
}
}
} catch { }
}
}
function Invoke-JobResponseEngine {
$ext = @('.exe', '.dll', '.sys', '.winmd'); $maxFiles = 100; $handled = 0
foreach ($basePath in Get-SuspiciousScanPaths) {
if ($handled -ge $maxFiles) { break }
if (-not (Test-Path -LiteralPath $basePath)) { continue }
try {
foreach ($e in $ext) {
Get-ChildItem -LiteralPath $basePath -Filter "*$e" -Recurse -File -ErrorAction SilentlyContinue | ForEach-Object {
if ($handled -ge $maxFiles) { return }
if (-not (Test-Path -LiteralPath $_.FullName)) { return }
if (Test-WhitelistedPath -Path $_.FullName) { return }
if (Move-QuarantineIfAllowed -Path $_.FullName -Reason 'ResponseEngine') { Write-EdrLog -Source 'ResponseEngine' -Message "CleanGuard Malicious -> quarantined $($_.FullName)" -Level THREAT -LogFile 'response_engine.log'; $script:ThreatCount++; $handled++ }
}
}
} catch { }
}
Write-EdrLog -Source 'ResponseEngine' -Message ("Tick | Threats: {0} | Terminated: {1} | Quarantined: {2} | Handled: {3}" -f $script:ThreatCount, $script:ProcessesTerminated, $script:FilesQuarantined, $handled) -Level INFO -LogFile 'response_engine.log'
}
function Invoke-JobPrivacyForgeSpoofing {
$systemNames = @('svchost.exe', 'lsass.exe', 'csrss.exe', 'smss.exe', 'winlogon.exe', 'services.exe', 'lsm.exe')
$self = $pid
try {
$procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$name = (NullCoalesce $p.Name)
$path = (NullCoalesce $p.ExecutablePath)
$isSystemNamed = $false
foreach ($sys in $systemNames) { if ($name -eq $sys) { $isSystemNamed = $true; break } }
if (-not $isSystemNamed) { continue }
if (-not $path) { Write-EdrLog -Source 'PrivacyForgeSpoofing' -Message "System-named process with no path: $name (PID: $($p.ProcessId))" -Level WARNING -LogFile 'privacy_forge.log'; continue }
$pathLower = $path.ToLower()
$fromSystem32 = $pathLower -match '\\windows\\system32\\'
$fromSysWOW64 = $pathLower -match '\\windows\\syswow64\\'
if (-not $fromSystem32 -and -not $fromSysWOW64) {
Write-EdrLog -Source 'PrivacyForgeSpoofing' -Message "SPOOFING: System binary not in System32/SysWOW64 | $name (PID: $($p.ProcessId)) | Path: $path" -Level THREAT -LogFile 'privacy_forge.log'
$script:ThreatCount++
}
$parent = Get-ParentProcess -Child $p -All $procs
if ($parent) {
$parentPath = (NullCoalesce $parent.ExecutablePath)
$parentName = (NullCoalesce $parent.Name)
if ($parentPath -and $parentName -match 'explorer|svchost') {
$parentLower = $parentPath.ToLower()
if ($parentLower -notmatch '\\windows\\' -and $parentLower -notmatch '\\program files') {
Write-EdrLog -Source 'PrivacyForgeSpoofing' -Message "SPOOFING: Suspicious parent path for $parentName | Child: $name (PID: $($p.ProcessId)) | Parent path: $parentPath" -Level THREAT -LogFile 'privacy_forge.log'
$script:ThreatCount++
}
}
}
}
Write-EdrLog -Source 'PrivacyForgeSpoofing' -Message "Spoofing check completed (system-named processes and parent paths)" -Level INFO -LogFile 'privacy_forge.log'
} catch { Write-EdrLog -Source 'PrivacyForgeSpoofing' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'privacy_forge.log' }
}
function Invoke-JobGFocus {
try {
$conns = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().GetActiveTcpConnections()
$est = ($conns | Where-Object { $_.State -eq [System.Net.NetworkInformation.TcpState]::Established }).Count
Write-EdrLog -Source 'GFocus' -Message "Established TCP connections: $est" -Level INFO -LogFile 'gfocus.log'
} catch { Write-EdrLog -Source 'GFocus' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'gfocus.log' }
}
function Invoke-JobMitreMapping {
$sourceToMitre = @{
'HashDetection' = @('T1204.002')
'LOLBinDetection' = @('T1218')
'ProcessAnomalyDetection' = @('T1059.001', 'T1047')
'AMSIBypassDetection' = @('T1562.001')
'CredentialDumpDetection' = @('T1003.001', 'T1003.002')
'RansomwareDetection' = @('T1486')
'RegistryPersistenceDetection' = @('T1547.001')
'ScheduledTaskDetection' = @('T1053.005')
'DLLHijackingDetection' = @('T1574.001')
'KeyloggerDetection' = @('T1056.001')
'NamedPipeMonitoring' = @('T1570')
'PrivacyForgeSpoofing' = @('T1036.005')
'IdsDetection' = @('T1059.001', 'T1047')
'WMIPersistenceDetection' = @('T1047')
'TokenManipulationDetection' = @('T1134')
'ProcessHollowingDetection' = @('T1055.012')
'FilelessDetection' = @('T1059.001')
'LateralMovementDetection' = @('T1021.002')
}
$techniquesSeen = @{}
try {
if (Test-Path -LiteralPath $script:LogPath) {
Get-ChildItem -LiteralPath $script:LogPath -Filter '*detections*.log' -ErrorAction SilentlyContinue | ForEach-Object {
Get-Content -LiteralPath $_.FullName -Tail 100 -ErrorAction SilentlyContinue | ForEach-Object {
if ($_ -match '\[THREAT\]\s*\[([^\]]+)\]') {
$src = $Matches[1]
if ($sourceToMitre.ContainsKey($src)) {
foreach ($t in $sourceToMitre[$src]) { $techniquesSeen[$t] = $true }
}
}
}
}
}
$techList = @($techniquesSeen.Keys) | Sort-Object
$msg = "ThreatCount: $($script:ThreatCount)"
if ($techList.Count -gt 0) { $msg += " | Techniques: $($techList -join ', ')" }
Write-EdrLog -Source 'MitreMapping' -Message $msg -Level INFO -LogFile 'mitre_detections.log'
} catch { Write-EdrLog -Source 'MitreMapping' -Message "Error: $($_.Exception.Message)" -Level ERROR -LogFile 'mitre_detections.log' }
}
function Invoke-JobIdsDetection {
$sigs = @('meterpreter', 'reverse_shell', 'bind_shell', 'exploit/', 'payload', 'cmd.exe /c', 'powershell -enc', 'rundll32 javascript:', 'mshta http', 'certutil -urlcache', 'bitsadmin /transfer', 'regsvr32 /s /n /u', 'Invoke-Mimikatz', 'sekurlsa::', ' Invoke-WebRequest ', 'Net.WebClient')
$self = $pid; $procs = Get-ProcessesWmi
foreach ($p in $procs) {
if ($p.ProcessId -eq $self) { continue }
$cmd = ((NullCoalesce $p.CommandLine)).ToLower()
foreach ($sig in $sigs) { if ($cmd -match $sig) { Write-EdrLog -Source 'IdsDetection' -Message ("IDS signature: {0} | {1} (PID: {2})" -f $sig, $p.Name, $p.ProcessId) -Level THREAT -LogFile 'ids_detections.log'; $script:ThreatCount++; Stop-ProcessIfAllowed -ProcessId $p.ProcessId -ProcessName $p.Name -ExePath $p.ExecutablePath; break } }
}
}
function Invoke-JobYaraDetection {
$baseDir = [System.IO.Path]::GetDirectoryName((Get-CurrentScriptPath))
$yaraExe = $null
if (Test-Path -LiteralPath (Join-Path $baseDir $script:YaraExeName)) { $yaraExe = Join-Path $baseDir $script:YaraExeName }
if (-not $yaraExe -and (Test-Path -LiteralPath (Join-Path (Join-Path $script:InstallPath $script:YaraSubFolder) $script:YaraExeName))) { $yaraExe = Join-Path (Join-Path $script:InstallPath $script:YaraSubFolder) $script:YaraExeName }
$rulesPath = $null
if (Test-Path -LiteralPath (Join-Path $baseDir $script:YaraRulesFileName)) { $rulesPath = Join-Path $baseDir $script:YaraRulesFileName }
if (-not $rulesPath -and (Test-Path -LiteralPath (Join-Path $script:DataPath $script:YaraRulesFileName))) { $rulesPath = Join-Path $script:DataPath $script:YaraRulesFileName }
if (-not $yaraExe -or -not $rulesPath) { Write-EdrLog -Source 'YaraDetection' -Message "YARA skipped: yara.exe or rules.yar not found." -Level INFO -LogFile 'yara_detections.log'; return }
$files = @()
foreach ($path in (Get-SuspiciousFiles)) {
if ($files.Count -ge 200) { break }
if (Test-WhitelistedPath -Path $path) { continue }
try { if ((Test-Path -LiteralPath $path) -and (Get-Item -LiteralPath $path).Length -gt 0 -and (Get-Item -LiteralPath $path).Length -lt 50MB) { $files += $path } } catch { }
}
if ($files.Count -eq 0) { Write-EdrLog -Source 'YaraDetection' -Message 'YARA scan: no files in scope.' -Level INFO -LogFile 'yara_detections.log'; return }
$batchSize = 40; $matches = 0; $yaraDir = [System.IO.Path]::GetDirectoryName($yaraExe)
$stdoutPath = Join-Path $script:LogPath 'yara_stdout.txt'; $stderrPath = Join-Path $script:LogPath 'yara_stderr.txt'
for ($i = 0; $i -lt $files.Count; $i += $batchSize) {
$batch = $files[$i..([Math]::Min($i + $batchSize - 1, $files.Count - 1))]
$yaraArgs = @("`"$rulesPath`"") + ($batch | ForEach-Object { "`"$_`"" })
try {
$proc = Start-Process -FilePath $yaraExe -ArgumentList $yaraArgs -WorkingDirectory $yaraDir -NoNewWindow -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath
$proc.WaitForExit(60000)
$stdout = Get-Content -LiteralPath $stdoutPath -ErrorAction SilentlyContinue
foreach ($line in $stdout) {
$trimmed = $line.Trim()
if (-not $trimmed) { continue }
if ($trimmed -match '^(\S+)\s+(.+)$') {
$ruleName = $Matches[1]; $filePath = $Matches[2].Trim()
Write-EdrLog -Source 'YaraDetection' -Message ("YARA match: rule=`"$ruleName`" file=`"$filePath`"") -Level THREAT -LogFile 'yara_detections.log'
$matches++
if (Move-QuarantineIfAllowed -Path $filePath -Reason "YARA:$ruleName") { $script:ThreatCount++ }
}
}
} catch { Write-EdrLog -Source 'YaraDetection' -Message "YARA run error: $($_.Exception.Message)" -Level ERROR -LogFile 'yara_detections.log' }
}
Write-EdrLog -Source 'YaraDetection' -Message ("YARA scan completed. Files in scope: $($files.Count), matches: $matches.") -Level $(if ($matches -gt 0) { 'THREAT' } else { 'INFO' }) -LogFile 'yara_detections.log'
}
# --- Job runner: each job is { Name, IntervalSeconds }; timer invokes Invoke-Job<Name> ---
$script:Jobs = @(
@{ Name = 'HashDetection'; IntervalSeconds = 15 }
@{ Name = 'LOLBinDetection'; IntervalSeconds = 60 }
@{ Name = 'ProcessAnomalyDetection'; IntervalSeconds = 30 }
@{ Name = 'AMSIBypassDetection'; IntervalSeconds = 60 }
@{ Name = 'CredentialDumpDetection'; IntervalSeconds = 45 }
@{ Name = 'CredentialProtection'; IntervalSeconds = 300 }
@{ Name = 'WMIPersistenceDetection'; IntervalSeconds = 60 }
@{ Name = 'ScheduledTaskDetection'; IntervalSeconds = 120 }
@{ Name = 'RegistryPersistenceDetection'; IntervalSeconds = 60 }
@{ Name = 'DLLHijackingDetection'; IntervalSeconds = 90 }
@{ Name = 'TokenManipulationDetection'; IntervalSeconds = 45 }
@{ Name = 'ProcessHollowingDetection'; IntervalSeconds = 30 }
@{ Name = 'KeyloggerDetection'; IntervalSeconds = 60 }
@{ Name = 'RansomwareDetection'; IntervalSeconds = 30 }
@{ Name = 'NetworkAnomalyDetection'; IntervalSeconds = 60 }
@{ Name = 'NetworkTrafficMonitoring'; IntervalSeconds = 45 }
@{ Name = 'RootkitDetection'; IntervalSeconds = 120 }
@{ Name = 'COMMonitoring'; IntervalSeconds = 60 }
@{ Name = 'ShadowCopyMonitoring'; IntervalSeconds = 90 }
@{ Name = 'USBMonitoring'; IntervalSeconds = 30 }
@{ Name = 'MobileDeviceMonitoring'; IntervalSeconds = 120 }
@{ Name = 'AttackToolsDetection'; IntervalSeconds = 60 }
@{ Name = 'AdvancedThreatDetection'; IntervalSeconds = 45 }
@{ Name = 'EventLogMonitoring'; IntervalSeconds = 60 }
@{ Name = 'FirewallRuleMonitoring'; IntervalSeconds = 90 }
@{ Name = 'ServiceMonitoring'; IntervalSeconds = 60 }
@{ Name = 'FilelessDetection'; IntervalSeconds = 60 }
@{ Name = 'MemoryScanning'; IntervalSeconds = 90 }
@{ Name = 'NamedPipeMonitoring'; IntervalSeconds = 45 }
@{ Name = 'DNSExfiltrationDetection'; IntervalSeconds = 60 }
@{ Name = 'BeaconDetection'; IntervalSeconds = 45 }
@{ Name = 'CodeInjectionDetection'; IntervalSeconds = 30 }
@{ Name = 'DataExfiltrationDetection'; IntervalSeconds = 60 }
@{ Name = 'FileEntropyDetection'; IntervalSeconds = 60 }
@{ Name = 'HoneypotMonitoring'; IntervalSeconds = 60 }
@{ Name = 'LateralMovementDetection'; IntervalSeconds = 60 }
@{ Name = 'ProcessCreationDetection'; IntervalSeconds = 30 }
@{ Name = 'QuarantineManagement'; IntervalSeconds = 120 }
@{ Name = 'ReflectiveDLLInjectionDetection'; IntervalSeconds = 45 }
@{ Name = 'SimpleAntivirus'; IntervalSeconds = 60 }
@{ Name = 'ResponseEngine'; IntervalSeconds = 30 }
@{ Name = 'PrivacyForgeSpoofing'; IntervalSeconds = 90 }
@{ Name = 'GFocus'; IntervalSeconds = 60 }
@{ Name = 'MitreMapping'; IntervalSeconds = 120 }
@{ Name = 'IdsDetection'; IntervalSeconds = 45 }
@{ Name = 'YaraDetection'; IntervalSeconds = 60 }
)
$script:JobTimers = @{}
$script:JobRunnerStopped = $false
function Start-JobRunner {
$script:JobRunnerStopped = $false
foreach ($j in $script:Jobs) {
$intervalMs = [Math]::Max(1, $j.IntervalSeconds) * 1000
$name = $j.Name
$timer = New-Object System.Timers.Timer $intervalMs
$timer.AutoReset = $true
Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
if ($script:JobRunnerStopped) { return }
$jobName = $Event.MessageData
try {
$fn = Get-Command -Name "Invoke-Job$jobName" -ErrorAction SilentlyContinue
if ($fn) { & $fn.Name } else { Write-EdrLog -Source $jobName -Message "$jobName tick" -Level INFO -LogFile "${jobName}.log" }
} catch {
Write-EdrLog -Source $jobName -Message "Error: $($_.Exception.Message)" -Level ERROR
}
} -MessageData $name | Out-Null
$timer.Start()
$script:JobTimers[$name] = $timer
}
Write-EdrLog -Source 'JobRunner' -Message "Started $($script:Jobs.Count) jobs."
}
function Stop-JobRunner {
$script:JobRunnerStopped = $true
foreach ($t in $script:JobTimers.Values) {
if ($t) { try { $t.Stop(); $t.Dispose() } catch { } }
}
$script:JobTimers.Clear()
}
# --- Main (no tray/dashboard; auto-install and persist unless -Uninstall) ---
if ($Uninstall) {
$err = Uninstall-Edr
if ($err) { Write-Warning $err; exit 1 }
Write-Host 'Uninstalled: persistence removed and install folder deleted.'
exit 0
}
# Auto-install and persist when running normally
if (-not (Test-EdrInstalled)) {
$err = Install-Edr
if ($err) { Write-Warning "Install failed: $err"; exit 1 }
Write-EdrLog -Source 'Main' -Message 'Auto-installed to ' + $script:InstallPath -Level INFO
}
if (-not (Test-EdrPersisted)) {
$err = Enable-EdrPersistence
if ($err) { Write-Warning "Persistence failed: $err" }
else { Write-EdrLog -Source 'Main' -Message 'Auto-persistence enabled (HKCU Run).' -Level INFO }
}
Start-JobRunner
Write-EdrLog -Source 'Main' -Message 'Antivirus started (no UI).' -Level INFO
# Keep process alive (job timers run in background)
try {
while ($true) { Start-Sleep -Seconds 3600 }
} finally {
Stop-JobRunner
}
Editor is loading...
Leave a Comment