Gorstaks Antivirus
unknown
powershell
3 months ago
346 kB
5
No Index
# Antivirus.ps1 - Single-file EDR (generated from current Bin logic)
# Author: Gorstak | Usage: .\Antivirus.ps1 | .\Antivirus.ps1 -RemoveRules
#Requires -RunAsAdministrator
param(
[Parameter(Mandatory=$false)][switch]$RemoveRules = $false,
[Parameter(Mandatory=$false)][string]$Module = $null
)
$script:ScriptRoot = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
# --- OptimizedConfig ---
# Optimized configuration for EDR modules
# Provides tick intervals, scan limits, batch settings, CPU throttling
#Requires -Version 5.1
$script:ModuleTickIntervals = @{
"HashDetection" = 90
"ResponseEngine" = 180
"MemoryScanning" = 90
"BeaconDetection" = 60
"NetworkTrafficMonitoring" = 45
"AMSIBypassDetection" = 90
"ProcessAnomalyDetection" = 90
"EventLogMonitoring" = 90
"FileEntropyDetection" = 120
"Initializer" = 300
"PrivacyForgeSpoofing" = 60
}
$script:ScanLimits = @{
"MaxFiles" = 500
"MaxProcesses" = 500
"MaxConnections" = 1000
"MaxEvents" = 500
"SampleSizeBytes" = 4096
}
function Get-TickInterval {
param([string]$ModuleName)
if ($script:ModuleTickIntervals.ContainsKey($ModuleName)) {
return $script:ModuleTickIntervals[$ModuleName]
}
return 90
}
function Get-ScanLimit {
param([string]$LimitName)
if ($script:ScanLimits.ContainsKey($LimitName)) {
return $script:ScanLimits[$LimitName]
}
return 500
}
function Get-BatchSettings {
return @{
BatchSize = 50
BatchDelayMs = 10
}
}
function Get-LoopSleep {
return 5
}
function Test-CPULoadThreshold {
try {
$cpu = Get-Counter '\Processor(_Total)\% Processor Time' -ErrorAction SilentlyContinue
if ($cpu -and $cpu.CounterSamples[0].CookedValue -gt 90) { return $true }
} catch { }
return $false
}
function Get-CPULoad {
try {
$cpu = Get-Counter '\Processor(_Total)\% Processor Time' -ErrorAction SilentlyContinue
if ($cpu) { return [int]$cpu.CounterSamples[0].CookedValue }
} catch { }
return 0
}
function Write-Log {
param(
[string]$Level,
[string]$Message,
[string]$Category = ""
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$output = "[$timestamp] [$Level] $Message"
if ($Category) {
$output = "[$timestamp] [$Level] [$Category] $Message"
}
Write-Output $output
}
# --- CacheManager ---
# Cache Manager Module
# Provides caching to reduce repeated expensive operations
#Requires -Version 5.1
$script:SignatureCache = @{}
$script:HashCache = @{}
$script:ProcessCache = @{}
$script:LastCacheClean = Get-Date
function Get-CachedSignature {
param([string]$FilePath)
$now = Get-Date
$ttl = 60 # minutes
if ($script:SignatureCache.ContainsKey($FilePath)) {
$cached = $script:SignatureCache[$FilePath]
if (($now - $cached.Timestamp).TotalMinutes -lt $ttl) {
return $cached.Value
}
}
try {
$sig = Get-AuthenticodeSignature -FilePath $FilePath -ErrorAction SilentlyContinue
$script:SignatureCache[$FilePath] = @{
Value = $sig
Timestamp = $now
}
return $sig
} catch {
return $null
}
}
function Get-CachedFileHash {
param(
[string]$FilePath,
[string]$Algorithm = "MD5"
)
$now = Get-Date
$ttl = 120 # minutes
$key = "$FilePath|$Algorithm"
if ($script:HashCache.ContainsKey($key)) {
$cached = $script:HashCache[$key]
$fileInfo = Get-Item $FilePath -ErrorAction SilentlyContinue
if ($fileInfo -and $cached.LastWrite -eq $fileInfo.LastWriteTime -and ($now - $cached.Timestamp).TotalMinutes -lt $ttl) {
return $cached.Value
}
}
try {
$fileInfo = Get-Item $FilePath -ErrorAction SilentlyContinue
if (-not $fileInfo) { return $null }
$hash = (Get-FileHash -Path $FilePath -Algorithm $Algorithm -ErrorAction SilentlyContinue).Hash
$script:HashCache[$key] = @{
Value = $hash
Timestamp = $now
LastWrite = $fileInfo.LastWriteTime
}
return $hash
} catch {
return $null
}
}
function Clear-ExpiredCache {
$now = Get-Date
if (($now - $script:LastCacheClean).TotalMinutes -lt 30) {
return
}
$script:LastCacheClean = $now
# Clean signature cache
$expiredSigs = $script:SignatureCache.Keys | Where-Object {
($now - $script:SignatureCache[$_].Timestamp).TotalMinutes -gt 60
}
foreach ($key in $expiredSigs) {
$script:SignatureCache.Remove($key)
}
# Clean hash cache
$expiredHashes = $script:HashCache.Keys | Where-Object {
($now - $script:HashCache[$_].Timestamp).TotalMinutes -gt 120
}
foreach ($key in $expiredHashes) {
$script:HashCache.Remove($key)
}
}
# --- Initializer ---
# Initializer Module
# Sets up the Antivirus EDR environment - runs once at startup - Optimized for low resource usage
$ModuleName = "Initializer"
$script:LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$Initialized = $false
function Invoke-Initialization {
try {
Write-Output "STATS:$ModuleName`:Starting environment initialization"
# Create required directories
$directories = @(
"$env:ProgramData\Antivirus",
"$env:ProgramData\Antivirus\Logs",
"$env:ProgramData\Antivirus\Data",
"$env:ProgramData\Antivirus\Modules",
"$env:ProgramData\Antivirus\Quarantine",
"$env:ProgramData\Antivirus\Reports"
)
foreach ($dir in $directories) {
if (-not (Test-Path $dir)) {
New-Item -Path $dir -ItemType Directory -Force | Out-Null
Write-Output "STATS:$ModuleName`:Created directory: $dir"
}
}
# Initialize log files with headers
$logFiles = @(
"$env:ProgramData\Antivirus\Logs\System_$(Get-Date -Format 'yyyy-MM-dd').log",
"$env:ProgramData\Antivirus\Logs\Threats_$(Get-Date -Format 'yyyy-MM-dd').log",
"$env:ProgramData\Antivirus\Logs\Responses_$(Get-Date -Format 'yyyy-MM-dd').log"
)
foreach ($logFile in $logFiles) {
if (-not (Test-Path $logFile)) {
$header = "# Antivirus EDR Log - Created $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`n# Format: Timestamp|Module|Action|Details`n"
Set-Content -Path $logFile -Value $header
Write-Output "STATS:$ModuleName`:Initialized log: $logFile"
}
}
# Create Event Log source if it doesn't exist
try {
if (-not [System.Diagnostics.EventLog]::SourceExists("AntivirusEDR")) {
[System.Diagnostics.EventLog]::CreateEventSource("AntivirusEDR", "Application")
Write-Output "STATS:$ModuleName`:Created Event Log source: AntivirusEDR"
}
} catch {
Write-Output "ERROR:$ModuleName`:Failed to create Event Log source: $_"
}
# Initialize configuration file
$configFile = "$env:ProgramData\Antivirus\Data\config.json"
if (-not (Test-Path $configFile)) {
$defaultConfig = @{
Version = "1.0"
Initialized = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
LastUpdate = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
Settings = @{
MaxLogSizeMB = 100
QuarantineRetentionDays = 30
EnableRealTimeResponse = $true
ResponseSeverity = "Medium"
}
}
$defaultConfig | ConvertTo-Json -Depth 3 | Set-Content -Path $configFile
Write-Output "STATS:$ModuleName`:Created configuration file"
}
# Create status tracking file
$statusFile = "$env:ProgramData\Antivirus\Data\agent_status.json"
if (-not (Test-Path $statusFile)) {
$statusTemplate = @{
LastCheck = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
ActiveAgents = @()
SystemHealth = "Healthy"
TotalDetections = 0
TotalResponses = 0
}
$statusTemplate | ConvertTo-Json -Depth 3 | Set-Content -Path $statusFile
Write-Output "STATS:$ModuleName`:Created status tracking file"
}
# Log initialization completion
$initLog = "$env:ProgramData\Antivirus\Logs\System_$(Get-Date -Format 'yyyy-MM-dd').log"
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|Initializer|Environment|Antivirus EDR environment initialized successfully" | Add-Content -Path $initLog
Write-Output "DETECTION:$ModuleName`:Environment initialization completed"
return 1
} catch {
Write-Output "ERROR:$ModuleName`:Initialization failed: $_"
return 0
}
}
function Start-Module {
$loopSleep = Get-LoopSleep
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high (only for maintenance, not init)
if ($Initialized -and (Test-CPULoadThreshold)) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping check"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
if (-not $Initialized) {
$count = Invoke-Initialization
if ($count -gt 0) {
$Initialized = $true
$TickInterval = Get-TickInterval -ModuleName $ModuleName # Use optimized interval
Write-Output "STATS:$ModuleName`:Initialization complete - switching to maintenance mode"
}
} else {
# Maintenance mode - just check system health
$statusFile = "$env:ProgramData\Antivirus\Data\agent_status.json"
if (Test-Path $statusFile) {
$status = Get-Content $statusFile | ConvertFrom-Json
$status.LastCheck = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
$status | ConvertTo-Json -Depth 3 | Set-Content -Path $statusFile
Write-Output "STATS:$ModuleName`:System health check completed"
} else {
Write-Output "STATS:$ModuleName`:Status file not found, system may need re-initialization"
}
}
$script:LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- HashDetection ---
# Optimized Hash-based Malware Detection Module
# Significantly reduced file I/O and CPU usage
$ModuleName = "HashDetection"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:ThreatHashes = @{}
$script:ScannedFiles = @{}
$script:Initialized = $false
function Initialize-HashDatabaseOptimized {
if ($script:Initialized) {
return
}
$threatPath = "$env:ProgramData\Antivirus\HashDatabase\threats.txt"
if (Test-Path $threatPath) {
Get-Content $threatPath -ErrorAction SilentlyContinue | ForEach-Object {
if ($_ -match '^([A-F0-9]{32,64})$') {
$script:ThreatHashes[$matches[1].ToUpper()] = $true
}
}
}
$script:Initialized = $true
}
function Invoke-HashScanOptimized {
$threatsFound = @()
$batchSettings = Get-BatchSettings
$maxFiles = Get-ScanLimit -LimitName "MaxFiles"
Initialize-HashDatabaseOptimized
$scanPaths = @("$env:APPDATA", "$env:LOCALAPPDATA\Temp", "$env:USERPROFILE\Downloads")
$scannedCount = 0
foreach ($scanPath in $scanPaths) {
if (-not (Test-Path $scanPath)) { continue }
if ($scannedCount -ge $maxFiles) { break }
try {
$cutoff = (Get-Date).AddHours(-1)
$files = Get-ChildItem -Path $scanPath -Include *.exe,*.dll -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt $cutoff } |
Select-Object -First ($maxFiles - $scannedCount)
$batchCount = 0
foreach ($file in $files) {
$scannedCount++
if ($script:ScannedFiles.ContainsKey($file.FullName)) {
$cached = $script:ScannedFiles[$file.FullName]
if ($cached.LastWrite -eq $file.LastWriteTime) {
continue
}
}
$batchCount++
if ($batchCount % $batchSettings.BatchSize -eq 0 -and $batchSettings.BatchDelayMs -gt 0) {
Start-Sleep -Milliseconds $batchSettings.BatchDelayMs
}
$hash = Get-CachedFileHash -FilePath $file.FullName -Algorithm "SHA256"
if (-not $hash) { continue }
# Mark as scanned
$script:ScannedFiles[$file.FullName] = @{
LastWrite = $file.LastWriteTime
Hash = $hash
}
# Check against threat database
if ($script:ThreatHashes.ContainsKey($hash.ToUpper())) {
$threatsFound += @{
File = $file.FullName
Hash = $hash
Threat = "Known Malware Hash"
}
}
}
} catch {
continue
}
}
if ($threatsFound.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\HashDetection_$(Get-Date -Format 'yyyy-MM-dd').log"
$threatsFound | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|THREAT|$($_.File)|$($_.Hash)" | Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($threatsFound.Count) hash-based threats"
}
Write-Output "STATS:$ModuleName`:Scanned=$scannedCount,Threats=$($threatsFound.Count)"
$now = Get-Date
$oldKeys = $script:ScannedFiles.Keys | Where-Object {
-not (Test-Path $_)
}
foreach ($key in $oldKeys) {
$script:ScannedFiles.Remove($key)
}
Clear-ExpiredCache
return $threatsFound.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Start-Sleep -Seconds (Get-Random -Minimum 10 -Maximum 60)
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-HashScanOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 60
}
}
}
# --- AMSIBypassDetection ---
# Detects AMSI bypass techniques (amsi.dll patching, etc.)
# Converted from GEDR C# job: JobAMSIBypassDetection
# Enhanced with full implementation from C# version
#Requires -Version 5.1
$ModuleName = "AMSIBypassDetection"
$script:Initialized = $false
# AMSI bypass patterns
$script:BypassPatterns = @(
"AmsiUtils",
"AmsiScanBuffer",
"amsiInitFailed",
"Bypass",
"amsi.dll",
"amsiutils",
"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",
"AmsiContext",
"AMSI_RESULT_CLEAN",
"ForceAmsi",
"Hacking",
"Context"
)
function Initialize-AMSIBypassDetection {
if ($script:Initialized) {
return
}
Write-Log "INFO" "Initializing AMSI Bypass Detection module"
$script:Initialized = $true
}
function Get-ProcessList {
# Get process list similar to GEDR's EdrProcess.GetProcesses
try {
$processes = Get-CimInstance -ClassName Win32_Process -ErrorAction SilentlyContinue |
Select-Object ProcessId, Name, CommandLine, ExecutablePath, ParentProcessId |
Where-Object { $_.ProcessId -ne $PID }
return $processes
}
catch {
Write-Log "ERROR" "Failed to get process list: $($_.Exception.Message)"
return @()
}
}
function Test-ScriptHostProcess {
param([string]$ProcessName)
if ([string]::IsNullOrEmpty($ProcessName)) {
return $false
}
$nameLower = $ProcessName.ToLowerInvariant()
return ($nameLower.Contains("powershell") -or
$nameLower.Contains("pwsh") -or
$nameLower.Contains("wscript") -or
$nameLower.Contains("cscript"))
}
function Test-AMSIBypassPattern {
param([string]$CommandLine)
if ([string]::IsNullOrEmpty($CommandLine)) {
return $false
}
$cmdLower = $CommandLine.ToLowerInvariant()
foreach ($pattern in $script:BypassPatterns) {
if ($cmdLower -match $pattern) {
return $true
}
}
return $false
}
function Test-ObfuscatedCommand {
param([string]$CommandLine)
if ([string]::IsNullOrEmpty($CommandLine)) {
return $false
}
$cmdLower = $CommandLine.ToLowerInvariant()
return ($cmdLower.Contains("-enc") -and
$cmdLower.Contains("-encodedcommand") -and
$CommandLine.Length -gt 500)
}
function Test-AMSIDisabledRegistry {
# Check if AMSI is disabled via registry
try {
# Check common AMSI bypass registry locations
$amsiPaths = @(
"HKLM:\SOFTWARE\Microsoft\AMSI",
"HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings",
"HKCU:\SOFTWARE\Microsoft\Windows Script Host\Settings"
)
foreach ($path in $amsiPaths) {
if (Test-Path $path) {
$properties = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue
if ($properties) {
# Check for common AMSI disable values
foreach ($prop in $properties.PSObject.Properties) {
if ($prop.Name -like "*amsi*" -or $prop.Name -like "*AMSI*") {
if ($prop.Value -eq 0 -or $prop.Value -eq "Disabled" -or $prop.Value -eq $false) {
return $true
}
}
}
}
}
}
return $false
}
catch {
Write-Log "ERROR" "Error checking AMSI registry: $($_.Exception.Message)"
return $false
}
}
function Invoke-ThreatResponse {
param(
[int]$ProcessId,
[string]$ProcessName,
[string]$ExecutablePath,
[string]$ThreatLevel
)
try {
# Log threat response
Write-Log "ACTION" "THREAT RESPONSE: Triggering response for $ProcessName (PID: $ProcessId) - Level: $ThreatLevel" -Category "threat_responses"
# Implement response actions based on threat level
switch ($ThreatLevel) {
"High" {
# For high threats, consider terminating process
if ($ProcessId -gt 0) {
try {
Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
Write-Log "ACTION" "THREAT RESPONSE: Terminated high-risk process $ProcessName (PID: $ProcessId)" -Category "threat_responses"
}
catch {
Write-Log "WARNING" "Failed to terminate process $ProcessName (PID: $ProcessId): $($_.Exception.Message)"
}
}
# Quarantine file if it exists
if ($ExecutablePath -and (Test-Path $ExecutablePath)) {
Invoke-QuarantineFile -FilePath $ExecutablePath -Reason "AMSI bypass detection"
}
}
"Critical" {
# For critical threats, always terminate and quarantine
if ($ProcessId -gt 0) {
try {
Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
Write-Log "ACTION" "THREAT RESPONSE: Terminated critical process $ProcessName (PID: $ProcessId)" -Category "threat_responses"
}
catch {
Write-Log "WARNING" "Failed to terminate process $ProcessName (PID: $ProcessId): $($_.Exception.Message)"
}
}
if ($ExecutablePath -and (Test-Path $ExecutablePath)) {
Invoke-QuarantineFile -FilePath $ExecutablePath -Reason "Critical AMSI bypass detection"
}
}
}
}
catch {
Write-Log "ERROR" "Error in threat response: $($_.Exception.Message)"
}
}
function Invoke-QuarantineFile {
param([string]$FilePath, [string]$Reason)
try {
$quarantinePath = "$env:ProgramData\Antivirus\Quarantine"
if (-not (Test-Path $quarantinePath)) {
New-Item -Path $quarantinePath -ItemType Directory -Force | Out-Null
}
$fileName = Split-Path $FilePath -Leaf
$quarantineFile = Join-Path $quarantinePath "$fileName-$([Guid]::NewGuid()).quar"
Move-Item -Path $FilePath -Destination $quarantineFile -Force
Write-Log "ACTION" "QUARANTINE: $FilePath moved to $quarantineFile (Reason: $Reason)" -Category "quarantine"
}
catch {
Write-Log "ERROR" "Failed to quarantine file $FilePath`: $($_.Exception.Message)"
}
}
function Invoke-AMSIBypassDetection {
try {
Initialize-AMSIBypassDetection
$script:ThreatCount = 0
$processes = Get-ProcessList
Write-Log "INFO" "Scanning $($processes.Count) processes for AMSI bypass patterns"
foreach ($process in $processes) {
$processName = if ($process.Name) { $process.Name } else { "" }
$cmdLine = if ($process.CommandLine) { $process.CommandLine } else { "" }
# Only check script host processes
if (-not (Test-ScriptHostProcess -ProcessName $processName)) {
continue
}
if ([string]::IsNullOrEmpty($cmdLine)) {
continue
}
# Check for AMSI bypass patterns
if (Test-AMSIBypassPattern -CommandLine $cmdLine) {
$cmdLower = $cmdLine.ToLowerInvariant()
$pattern = $script:BypassPatterns | Where-Object { $cmdLower -match $_ } | Select-Object -First 1
$dedupeKey = "AMSIBypass_$($process.ProcessId)_$($pattern)"
if (Test-Deduplication -Key $dedupeKey -Category "amsi_bypass") {
Write-Log "THREAT" "AMSI BYPASS: $($process.Name) (PID: $($process.ProcessId)) - Pattern: $pattern" -Category "amsi_bypass_detections"
$script:ThreatCount++
}
# Trigger threat response
Invoke-ThreatResponse -ProcessId $process.ProcessId -ProcessName $process.Name -ExecutablePath $process.ExecutablePath -ThreatLevel "High"
}
# Check for obfuscated commands
if (Test-ObfuscatedCommand -CommandLine $cmdLine) {
$dedupeKey = "AMSIBypass_$($process.ProcessId)_obfuscated"
if (Test-Deduplication -Key $dedupeKey -Category "amsi_bypass") {
Write-Log "THREAT" "AMSI BYPASS (obfuscated): $($process.Name) (PID: $($process.ProcessId)) - Long encoded command" -Category "amsi_bypass_detections"
$script:ThreatCount++
}
# Trigger critical threat response for obfuscated commands
Invoke-ThreatResponse -ProcessId $process.ProcessId -ProcessName $process.Name -ExecutablePath $process.ExecutablePath -ThreatLevel "Critical"
}
}
# Check registry for AMSI disable
if (Test-AMSIDisabledRegistry) {
$dedupeKey = "AMSIBypass_Registry"
if (Test-Deduplication -Key $dedupeKey -Category "amsi_bypass") {
Write-Log "THREAT" "AMSI BYPASS: Registry tampering detected - AMSI disabled via registry" -Category "amsi_bypass_detections"
$script:ThreatCount++
}
}
Write-Log "INFO" "AMSI bypass detection completed. Threats found: $script:ThreatCount"
}
catch {
Write-Log "ERROR" "Error in AMSIBypassDetection: $($_.Exception.Message)"
}
}
# Module exports - scheduler will call Invoke-AMSIBypassDetection on appropriate interval
# Alias for backward compatibility
function Invoke-AMSIBypassScan {
Invoke-AMSIBypassDetection
}
# --- GFocus ---
# GFocus.ps1 - Network traffic monitor + firewall rule cleanup
# Single script: monitor mode (default) or -RemoveRules to clear NTM_Block_* / BlockedConnection_*
# Monitors IPs; blocks or allows or removes block as the user surfs. Address bar is inferred from
# browser 80/443 connections (no extension): first 80/443 = navigation, within 30s = dependencies.
# Browsers only: games and other apps are never monitored or blocked. Block rules are
# browser-specific (program= + remoteip). DNS IPs (8.8.8.8, 1.1.1.1, etc.) are never blocked.
# Requires Administrator privileges
function Write-ColorOutput {
param([string]$Message, [string]$Color = "White")
Write-Host $Message -ForegroundColor $Color
}
# --- Remove-rules mode: clear NTM_Block_* and BlockedConnection_*, then exit ---
function Remove-BlockedRules {
Write-ColorOutput "Removing all blocked connection rules..." "Yellow"
$totalRemoved = 0
$blockedRules = Get-NetFirewallRule -DisplayName "BlockedConnection_*" -ErrorAction SilentlyContinue
if ($blockedRules) {
$count = ($blockedRules | Measure-Object).Count
Write-ColorOutput "Found $count BlockedConnection_* rule(s)." "Cyan"
foreach ($Rule in $blockedRules) {
Remove-NetFirewallRule -DisplayName $Rule.DisplayName -ErrorAction SilentlyContinue
Write-ColorOutput " Removed: $($Rule.DisplayName)" "Green"
$totalRemoved++
}
} else {
Write-ColorOutput "No BlockedConnection_* rules found." "Gray"
}
$out = netsh advfirewall firewall show rule name=all 2>&1 | Out-String
$ruleMatches = [regex]::Matches($out, 'Rule Name:\s*(NTM_Block_[^\s\r\n]+)')
$ntmList = @($ruleMatches | ForEach-Object { $_.Groups[1].Value.Trim() } | Sort-Object -Unique)
if ($ntmList.Count -gt 0) {
Write-ColorOutput "Found $($ntmList.Count) NTM_Block_* rule(s)." "Cyan"
foreach ($name in $ntmList) {
$del = netsh advfirewall firewall delete rule name="$name" 2>&1 | Out-String
if ($del -notmatch 'No rules match') {
Write-ColorOutput " Removed: $name" "Green"
$totalRemoved++
}
}
} else {
Write-ColorOutput "No NTM_Block_* rules found." "Gray"
}
if ($totalRemoved -gt 0) {
Write-ColorOutput "`nDone. Removed $totalRemoved rule(s) in total." "Green"
} else {
Write-ColorOutput "`nNo blocked connection rules to remove." "Gray"
}
}
# --- Monitor mode (NTM) ---
$script:AllowedDomains = @()
$script:AllowedIPs = @()
$script:BlockedConnections = @{}
$script:MonitoringActive = $true
$script:CurrentBrowserConnections = @{}
# Browsers only: monitoring and blocking apply solely to these processes.
$BrowserProcesses = @(
'chrome', 'firefox', 'msedge', 'iexplore', 'opera', 'brave', 'vivaldi', 'waterfox', 'palemoon',
'seamonkey', 'librewolf', 'tor', 'dragon', 'iridium', 'chromium', 'maxthon', 'slimjet', 'citrio',
'blisk', 'sidekick', 'epic', 'ghostery', 'falkon', 'kinza', 'orbitum', 'coowon', 'coc_coc_browser',
'browser', 'qqbrowser', 'ucbrowser', '360chrome', '360se', 'sleipnir', 'k-meleon', 'basilisk',
'floorp', 'pulse', 'naver', 'whale', 'coccoc', 'yandex', 'avastbrowser', 'asb', 'avgbrowser',
'ccleanerbrowser', 'dcbrowser', 'edge', 'edgedev', 'edgebeta', 'edgecanary', 'operagx', 'operaneon',
'bravesoftware', 'browsex', 'browsec', 'comet', 'elements', 'flashpeak', 'surf'
)
# Gaming (and all non-browser apps) are never monitored or blocked — explicitly unhindered.
$GamingProcesses = @(
'steam', 'steamwebhelper', 'epicgameslauncher', 'origin', 'battle.net', 'eadesktop', 'ea app',
'ubisoft game launcher', 'gog galaxy', 'rungame', 'gamebar', 'gameservices', 'overwolf'
)
# Never block these IPs (common DNS). Blocking them would break resolution for everyone.
$NeverBlockIPs = @('8.8.8.8', '8.8.4.4', '1.1.1.1', '1.0.0.1')
function Remove-BlockRulesForIP {
param([string]$RemoteAddress)
$safeName = $RemoteAddress -replace '\.', '_' -replace ':', '_'
$prefix = "NTM_Block_${safeName}_"
$out = netsh advfirewall firewall show rule name=all 2>&1 | Out-String
$ruleMatches = [regex]::Matches($out, 'Rule Name:\s*(NTM_Block_[^\s\r\n]+)')
foreach ($m in $ruleMatches) {
$name = $m.Groups[1].Value.Trim()
if ($name -like "${prefix}*") {
$del = netsh advfirewall firewall delete rule name="$name" 2>&1 | Out-String
if ($del -notmatch 'No rules match') {
Write-ColorOutput "REMOVED BLOCK (user surfed): $RemoteAddress -> $name" "Green"
}
}
}
$toRemove = @($script:BlockedConnections.Keys | Where-Object { $_ -like "${RemoteAddress}|*" })
foreach ($k in $toRemove) { $script:BlockedConnections.Remove($k) }
}
function Add-AllowedDomain {
param([string]$Domain)
$Domain = $Domain -replace '^https?://', '' -replace '/$', ''
$Domain = ($Domain -split '/')[0]
if ($Domain -match '^[\d\.]+$' -or $Domain -match '^[\da-f:]+$') {
if ($script:AllowedIPs -notcontains $Domain) {
$script:AllowedIPs += $Domain
Write-ColorOutput "Added allowed IP: $Domain" "Green"
Remove-BlockRulesForIP -RemoteAddress $Domain
}
return
}
if ($script:AllowedDomains -notcontains $Domain) {
$script:AllowedDomains += $Domain
Write-ColorOutput "Added allowed domain: $Domain" "Green"
try {
$IPs = [System.Net.Dns]::GetHostAddresses($Domain) | ForEach-Object { $_.IPAddressToString }
foreach ($IP in $IPs) {
if ($script:AllowedIPs -notcontains $IP) {
$script:AllowedIPs += $IP
Write-ColorOutput " Resolved IP: $IP" "Gray"
Remove-BlockRulesForIP -RemoteAddress $IP
}
}
} catch {
Write-ColorOutput " Warning: Could not resolve domain to IP" "Yellow"
}
}
}
function Test-BrowserConnection {
param([string]$RemoteAddress)
if ($RemoteAddress -match '^(127\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)') { return $true }
if ($script:AllowedIPs -contains $RemoteAddress) { return $true }
return $false
}
function Watch-BrowserActivity {
param([string]$RemoteAddress, [string]$ProcessName, [int]$RemotePort)
if ($BrowserProcesses -contains $ProcessName.ToLower()) {
$Now = Get-Date
$RecentNavigationTime = $null
foreach ($BrowserIP in $script:CurrentBrowserConnections.Keys) {
$ConnectionTime = $script:CurrentBrowserConnections[$BrowserIP]
$TimeDiff = ($Now - $ConnectionTime).TotalSeconds
if ($TimeDiff -le 30) {
if ($null -eq $RecentNavigationTime -or $ConnectionTime -gt $RecentNavigationTime) {
$RecentNavigationTime = $ConnectionTime
}
}
}
if ($null -ne $RecentNavigationTime) {
if ($script:AllowedIPs -notcontains $RemoteAddress) {
$script:AllowedIPs += $RemoteAddress
Write-ColorOutput "DEPENDENCY: Allowing $RemoteAddress (linked to browser navigation)" "Gray"
Remove-BlockRulesForIP -RemoteAddress $RemoteAddress
}
return $true
}
elseif ($RemotePort -eq 443 -or $RemotePort -eq 80) {
if ($script:AllowedIPs -notcontains $RemoteAddress) {
$script:AllowedIPs += $RemoteAddress
Write-ColorOutput "BROWSER NAVIGATION: Allowing $RemoteAddress and its dependencies" "Cyan"
Remove-BlockRulesForIP -RemoteAddress $RemoteAddress
}
$script:CurrentBrowserConnections[$RemoteAddress] = $Now
return $true
}
else {
if ($script:AllowedIPs -notcontains $RemoteAddress) {
$script:AllowedIPs += $RemoteAddress
Write-ColorOutput "BROWSER: Allowing $RemoteAddress" "DarkCyan"
Remove-BlockRulesForIP -RemoteAddress $RemoteAddress
}
return $true
}
}
$Now = Get-Date
foreach ($BrowserIP in $script:CurrentBrowserConnections.Keys) {
$ConnectionTime = $script:CurrentBrowserConnections[$BrowserIP]
$TimeDiff = ($Now - $ConnectionTime).TotalSeconds
if ($TimeDiff -le 30) {
if ($script:AllowedIPs -notcontains $RemoteAddress) {
$script:AllowedIPs += $RemoteAddress
Write-ColorOutput "DEPENDENCY: Allowing $RemoteAddress (linked to browser navigation)" "Gray"
Remove-BlockRulesForIP -RemoteAddress $RemoteAddress
}
return $true
}
}
return $false
}
function New-BlockRule {
param([string]$RemoteAddress, [int]$RemotePort, [string]$ProcessName, [string]$ProgramPath)
if ($RemoteAddress -in $NeverBlockIPs) { return }
$safeName = $RemoteAddress -replace '\.', '_' -replace ':', '_'
$procSafe = ($ProcessName -replace '\.exe$','').Trim().ToLower()
$ruleName = "NTM_Block_${safeName}_${procSafe}"
$key = "${RemoteAddress}|${ProcessName}"
if (-not $ProgramPath -or -not (Test-Path $ProgramPath)) {
Write-ColorOutput "Skip block (no program path): $RemoteAddress ($ProcessName)" "Yellow"
return
}
$progArg = "program=`"$ProgramPath`""
$out = netsh advfirewall firewall add rule name="$ruleName" dir=out action=block remoteip="$RemoteAddress" $progArg 2>&1 | Out-String
if ($out -match 'already exists') {
$script:BlockedConnections[$key] = @{ Port = $RemotePort; Process = $ProcessName }
return
}
if ($out -match 'Error|Failed|Unable') {
Write-ColorOutput "Failed to block $RemoteAddress for $ProcessName : $($out.Trim())" "Red"
return
}
$script:BlockedConnections[$key] = @{ Port = $RemotePort; Process = $ProcessName }
Write-ColorOutput "BLOCKED (browser only): $RemoteAddress`:$RemotePort ($ProcessName)" "Red"
}
function Start-ConnectionMonitoring {
Write-ColorOutput "" "Cyan"
Write-ColorOutput "=== GFocus / Network Traffic Monitor ===" "Cyan"
Write-ColorOutput "Browsers only: monitoring and blocking apply to browsers only." "Cyan"
Write-ColorOutput "Gaming and all other apps are unhindered (never monitored or blocked)." "Green"
Write-ColorOutput "Address bar inferred from browser 80/443 nav + 30s dependencies (no extension)." "Cyan"
Write-ColorOutput "Block/allow/remove block as user surfs. Press Ctrl+C to stop." "Yellow"
Write-ColorOutput "To clear block rules later: GFocus.ps1 -RemoveRules" "Gray"
Write-ColorOutput "" "Cyan"
$SeenConnections = @{}
while ($script:MonitoringActive) {
$Connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
Where-Object { $_.RemoteAddress -ne '0.0.0.0' -and $_.RemoteAddress -ne '::' }
foreach ($Conn in $Connections) {
$Key = "$($Conn.RemoteAddress):$($Conn.RemotePort):$($Conn.OwningProcess)"
if ($SeenConnections.ContainsKey($Key)) { continue }
$SeenConnections[$Key] = $true
try {
$Process = Get-Process -Id $Conn.OwningProcess -ErrorAction Stop
$ProcessName = $Process.ProcessName
$ProcessPath = $Process.Path
} catch { $Process = $null; $ProcessName = "Unknown"; $ProcessPath = $null }
$procName = ($ProcessName -replace '\.exe$','').Trim().ToLower()
if ($procName -notin $BrowserProcesses) {
continue
}
$IsBrowserOrDependency = Watch-BrowserActivity -RemoteAddress $Conn.RemoteAddress -ProcessName $ProcessName -RemotePort $Conn.RemotePort
if ($IsBrowserOrDependency) { continue }
if (-not (Test-BrowserConnection -RemoteAddress $Conn.RemoteAddress)) {
$blockKey = "$($Conn.RemoteAddress)|$ProcessName"
if (-not $script:BlockedConnections.ContainsKey($blockKey)) {
New-BlockRule -RemoteAddress $Conn.RemoteAddress -RemotePort $Conn.RemotePort -ProcessName $ProcessName -ProgramPath $ProcessPath
}
} else {
Write-ColorOutput "ALLOWED: $($Conn.RemoteAddress):$($Conn.RemotePort) (Process: $ProcessName)" "Green"
}
}
$Now = Get-Date
$ToRemove = @()
foreach ($IP in $script:CurrentBrowserConnections.Keys) {
if (($Now - $script:CurrentBrowserConnections[$IP]).TotalSeconds -gt 60) { $ToRemove += $IP }
}
foreach ($IP in $ToRemove) { $script:CurrentBrowserConnections.Remove($IP) }
Start-Sleep -Seconds 2
}
}
function Stop-Monitoring {
Write-ColorOutput "" "Cyan"
Write-ColorOutput "=== Stopping GFocus ===" "Cyan"
Write-ColorOutput "Blocked connections:" "Yellow"
if ($script:BlockedConnections.Count -eq 0) {
Write-ColorOutput " None." "Green"
} else {
foreach ($k in $script:BlockedConnections.Keys) {
$Info = $script:BlockedConnections[$k]
$ip = ($k -split '\|', 2)[0]
Write-ColorOutput " - ${ip}:$($Info.Port) - $($Info.Process) (browser-only rule)" "Red"
}
}
Write-ColorOutput "`nTo remove block rules: GFocus.ps1 -RemoveRules" "Gray"
}
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Stop-Monitoring }
# One tick for scheduler: process new browser connections (allow/block). Uses script-level seen cache.
if (-not $script:GFocusSeenConnections) { $script:GFocusSeenConnections = @{} }
function Invoke-GFocusTick {
$Connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
Where-Object { $_.RemoteAddress -ne '0.0.0.0' -and $_.RemoteAddress -ne '::' }
foreach ($Conn in $Connections) {
$Key = "$($Conn.RemoteAddress):$($Conn.RemotePort):$($Conn.OwningProcess)"
if ($script:GFocusSeenConnections.ContainsKey($Key)) { continue }
$script:GFocusSeenConnections[$Key] = $true
try {
$Process = Get-Process -Id $Conn.OwningProcess -ErrorAction Stop
$ProcessName = $Process.ProcessName
$ProcessPath = $Process.Path
} catch { $Process = $null; $ProcessName = "Unknown"; $ProcessPath = $null }
$procName = ($ProcessName -replace '\.exe$','').Trim().ToLower()
if ($procName -notin $BrowserProcesses) { continue }
$IsBrowserOrDependency = Watch-BrowserActivity -RemoteAddress $Conn.RemoteAddress -ProcessName $ProcessName -RemotePort $Conn.RemotePort
if ($IsBrowserOrDependency) { continue }
if (-not (Test-BrowserConnection -RemoteAddress $Conn.RemoteAddress)) {
$blockKey = "$($Conn.RemoteAddress)|$ProcessName"
if (-not $script:BlockedConnections.ContainsKey($blockKey)) {
New-BlockRule -RemoteAddress $Conn.RemoteAddress -RemotePort $Conn.RemotePort -ProcessName $ProcessName -ProgramPath $ProcessPath
}
}
}
$Now = Get-Date
$ToRemove = @($script:CurrentBrowserConnections.Keys | Where-Object { ($Now - $script:CurrentBrowserConnections[$_]).TotalSeconds -gt 60 })
foreach ($IP in $ToRemove) { $script:CurrentBrowserConnections.Remove($IP) }
}
# --- ResponseEngine ---
# Response Engine Module
# Centralized response system for all detection modules - Optimized for low resource usage
$ModuleName = "ResponseEngine"
$script:LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$ResponseQueue = @()
$ResponseActions = @{
"Critical" = @("Quarantine", "KillProcess", "BlockNetwork", "Log")
"High" = @("Quarantine", "Log", "Alert")
"Medium" = @("Log", "Alert")
"Low" = @("Log")
}
$ProcessedThreats = @{}
function Invoke-ResponseAction {
param(
[hashtable]$Detection,
[string]$Severity
)
$actions = $ResponseActions[$Severity]
if (-not $actions) {
$actions = @("Log")
}
$results = @()
foreach ($action in $actions) {
try {
switch ($action) {
"Quarantine" {
if ($Detection.FilePath -or $Detection.DllPath) {
$filePath = $Detection.FilePath -or $Detection.DllPath
if (Test-Path $filePath) {
# Import quarantine function if available
$quarantineModule = Get-Module -Name "QuarantineManagement" -ErrorAction SilentlyContinue
if (-not $quarantineModule) {
# Load quarantine module
$quarantinePath = Join-Path $PSScriptRoot "QuarantineManagement.ps1"
if (Test-Path $quarantinePath) {
. $quarantinePath
}
}
# Call quarantine function
if (Get-Command -Name "Invoke-QuarantineFile" -ErrorAction SilentlyContinue) {
Invoke-QuarantineFile -FilePath $filePath -Reason "Threat Detected: $($Detection.Type)" -Source $Detection.ModuleName
$results += "Quarantined: $filePath"
}
}
}
}
"KillProcess" {
if ($Detection.ProcessId) {
try {
$proc = Get-Process -Id $Detection.ProcessId -ErrorAction Stop
Stop-Process -Id $Detection.ProcessId -Force -ErrorAction Stop
$results += "Killed process: $($proc.ProcessName) (PID: $Detection.ProcessId)"
} catch {
$results += "Failed to kill process PID: $Detection.ProcessId"
}
}
}
"BlockNetwork" {
if ($Detection.RemoteAddress -or $Detection.RemotePort) {
try {
# Block network connection using firewall
$remoteIP = $Detection.RemoteAddress
$remotePort = $Detection.RemotePort
if ($remoteIP) {
$ruleName = "Block_Threat_$($remoteIP.Replace('.', '_'))"
$existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if (-not $existingRule) {
New-NetFirewallRule -DisplayName $ruleName -Direction Outbound -RemoteAddress $remoteIP -Action Block -ErrorAction SilentlyContinue | Out-Null
$results += "Blocked network to: $remoteIP"
}
}
} catch {
$results += "Failed to block network: $_"
}
}
}
"Alert" {
# Send alert (can be extended with email, SIEM, etc.)
$alertMsg = "ALERT: $($Detection.Type) - $($Detection.ProcessName -or $Detection.FilePath) - Severity: $Severity"
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2100 `
-Message $alertMsg
$results += "Alert sent: $alertMsg"
}
"Log" {
# Already logged, but add to response log
$logPath = "$env:ProgramData\Antivirus\Logs\ResponseEngine_$(Get-Date -Format 'yyyy-MM-dd').log"
$logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$Severity|$($Detection.Type)|$($Detection.ProcessName -or $Detection.FilePath)|$($Detection.ModuleName)"
Add-Content -Path $logPath -Value $logEntry -ErrorAction SilentlyContinue
$results += "Logged"
}
}
} catch {
$results += "Error in action $action`: $_"
}
}
return $results
}
function Invoke-ResponseEngine {
$responses = @()
try {
# Check all module detection logs for new threats
$logPath = "$env:ProgramData\Antivirus\Logs"
if (Test-Path $logPath) {
$today = Get-Date -Format 'yyyy-MM-dd'
$logFiles = Get-ChildItem -Path $logPath -Filter "*_$today.log" -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne "ResponseEngine_$today.log" -and $_.Name -ne "Antivirus_$today.log" }
foreach ($logFile in $logFiles) {
try {
$moduleName = $logFile.BaseName -replace "_$today", ""
$logEntries = Get-Content -Path $logFile.FullName -ErrorAction SilentlyContinue | Select-Object -Last 50
foreach ($entry in $logEntries) {
# Parse log entry (format: timestamp|type|risk|details)
if ($entry -match '\|') {
$parts = $entry -split '\|'
if ($parts.Length -ge 3) {
$timestamp = $parts[0]
$detectionType = $parts[1]
$risk = $parts[2]
$details = $parts[3..($parts.Length-1)] -join '|'
# Create detection hash
$detectionHash = ($moduleName + $timestamp + $detectionType + $details).GetHashCode()
# Skip if already processed
if ($ProcessedThreats.ContainsKey($detectionHash)) {
continue
}
# Determine severity from risk level
$severity = switch ($risk) {
"Critical" { "Critical" }
"High" { "High" }
"Medium" { "Medium" }
default { "Low" }
}
# Create detection object
$detection = @{
ModuleName = $moduleName
Timestamp = $timestamp
Type = $detectionType
Risk = $risk
Details = $details
Severity = $severity
}
# Extract ProcessId, FilePath, etc. from details
if ($details -match 'PID:(\d+)') {
$detection.ProcessId = [int]$matches[1]
}
if ($details -match '(.+\.exe|.+\.dll)') {
$detection.FilePath = $matches[1]
}
if ($details -match '(\d+\.\d+\.\d+\.\d+)') {
$detection.RemoteAddress = $matches[1]
}
# Execute response actions
$actionResults = Invoke-ResponseAction -Detection $detection -Severity $severity
# Mark as processed
$ProcessedThreats[$detectionHash] = Get-Date
$responses += @{
Detection = $detection
Actions = $actionResults
Timestamp = Get-Date
}
Write-Output "DETECTION:$ModuleName`:Processed $detectionType from $moduleName - Actions: $($actionResults -join ', ')"
}
}
}
} catch {
continue
}
}
}
# Cleanup old processed threats (older than 24 hours)
$oldKeys = $ProcessedThreats.Keys | Where-Object {
((Get-Date) - $ProcessedThreats[$_]).TotalHours -gt 24
}
foreach ($key in $oldKeys) {
$ProcessedThreats.Remove($key)
}
# Also check Event Log for detection events (2001-2100)
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Application'; Id=2001..2099} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object {
$_.Source -eq "AntivirusEDR" -and
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromMinutes(5)
}
foreach ($event in $events) {
$eventHash = ($event.Id.ToString() + $event.TimeCreated.ToString()).GetHashCode()
if (-not $ProcessedThreats.ContainsKey($eventHash)) {
# Parse event message for detection info
$message = $event.Message
$severity = if ($event.EntryType -eq "Error") { "Critical" }
elseif ($event.EntryType -eq "Warning") { "High" }
else { "Medium" }
$detection = @{
ModuleName = "EventLog"
Timestamp = $event.TimeCreated.ToString()
Type = $message
Severity = $severity
EventId = $event.Id
}
# Extract info from message
if ($message -match 'PID:\s*(\d+)') {
$detection.ProcessId = [int]$matches[1]
}
if ($message -match '(?:THREAT|DETECTED|FOUND):\s*(.+?)(?:\s*\||\s*-\s*|$)') {
$detection.Details = $matches[1]
}
# Execute response for critical/high severity
if ($severity -in @("Critical", "High")) {
$actionResults = Invoke-ResponseAction -Detection $detection -Severity $severity
$responses += @{
Detection = $detection
Actions = $actionResults
Timestamp = Get-Date
}
}
$ProcessedThreats[$eventHash] = Get-Date
}
}
} catch { }
if ($responses.Count -gt 0) {
Write-Output "STATS:$ModuleName`:Processed $($responses.Count) threats"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $responses.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high
if (Test-CPULoadThreshold) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping scan"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ResponseEngine
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- BeaconDetection ---
# Beacon Detection Module
# Detects C2 beaconing and command & control communication - Optimized for low resource usage
$ModuleName = "BeaconDetection"
$script:LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$ConnectionBaseline = @{}
function Initialize-BeaconBaseline {
try {
$maxConnections = Get-ScanLimit -LimitName "MaxConnections"
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" } | Select-Object -First $maxConnections
foreach ($conn in $connections) {
$key = "$($conn.RemoteAddress):$($conn.RemotePort)"
if (-not $ConnectionBaseline.ContainsKey($key)) {
$ConnectionBaseline[$key] = @{
Count = 0
FirstSeen = Get-Date
LastSeen = Get-Date
}
}
$ConnectionBaseline[$key].Count++
$ConnectionBaseline[$key].LastSeen = Get-Date
}
} catch { }
}
function Invoke-BeaconDetection {
$detections = @()
try {
# Monitor for periodic connections (beacon indicator)
$maxConnections = Get-ScanLimit -LimitName "MaxConnections"
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" } | Select-Object -First $maxConnections
# Group connections by process and remote address
$connGroups = $connections | Group-Object -Property @{Expression={$_.OwningProcess}}, @{Expression={$_.RemoteAddress}}
foreach ($group in $connGroups) {
$procId = $group.Name.Split(',')[0].Trim()
$remoteIP = $group.Name.Split(',')[1].Trim()
try {
$proc = Get-Process -Id $procId -ErrorAction SilentlyContinue
if (-not $proc) { continue }
# Check connection frequency (beacon pattern)
$connTimes = $group.Group | ForEach-Object { $_.CreationTime } | Sort-Object
if ($connTimes.Count -gt 3) {
# Calculate intervals between connections
$intervals = @()
for ($i = 1; $i -lt $connTimes.Count; $i++) {
$interval = ($connTimes[$i] - $connTimes[$i-1]).TotalSeconds
$intervals += $interval
}
# Check for regular intervals (beacon indicator)
if ($intervals.Count -gt 2) {
$avgInterval = ($intervals | Measure-Object -Average).Average
$variance = ($intervals | ForEach-Object { [Math]::Pow($_ - $avgInterval, 2) } | Measure-Object -Average).Average
$stdDev = [Math]::Sqrt($variance)
# Low variance = regular intervals = beacon
if ($stdDev -lt $avgInterval * 0.2 -and $avgInterval -gt 10 -and $avgInterval -lt 3600) {
$detections += @{
ProcessId = $procId
ProcessName = $proc.ProcessName
RemoteAddress = $remoteIP
ConnectionCount = $connTimes.Count
AverageInterval = [Math]::Round($avgInterval, 2)
Type = "Beacon Pattern Detected"
Risk = "High"
}
}
}
}
} catch {
continue
}
}
# Check for connections to suspicious TLDs
foreach ($conn in $connections) {
if ($conn.RemoteAddress -notmatch '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)') {
try {
$dns = [System.Net.Dns]::GetHostEntry($conn.RemoteAddress).HostName
$suspiciousTLDs = @(".onion", ".bit", ".i2p", ".tk", ".ml", ".ga", ".cf")
foreach ($tld in $suspiciousTLDs) {
if ($dns -like "*$tld") {
$detections += @{
ProcessId = $conn.OwningProcess
RemoteAddress = $conn.RemoteAddress
RemoteHost = $dns
Type = "Connection to Suspicious TLD"
Risk = "Medium"
}
break
}
}
} catch { }
}
}
# Check for HTTP/HTTPS connections with small data transfer (beacon)
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$procConns = $connections | Where-Object { $_.OwningProcess -eq $proc.Id }
$httpConns = $procConns | Where-Object { $_.RemotePort -in @(80, 443, 8080, 8443) }
if ($httpConns.Count -gt 0) {
# Check network stats
$netStats = Get-Counter "\Process($($proc.ProcessName))\IO Data Bytes/sec" -ErrorAction SilentlyContinue
if ($netStats -and $netStats.CounterSamples[0].CookedValue -lt 1000 -and $netStats.CounterSamples[0].CookedValue -gt 0) {
# Small but consistent data transfer = beacon
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
DataRate = $netStats.CounterSamples[0].CookedValue
ConnectionCount = $httpConns.Count
Type = "Low Data Transfer Beacon Pattern"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
} catch { }
# Check for processes with connections to many different IPs (C2 rotation)
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
$procConns = $connections | Where-Object { $_.OwningProcess -eq $proc.Id }
$uniqueIPs = ($procConns | Select-Object -Unique RemoteAddress).RemoteAddress.Count
if ($uniqueIPs -gt 10) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
UniqueIPs = $uniqueIPs
ConnectionCount = $procConns.Count
Type = "Multiple C2 Connections (IP Rotation)"
Risk = "High"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2037 `
-Message "BEACON DETECTED: $($detection.Type) - $($detection.ProcessName) (PID: $($detection.ProcessId)) - $($detection.RemoteAddress -or $detection.RemoteHost)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\BeaconDetection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|PID:$($_.ProcessId)|$($_.ProcessName)|$($_.RemoteAddress -or $_.RemoteHost)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) beacon indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Initialize-BeaconBaseline
Start-Sleep -Seconds (Get-Random -Minimum 30 -Maximum 90) # Longer initial delay
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high
if (Test-CPULoadThreshold) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping scan"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-BeaconDetection
$script:LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- NetworkTrafficMonitoring ---
# Optimized Network Traffic Monitoring Module
# Reduced polling and caching of connection state
$ModuleName = "NetworkTrafficMonitoring"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:ConnectionCache = @{}
$script:KnownGoodConnections = @{}
function Invoke-NetworkTrafficMonitoringOptimized {
$detections = @()
$maxConnections = Get-ScanLimit -LimitName "MaxConnections"
$batchSettings = Get-BatchSettings
try {
$tcpConnections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" } |
Select-Object -First $maxConnections
$batchCount = 0
foreach ($conn in $tcpConnections) {
$key = "$($conn.LocalAddress):$($conn.LocalPort)-$($conn.RemoteAddress):$($conn.RemotePort)"
if ($script:KnownGoodConnections.ContainsKey($key)) {
continue
}
$batchCount++
if ($batchCount % $batchSettings.BatchSize -eq 0 -and $batchSettings.BatchDelayMs -gt 0) {
Start-Sleep -Milliseconds $batchSettings.BatchDelayMs
}
# Check for suspicious patterns (simplified checks)
$isPrivate = $conn.RemoteAddress -match '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)'
if (-not $isPrivate) {
# Connection to public IP on ephemeral port
if ($conn.RemotePort -gt 49152) {
$detections += @{
RemoteAddress = $conn.RemoteAddress
RemotePort = $conn.RemotePort
Type = "Connection to Public Ephemeral Port"
Risk = "Low"
}
}
} else {
$script:KnownGoodConnections[$key] = $true
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\NetworkTraffic_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.RemoteAddress):$($_.RemotePort)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) traffic anomalies"
}
Write-Output "STATS:$ModuleName`:Active connections=$($tcpConnections.Count)"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Start-Sleep -Seconds (Get-Random -Minimum 30 -Maximum 90) # Longer initial delay
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high
if (Test-CPULoadThreshold) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping scan"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-NetworkTrafficMonitoringOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- ProcessAnomalyDetection ---
# Optimized Process Anomaly Detection Module
# Reduced resource usage with baseline caching
$ModuleName = "ProcessAnomalyDetection"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:BaselineProcesses = @{}
$script:KnownGoodProcesses = @{}
function Initialize-BaselineOptimized {
if ($script:BaselineProcesses.Count -gt 0) {
return
}
try {
$maxProcs = Get-ScanLimit -LimitName "MaxProcesses"
$processes = Get-Process -ErrorAction SilentlyContinue | Select-Object -First $maxProcs
foreach ($proc in $processes) {
$key = $proc.ProcessName
if (-not $script:BaselineProcesses.ContainsKey($key)) {
$script:BaselineProcesses[$key] = @{
Count = 0
FirstSeen = Get-Date
}
}
$script:BaselineProcesses[$key].Count++
}
} catch { }
}
function Test-ProcessAnomalyOptimized {
param($Process)
$anomalies = @()
if ($script:KnownGoodProcesses.ContainsKey($Process.ProcessName)) {
return $anomalies
}
if ($Process.Path) {
$systemPaths = @("$env:SystemRoot\System32", "$env:SystemRoot\SysWOW64")
foreach ($sysPath in $systemPaths) {
if ($Process.Path -like "$sysPath\*") {
try {
$sig = Get-CachedSignature -FilePath $Process.Path
if ($sig -and $sig.Status -ne "Valid") {
$anomalies += "Unsigned executable in system directory"
} elseif ($sig -and $sig.Status -eq "Valid") {
$script:KnownGoodProcesses[$Process.ProcessName] = $true
}
} catch { }
}
}
}
return $anomalies
}
function Invoke-ProcessAnomalyScanOptimized {
$detections = @()
$batchSettings = Get-BatchSettings
$maxProcs = Get-ScanLimit -LimitName "MaxProcesses"
try {
Initialize-BaselineOptimized
$processes = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.Path } |
Select-Object -First $maxProcs
$batchCount = 0
foreach ($proc in $processes) {
if ($script:KnownGoodProcesses.ContainsKey($proc.ProcessName)) {
continue
}
$batchCount++
if ($batchCount % $batchSettings.BatchSize -eq 0 -and $batchSettings.BatchDelayMs -gt 0) {
Start-Sleep -Milliseconds $batchSettings.BatchDelayMs
}
$anomalies = Test-ProcessAnomalyOptimized -Process $proc
if ($anomalies.Count -gt 0) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
Path = $proc.Path
Anomalies = $anomalies
Risk = "High"
}
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\ProcessAnomaly_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|PID:$($_.ProcessId)|$($_.ProcessName)|$($_.Anomalies -join ';')" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) process anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
Clear-ExpiredCache
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Start-Sleep -Seconds (Get-Random -Minimum 30 -Maximum 90) # Longer initial delay
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high
if (Test-CPULoadThreshold) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping scan"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ProcessAnomalyScanOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- EventLogMonitoring ---
# Optimized Event Log Monitoring Module
# Reduced Event Log query overhead
$ModuleName = "EventLogMonitoring"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:LastEventTime = @{}
function Invoke-EventLogMonitoringOptimized {
$detections = @()
$maxEvents = Get-ScanLimit -LimitName "MaxEvents"
try {
$lastCheck = if ($script:LastEventTime.ContainsKey('Security')) {
$script:LastEventTime['Security']
} else {
(Get-Date).AddMinutes(-$TickInterval / 60)
}
try {
$securityEvents = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
StartTime = $lastCheck
} -ErrorAction SilentlyContinue -MaxEvents $maxEvents
$script:LastEventTime['Security'] = Get-Date
# Check for failed logons
$failedLogons = $securityEvents | Where-Object { $_.Id -eq 4625 }
if ($failedLogons.Count -gt 10) {
$detections += @{
EventCount = $failedLogons.Count
Type = "Excessive Failed Logon Attempts"
Risk = "High"
}
}
# Check for privilege escalation
$privilegeEvents = $securityEvents | Where-Object { $_.Id -in @(4672, 4673, 4674) }
if ($privilegeEvents.Count -gt 0) {
$detections += @{
EventCount = $privilegeEvents.Count
Type = "Privilege Escalation Events"
Risk = "High"
}
}
# Check for log clearing
$logClearing = $securityEvents | Where-Object { $_.Id -eq 1102 }
if ($logClearing.Count -gt 0) {
$detections += @{
EventCount = $logClearing.Count
Type = "Event Log Cleared"
Risk = "Critical"
}
}
} catch { }
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\EventLogMonitoring_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|Count:$($_.EventCount)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) event log anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 20)
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-EventLogMonitoringOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 60
}
}
}
# --- FileEntropyDetection ---
# Optimized File Entropy Detection Module
# Reduced file I/O with smart sampling
$ModuleName = "FileEntropyDetection"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$HighEntropyThreshold = 7.2
$script:ScannedFiles = @{}
function Measure-FileEntropyOptimized {
param([string]$FilePath)
try {
if (-not (Test-Path $FilePath)) { return $null }
$fileInfo = Get-Item $FilePath -ErrorAction Stop
$sampleSize = Get-ScanLimit -LimitName "SampleSizeBytes"
$sampleSize = [Math]::Min($sampleSize, $fileInfo.Length)
if ($sampleSize -eq 0) { return $null }
$stream = [System.IO.File]::OpenRead($FilePath)
$bytes = New-Object byte[] $sampleSize
$stream.Read($bytes, 0, $sampleSize) | Out-Null
$stream.Close()
# Calculate byte frequency
$freq = @{}
foreach ($byte in $bytes) {
if ($freq.ContainsKey($byte)) {
$freq[$byte]++
} else {
$freq[$byte] = 1
}
}
# Calculate Shannon entropy
$entropy = 0
$total = $bytes.Count
foreach ($count in $freq.Values) {
$p = $count / $total
if ($p -gt 0) {
$entropy -= $p * [Math]::Log($p, 2)
}
}
return @{
Entropy = $entropy
FileSize = $fileInfo.Length
SampleSize = $sampleSize
}
} catch {
return $null
}
}
function Invoke-FileEntropyDetectionOptimized {
$detections = @()
$maxFiles = Get-ScanLimit -LimitName "MaxFiles"
$batchSettings = Get-BatchSettings
try {
$cutoff = (Get-Date).AddHours(-2)
$scanPaths = @("$env:APPDATA", "$env:LOCALAPPDATA\Temp", "$env:USERPROFILE\Downloads")
$scannedCount = 0
foreach ($scanPath in $scanPaths) {
if (-not (Test-Path $scanPath)) { continue }
if ($scannedCount -ge $maxFiles) { break }
try {
$files = Get-ChildItem -Path $scanPath -Include *.exe,*.dll,*.scr -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt $cutoff } |
Select-Object -First ($maxFiles - $scannedCount)
$batchCount = 0
foreach ($file in $files) {
$scannedCount++
if ($script:ScannedFiles.ContainsKey($file.FullName)) {
$cached = $script:ScannedFiles[$file.FullName]
if ($cached.LastWrite -eq $file.LastWriteTime) {
continue
}
}
$batchCount++
if ($batchCount % $batchSettings.BatchSize -eq 0 -and $batchSettings.BatchDelayMs -gt 0) {
Start-Sleep -Milliseconds $batchSettings.BatchDelayMs
}
$entropyResult = Measure-FileEntropyOptimized -FilePath $file.FullName
# Mark as scanned
$script:ScannedFiles[$file.FullName] = @{
LastWrite = $file.LastWriteTime
Entropy = if ($entropyResult) { $entropyResult.Entropy } else { 0 }
}
if ($entropyResult -and $entropyResult.Entropy -ge $HighEntropyThreshold) {
$detections += @{
FilePath = $file.FullName
FileName = $file.Name
Entropy = [Math]::Round($entropyResult.Entropy, 2)
Type = "High Entropy File"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\FileEntropy_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.FilePath)|Entropy:$($_.Entropy)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) high entropy files"
}
Write-Output "STATS:$ModuleName`:Scanned=$scannedCount"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
$toRemove = $script:ScannedFiles.Keys | Where-Object { -not (Test-Path $_) }
foreach ($key in $toRemove) {
$script:ScannedFiles.Remove($key)
}
Clear-ExpiredCache
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
Start-Sleep -Seconds (Get-Random -Minimum 30 -Maximum 90)
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-FileEntropyDetectionOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120
}
}
}
# --- YaraDetection ---
# YARA Detection
# Runs yara.exe against suspicious files (if present)
$ModuleName = "YaraDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 120 }
$YaraPaths = @("$env:ProgramFiles\Yara\yara64.exe", "$env:ProgramFiles (x86)\Yara\yara.exe", "yara.exe", "yara64.exe")
$RulesPaths = @("$env:ProgramData\Antivirus\Yara", "$env:ProgramData\Antivirus\Rules", "$PSScriptRoot\YaraRules")
$ScanPaths = @("$env:Temp", "$env:TEMP", "$env:SystemRoot\Temp")
function Get-YaraExe {
foreach ($p in $YaraPaths) {
if (Test-Path $p) { return $p }
}
return $null
}
function Get-RulesPath {
foreach ($p in $RulesPaths) {
if (Test-Path $p) {
$rules = Get-ChildItem -Path $p -Filter *.yar -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
if ($rules) { return $rules.Directory.FullName }
}
}
return $null
}
function Invoke-YaraScan {
$yara = Get-YaraExe
if (-not $yara) {
return 0
}
$rulesDir = Get-RulesPath
if (-not $rulesDir) {
return 0
}
$detections = @()
foreach ($base in $ScanPaths) {
if (-not (Test-Path $base)) { continue }
try {
$files = Get-ChildItem -Path $base -Include *.exe, *.dll, *.ps1 -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 100
foreach ($f in $files) {
try {
$out = & $yara -r "$rulesDir\*.yar" $f.FullName 2>&1
if ($out -and $out -match '\S') {
$detections += @{
File = $f.FullName
Match = ($out | Select-Object -First 5) -join "; "
}
}
} catch { }
}
} catch { }
}
if ($detections.Count -gt 0) {
foreach ($d in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2096 -Message "YARA: $($d.File) - $($d.Match)" -ErrorAction SilentlyContinue
}
$logPath = "$env:ProgramData\Antivirus\Logs\yara_detection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.File)|$($_.Match)" | Add-Content -Path $logPath }
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) YARA matches"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-YaraScan | Out-Null
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- WMIPersistenceDetection ---
# WMI Persistence Detection Module
# Detects WMI-based persistence mechanisms
$ModuleName = "WMIPersistenceDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-WMIPersistenceScan {
$detections = @()
try {
# Check WMI Event Consumers
$eventConsumers = Get-CimInstance -Namespace root\subscription -ClassName __EventConsumer -ErrorAction SilentlyContinue
foreach ($consumer in $eventConsumers) {
# Check for suspicious consumer types
if ($consumer.__CLASS -match 'ActiveScript|CommandLine') {
$suspicious = $false
$details = @{}
# Check CommandLineEventConsumer
if ($consumer.__CLASS -eq '__EventConsumer') {
$cmdLine = $consumer.CommandLineTemplate
if ($cmdLine) {
$details.CommandLine = $cmdLine
# Check for suspicious commands
if ($cmdLine -match 'powershell|cmd|certutil|bitsadmin|wmic' -or
$cmdLine -match 'http|https|ftp' -or
$cmdLine -match '-encodedcommand|-nop|-w.*hidden') {
$suspicious = $true
}
}
}
# Check ActiveScriptEventConsumer
if ($consumer.__CLASS -match 'ActiveScript') {
$script = $consumer.ScriptText
if ($script -and ($script.Length -gt 1000 -or
$script -match 'wscript|eval|exec|shell')) {
$suspicious = $true
$details.ScriptLength = $script.Length
}
}
if ($suspicious) {
$detections += @{
ConsumerName = $consumer.Name
ConsumerClass = $consumer.__CLASS
Details = $details
Risk = "High"
}
}
}
}
# Check WMI Event Filters
$eventFilters = Get-CimInstance -Namespace root\subscription -ClassName __EventFilter -ErrorAction SilentlyContinue
foreach ($filter in $eventFilters) {
$query = $filter.Query
if ($query) {
# Check for suspicious event filters
if ($query -match 'SELECT.*FROM.*__InstanceModificationEvent' -or
$query -match 'SELECT.*FROM.*Win32_ProcessStartTrace') {
$filterName = $filter.Name
# Check if filter is bound to suspicious consumer
$bindings = Get-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding -ErrorAction SilentlyContinue |
Where-Object { $_.Filter -like "*$filterName*" }
if ($bindings) {
$detections += @{
FilterName = $filterName
Query = $query
Type = "Event Filter Binding"
Risk = "Medium"
}
}
}
}
}
# Check for suspicious WMI namespaces
try {
$namespaces = Get-CimInstance -Namespace root -ClassName __Namespace -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match '^[a-f0-9]{32}$' }
foreach ($ns in $namespaces) {
$detections += @{
Namespace = $ns.Name
Type = "Suspicious WMI Namespace"
Risk = "High"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2006 `
-Message "WMI PERSISTENCE DETECTED: $($detection.ConsumerName -or $detection.FilterName -or $detection.Namespace) - $($detection.Type)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\WMIPersistence_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.ConsumerName -or $_.FilterName)|$($_.Type)|$($_.Risk)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) WMI persistence mechanisms"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-WMIPersistenceScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ScheduledTaskDetection ---
# Scheduled Task Detection Module
# Detects malicious scheduled tasks
$ModuleName = "ScheduledTaskDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-ScheduledTaskScan {
$detections = @()
try {
# Get all scheduled tasks
$tasks = Get-ScheduledTask -ErrorAction SilentlyContinue
foreach ($task in $tasks) {
$taskInfo = Get-ScheduledTaskInfo -TaskName $task.TaskName -ErrorAction SilentlyContinue
$taskActions = $task.Actions
$taskSettings = $task.Settings
$suspicious = $false
$reasons = @()
# Check task actions
foreach ($action in $taskActions) {
if ($action.Execute) {
$executeLower = $action.Execute.ToLower()
# Check for suspicious executables
if ($executeLower -match 'powershell|cmd|wscript|cscript|rundll32|mshta') {
if ($action.Arguments) {
$argsLower = $action.Arguments.ToLower()
# Check for suspicious arguments
if ($argsLower -match '-encodedcommand|-nop|-w.*hidden|-executionpolicy.*bypass' -or
$argsLower -match 'http|https|ftp' -or
$argsLower -match 'javascript:|\.hta|\.vbs') {
$suspicious = $true
$reasons += "Suspicious command line arguments"
}
}
# Check for tasks running as SYSTEM
if ($task.Principal.RunLevel -eq "Highest" -or
$task.Principal.UserId -eq "SYSTEM") {
$suspicious = $true
$reasons += "Runs as SYSTEM/High privilege"
}
}
}
}
# Check for hidden tasks
if ($taskSettings.Hidden) {
$suspicious = $true
$reasons += "Hidden task"
}
# Check for tasks that run when user is logged off
if ($taskSettings.RunOnlyIfNetworkAvailable -and
$taskSettings.StartWhenAvailable) {
$suspicious = $true
$reasons += "Runs when network available (exfiltration risk)"
}
# Check for tasks in suspicious locations
foreach ($action in $taskActions) {
if ($action.WorkingDirectory) {
$workDir = $action.WorkingDirectory
if ($workDir -match '\$env:|temp|appdata' -and
$workDir -notmatch '^[A-Z]:\\') {
$suspicious = $true
$reasons += "Suspicious working directory"
}
}
}
# Check for recently created tasks
$createdDate = $taskInfo | Select-Object -ExpandProperty 'CreationDate' -ErrorAction SilentlyContinue
if ($createdDate) {
$age = (Get-Date) - $createdDate
if ($age.TotalDays -lt 7) {
$suspicious = $true
$reasons += "Recently created (within 7 days)"
}
}
if ($suspicious) {
$detections += @{
TaskName = $task.TaskName
TaskPath = $task.TaskPath
Actions = $taskActions
Reasons = $reasons
State = $task.State
Risk = "High"
}
}
}
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2007 `
-Message "SUSPICIOUS TASK: $($detection.TaskName) - $($detection.Reasons -join ', ')"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ScheduledTask_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
$actionStr = ($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join ' | '
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.TaskName)|$($_.Reasons -join ';')|$actionStr" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) suspicious scheduled tasks"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ScheduledTaskScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- RegistryPersistenceDetection ---
# Registry Persistence Detection Module
# Detects malicious registry-based persistence
$ModuleName = "RegistryPersistenceDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
$PersistenceKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run",
"HKLM:\SYSTEM\CurrentControlSet\Services"
)
function Test-SuspiciousRegistryValue {
param([string]$Value)
if ([string]::IsNullOrEmpty($Value)) { return $false }
$valueLower = $Value.ToLower()
# Check for suspicious patterns
$suspiciousPatterns = @(
'powershell.*-encodedcommand',
'powershell.*-nop.*-w.*hidden',
'cmd.*\/c.*powershell',
'wscript.*http',
'cscript.*http',
'rundll32.*javascript',
'mshta.*http',
'certutil.*urlcache',
'bitsadmin.*transfer',
'regsvr32.*http',
'\.exe.*http',
'\.dll.*http'
)
foreach ($pattern in $suspiciousPatterns) {
if ($valueLower -match $pattern) {
return $true
}
}
# Check for suspicious file locations
if ($valueLower -match '\$env:' -and
($valueLower -match 'temp|appdata|local' -or
$valueLower -notmatch '^[A-Z]:\\')) {
return $true
}
# Check for unsigned executables
if ($valueLower -like '*.exe' -or $valueLower -like '*.dll') {
$filePath = $valueLower -replace '"', '' -split ' ' | Select-Object -First 1
if ($filePath -and (Test-Path $filePath)) {
try {
$sig = Get-AuthenticodeSignature -FilePath $filePath -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
return $true
}
} catch { }
}
}
return $false
}
function Invoke-RegistryPersistenceScan {
$detections = @()
try {
foreach ($regPath in $PersistenceKeys) {
if (-not (Test-Path $regPath)) { continue }
try {
$values = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue
if ($values) {
$valueProps = $values.PSObject.Properties | Where-Object {
$_.Name -notin @('PSPath','PSParentPath','PSChildName','PSDrive','PSProvider')
}
foreach ($prop in $valueProps) {
$regValue = $prop.Value
$regName = $prop.Name
if (Test-SuspiciousRegistryValue -Value $regValue) {
$detections += @{
RegistryPath = $regPath
ValueName = $regName
Value = $regValue
Risk = "High"
}
}
}
}
} catch { }
}
# Check for suspicious service entries
try {
$services = Get-CimInstance Win32_Service -ErrorAction SilentlyContinue |
Where-Object {
$_.PathName -match 'powershell|cmd|wscript|cscript|http' -or
$_.StartName -eq 'LocalSystem' -and $_.PathName -notmatch '^[A-Z]:\\Windows'
}
foreach ($svc in $services) {
if (Test-SuspiciousRegistryValue -Value $svc.PathName) {
$detections += @{
RegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$($svc.Name)"
ValueName = "ImagePath"
Value = $svc.PathName
ServiceName = $svc.Name
Risk = "Critical"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2008 `
-Message "REGISTRY PERSISTENCE: $($detection.RegistryPath)\$($detection.ValueName) - $($detection.Value)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\RegistryPersistence_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.RegistryPath)|$($_.ValueName)|$($_.Value)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) registry persistence mechanisms"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-RegistryPersistenceScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- DLLHijackingDetection ---
# DLL Hijacking Detection Module
# Detects DLL hijacking attempts
$ModuleName = "DLLHijackingDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Test-DLLHijacking {
param([string]$DllPath)
if (-not (Test-Path $DllPath)) { return $false }
# Check if DLL is in suspicious locations
$suspiciousPaths = @(
"$env:TEMP",
"$env:LOCALAPPDATA\Temp",
"$env:APPDATA",
"$env:USERPROFILE\Downloads",
"$env:USERPROFILE\Desktop"
)
foreach ($susPath in $suspiciousPaths) {
if ($DllPath -like "$susPath*") {
return $true
}
}
# Check if DLL is unsigned
try {
$sig = Get-AuthenticodeSignature -FilePath $DllPath -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
return $true
}
} catch { }
return $false
}
function Invoke-DLLHijackingScan {
$detections = @()
try {
# Check loaded DLLs in processes
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules | Where-Object { $_.FileName -like "*.dll" }
foreach ($module in $modules) {
if (Test-DLLHijacking -DllPath $module.FileName) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
DllPath = $module.FileName
DllName = $module.ModuleName
Risk = "High"
}
}
}
} catch {
# Access denied or process exited
continue
}
}
# Check for DLLs in application directories
$appPaths = @(
"$env:ProgramFiles",
"$env:ProgramFiles(x86)",
"$env:SystemRoot\System32",
"$env:SystemRoot\SysWOW64"
)
foreach ($appPath in $appPaths) {
if (-not (Test-Path $appPath)) { continue }
try {
$dlls = Get-ChildItem -Path $appPath -Filter "*.dll" -Recurse -ErrorAction SilentlyContinue |
Select-Object -First 100
foreach ($dll in $dlls) {
if ($dll.DirectoryName -ne "$appPath") {
# Check if DLL is signed
try {
$sig = Get-AuthenticodeSignature -FilePath $dll.FullName -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
$detections += @{
DllPath = $dll.FullName
Type = "Unsigned DLL in application directory"
Risk = "Medium"
}
}
} catch { }
}
}
} catch { }
}
# Check Event Log for DLL load failures
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'; Id=7} -ErrorAction SilentlyContinue -MaxEvents 100
foreach ($event in $events) {
if ($event.Message -match 'DLL.*not.*found|DLL.*load.*failed') {
$detections += @{
EventId = $event.Id
Message = $event.Message
TimeCreated = $event.TimeCreated
Type = "DLL Load Failure"
Risk = "Medium"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2009 `
-Message "DLL HIJACKING: $($detection.ProcessName -or $detection.Type) - $($detection.DllPath -or $detection.Message)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\DLLHijacking_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.ProcessName -or $_.Type)|$($_.DllPath -or $_.DllName)|$($_.Risk)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) DLL hijacking indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-DLLHijackingScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- TokenManipulationDetection ---
# Token Manipulation Detection Module
# Detects token theft and impersonation
$ModuleName = "TokenManipulationDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-TokenManipulationScan {
$detections = @()
try {
# Check for processes with unusual token privileges
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath, ParentProcessId
foreach ($proc in $processes) {
try {
$procObj = Get-Process -Id $proc.ProcessId -ErrorAction Stop
# Check for SeDebugPrivilege (enables token access)
try {
$token = Get-CimInstance Win32_LogicalDisk -ErrorAction SilentlyContinue
# Indirect check - processes accessing LSASS often have this
if ($proc.Name -eq "lsass") {
# Check for processes accessing LSASS
$accessingProcs = Get-CimInstance Win32_Process |
Where-Object { $_.ParentProcessId -eq $proc.ProcessId -and
$_.Name -notin @("svchost.exe", "dwm.exe") }
foreach ($accProc in $accessingProcs) {
$detections += @{
ProcessId = $accProc.ProcessId
ProcessName = $accProc.Name
Type = "LSASS Access - Possible Token Theft"
Risk = "Critical"
}
}
}
} catch { }
# Check for processes running as SYSTEM but not in Windows directory
if ($procObj.StartInfo.UserName -eq "SYSTEM" -or
$proc.Name -eq "SYSTEM") {
if ($proc.ExecutablePath -and
$proc.ExecutablePath -notlike "$env:SystemRoot\*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ExecutablePath = $proc.ExecutablePath
Type = "SYSTEM token on non-Windows executable"
Risk = "High"
}
}
}
} catch {
continue
}
}
# Check Security Event Log for token operations
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4672} -ErrorAction SilentlyContinue -MaxEvents 100
foreach ($event in $events) {
$xml = [xml]$event.ToXml()
$subjectUserName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text'
$targetUserName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TargetUserName'}).'#text'
# Check for unusual token impersonation
if ($subjectUserName -ne $targetUserName -and
$targetUserName -eq "SYSTEM") {
$detections += @{
EventId = $event.Id
SubjectUser = $subjectUserName
TargetUser = $targetUserName
Type = "Token Impersonation - SYSTEM"
TimeCreated = $event.TimeCreated
Risk = "High"
}
}
}
} catch { }
# Check for common token manipulation tools
$tokenTools = @("incognito", "mimikatz", "invoke-tokenmanipulation", "getsystem")
$runningProcs = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $runningProcs) {
foreach ($tool in $tokenTools) {
if ($proc.ProcessName -like "*$tool*" -or
$proc.Path -like "*$tool*") {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
ProcessPath = $proc.Path
Type = "Token Manipulation Tool"
Tool = $tool
Risk = "Critical"
}
}
}
}
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2010 `
-Message "TOKEN MANIPULATION: $($detection.ProcessName -or $detection.Type) - $($detection.Tool -or $detection.TargetUser)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\TokenManipulation_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.ProcessName -or $_.Type)|$($_.Risk)|$($_.Tool -or $_.TargetUser)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) token manipulation attempts"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-TokenManipulationScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ProcessHollowingDetection ---
# Process Hollowing Detection Module
# Detects process hollowing attacks
$ModuleName = "ProcessHollowingDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 20 }
function Invoke-ProcessHollowingScan {
$detections = @()
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath, CommandLine, ParentProcessId, CreationDate
foreach ($proc in $processes) {
try {
$procObj = Get-Process -Id $proc.ProcessId -ErrorAction Stop
$procPath = $procObj.Path
$imgPath = $proc.ExecutablePath
# Check for path mismatch (indicator of process hollowing)
if ($procPath -and $imgPath -and $procPath -ne $imgPath) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ProcessPath = $procPath
ImagePath = $imgPath
Type = "Path Mismatch - Process Hollowing"
Risk = "Critical"
}
}
# Check for processes with unusual parent relationships
if ($proc.ParentProcessId) {
try {
$parent = Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.ParentProcessId)" -ErrorAction Stop
# Check for processes spawned from non-standard parents
$suspiciousParents = @{
"explorer.exe" = @("notepad.exe", "calc.exe", "cmd.exe", "powershell.exe")
"winlogon.exe" = @("cmd.exe", "powershell.exe", "wmic.exe")
"services.exe" = @("cmd.exe", "powershell.exe", "rundll32.exe")
}
if ($suspiciousParents.ContainsKey($parent.Name)) {
if ($proc.Name -in $suspiciousParents[$parent.Name]) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ParentProcess = $parent.Name
Type = "Suspicious Parent-Child Relationship"
Risk = "High"
}
}
}
} catch { }
}
# Check for processes with suspended threads
try {
$threads = Get-CimInstance Win32_Thread -Filter "ProcessHandle=$($proc.ProcessId)" -ErrorAction SilentlyContinue
$suspendedThreads = $threads | Where-Object { $_.ThreadState -eq 5 } # Suspended
if ($suspendedThreads.Count -gt 0 -and $suspendedThreads.Count -eq $threads.Count) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
SuspendedThreads = $suspendedThreads.Count
Type = "All Threads Suspended - Process Hollowing"
Risk = "High"
}
}
} catch { }
# Check for processes with unusual memory regions
try {
$memoryRegions = Get-Process -Id $proc.ProcessId -ErrorAction Stop |
Select-Object -ExpandProperty Modules -ErrorAction SilentlyContinue
if ($memoryRegions) {
$unknownModules = $memoryRegions | Where-Object {
$_.FileName -notlike "$env:SystemRoot\*" -and
$_.FileName -notlike "$env:ProgramFiles*" -and
$_.ModuleName -notin @("kernel32.dll", "ntdll.dll", "user32.dll")
}
if ($unknownModules.Count -gt 5) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
UnknownModules = $unknownModules.Count
Type = "Unusual Memory Modules"
Risk = "Medium"
}
}
}
} catch { }
} catch {
continue
}
}
# Check for processes with unusual PE structure
try {
$suspiciousProcs = $processes | Where-Object {
$_.ExecutablePath -and
(Test-Path $_.ExecutablePath) -and
$_.ExecutablePath -notlike "$env:SystemRoot\*"
}
foreach ($proc in $suspiciousProcs) {
try {
$peInfo = Get-Item $proc.ExecutablePath -ErrorAction Stop
# Check if executable is signed
$sig = Get-AuthenticodeSignature -FilePath $proc.ExecutablePath -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
# Check if it's impersonating a legitimate process
$legitNames = @("svchost.exe", "explorer.exe", "notepad.exe", "calc.exe", "dwm.exe")
if ($proc.Name -in $legitNames) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ExecutablePath = $proc.ExecutablePath
Type = "Unsigned Executable Impersonating Legitimate Process"
Risk = "Critical"
}
}
}
} catch { }
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2011 `
-Message "PROCESS HOLLOWING: $($detection.ProcessName) (PID: $($detection.ProcessId)) - $($detection.Type)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ProcessHollowing_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|PID:$($_.ProcessId)|$($_.ProcessName)|$($_.Type)|$($_.Risk)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) process hollowing indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ProcessHollowingScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- KeyloggerDetection ---
# Keylogger Detection Module
# Detects keylogging activity
$ModuleName = "KeyloggerDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-KeyloggerScan {
$detections = @()
try {
# Check for known keylogger processes
$keyloggerNames = @("keylog", "keylogger", "keyspy", "keycapture", "keystroke", "keyhook", "keymon", "kl")
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
$procNameLower = $proc.ProcessName.ToLower()
foreach ($keylogName in $keyloggerNames) {
if ($procNameLower -like "*$keylogName*") {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
ProcessPath = $proc.Path
Type = "Known Keylogger Process"
Risk = "Critical"
}
break
}
}
}
# Check for processes with keyboard hooks
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath
foreach ($proc in $processes) {
try {
$procObj = Get-Process -Id $proc.ProcessId -ErrorAction Stop
# Check for SetWindowsHookEx usage (common in keyloggers)
$modules = $procObj.Modules | Where-Object {
$_.ModuleName -match "hook|keyboard|input"
}
if ($modules.Count -gt 0) {
# Check if process is signed
if ($proc.ExecutablePath -and (Test-Path $proc.ExecutablePath)) {
$sig = Get-AuthenticodeSignature -FilePath $proc.ExecutablePath -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ExecutablePath = $proc.ExecutablePath
HookModules = $modules.ModuleName -join ','
Type = "Unsigned Process with Keyboard Hooks"
Risk = "High"
}
}
}
}
} catch {
continue
}
}
} catch { }
# Check for processes accessing keyboard input devices
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$handles = Get-CimInstance Win32_ProcessHandle -Filter "ProcessId=$($proc.Id)" -ErrorAction SilentlyContinue
if ($handles) {
# Check for keyboard device access
$keyboardHandles = $handles | Where-Object {
$_.Name -match "keyboard|kbdclass|keybd"
}
if ($keyboardHandles.Count -gt 0) {
# Exclude legitimate processes
$legitProcesses = @("explorer.exe", "winlogon.exe", "csrss.exe")
if ($proc.ProcessName -notin $legitProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
KeyboardHandles = $keyboardHandles.Count
Type = "Direct Keyboard Device Access"
Risk = "High"
}
}
}
}
} catch {
continue
}
}
} catch { }
# Check for clipboard monitoring (often used with keyloggers)
try {
$clipboardProcs = Get-Process | Where-Object {
$_.Modules.ModuleName -like "*clipboard*" -or
$_.Path -like "*clipboard*"
}
foreach ($proc in $clipboardProcs) {
if ($proc.ProcessName -notin @("explorer.exe", "dwm.exe")) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
Type = "Clipboard Monitoring Process"
Risk = "Medium"
}
}
}
} catch { }
# Check Event Log for suspicious keyboard events
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Security'} -ErrorAction SilentlyContinue -MaxEvents 500 |
Where-Object { $_.Message -match 'keyboard|keystroke|hook' }
if ($events.Count -gt 10) {
$detections += @{
EventCount = $events.Count
Type = "Excessive Keyboard Events"
Risk = "Medium"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2012 `
-Message "KEYLOGGER DETECTED: $($detection.ProcessName -or $detection.Type) - $($detection.HookModules -or $detection.Type)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\Keylogger_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.ProcessName -or $_.Type)|$($_.Risk)|$($_.HookModules -or $_.KeyboardHandles)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) keylogger indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-KeyloggerScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ReflectiveDLLInjectionDetection ---
# Reflective DLL Injection Detection Module
# Detects reflective DLL injection and memory-only DLLs
$ModuleName = "ReflectiveDLLInjectionDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-ReflectiveDLLInjectionDetection {
$detections = @()
try {
# Check for processes with memory-only DLLs (reflective injection indicator)
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules
# Check for DLLs that don't exist on disk (reflective injection)
$memoryOnlyDlls = $modules | Where-Object {
$_.FileName -notlike "$env:SystemRoot\*" -and
$_.FileName -notlike "$env:ProgramFiles*" -and
-not (Test-Path $_.FileName)
}
if ($memoryOnlyDlls.Count -gt 0) {
foreach ($dll in $memoryOnlyDlls) {
# Exclude known legitimate cases
if ($dll.ModuleName -in @("kernel32.dll", "ntdll.dll", "user32.dll")) {
continue
}
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
DllName = $dll.ModuleName
BaseAddress = $dll.BaseAddress.ToString()
DllPath = $dll.FileName
Type = "Memory-Only DLL (Reflective Injection)"
Risk = "Critical"
}
}
}
# Check for unusual DLL base addresses (heap-based injection)
$unusualAddresses = $modules | Where-Object {
$addr = [Int64]$_.BaseAddress
# DLLs loaded at unusual addresses (not typical image base)
($addr -lt 0x400000 -or $addr -gt 0x7FFFFFFF0000) -and
$_.FileName -like "*.dll"
}
if ($unusualAddresses.Count -gt 3) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
UnusualAddressCount = $unusualAddresses.Count
Type = "DLLs at Unusual Memory Addresses"
Risk = "High"
}
}
# Check for processes with many unsigned DLLs in memory
$unsignedInMemory = 0
foreach ($mod in $modules) {
if ($mod.FileName -like "*.dll" -and (Test-Path $mod.FileName)) {
try {
$sig = Get-AuthenticodeSignature -FilePath $mod.FileName -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid" -and $mod.FileName -notlike "$env:SystemRoot\*") {
$unsignedInMemory++
}
} catch { }
}
}
if ($unsignedInMemory -gt 10) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
UnsignedDllCount = $unsignedInMemory
Type = "Many Unsigned DLLs in Memory"
Risk = "Medium"
}
}
} catch {
continue
}
}
# Check for processes using reflective loading APIs
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine
foreach ($proc in $processes) {
if ($proc.CommandLine) {
# Check for reflective loading patterns in command line
if ($proc.CommandLine -match 'VirtualAlloc|WriteProcessMemory|CreateRemoteThread|LoadLibrary|GetProcAddress' -or
$proc.CommandLine -match 'reflective|manual.*map|pe.*injection') {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Type = "Process Using Reflective Loading APIs"
Risk = "High"
}
}
}
}
} catch { }
# Check for hollowed processes (related to reflective injection)
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath
foreach ($proc in $processes) {
try {
$procObj = Get-Process -Id $proc.ProcessId -ErrorAction Stop
$procPath = $procObj.Path
$imgPath = $proc.ExecutablePath
# Check for path mismatch (process hollowing often uses reflective injection)
if ($procPath -and $imgPath -and $procPath -ne $imgPath) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ProcessPath = $procPath
ImagePath = $imgPath
Type = "Process Hollowing with Reflective Injection"
Risk = "Critical"
}
}
} catch {
continue
}
}
} catch { }
# Check Event Log for DLL load failures (may indicate injection attempts)
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'; Id=7} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(1) -and
$_.Message -match 'DLL.*not.*found|DLL.*load.*failed|reflective'
}
if ($events.Count -gt 10) {
$detections += @{
EventCount = $events.Count
Type = "Excessive DLL Load Failures (Possible Injection Attempts)"
Risk = "Medium"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2036 `
-Message "REFLECTIVE DLL INJECTION: $($detection.Type) - $($detection.ProcessName) (PID: $($detection.ProcessId))"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ReflectiveDLL_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|PID:$($_.ProcessId)|$($_.ProcessName)|$($_.DllName -or $_.BaseAddress)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) reflective DLL injection indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ReflectiveDLLInjectionDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- RansomwareDetection ---
# Ransomware Detection Module
# Detects ransomware behavior patterns and ransom notes
#Requires -Version 5.1
# Converted from GEDR C# job: JobRansomwareDetection
# Enhanced with full implementation from C# version
$ModuleName = "RansomwareDetection"
$LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:Initialized = $false
# Ransomware command-line patterns
$script:RansomwarePatterns = @(
"vssadmin delete shadows",
"vssadmin.exe delete",
"wbadmin delete catalog",
"bcdedit",
"shadow copy",
"shadowcopy",
"cryptolocker",
"wannacry",
".encrypted",
".locked",
".crypto"
)
# Ransom note file names
$script:RansomNoteNames = @(
"readme.txt",
"decrypt.txt",
"how_to_decrypt.txt",
"recover.txt",
"restore.txt",
"!!!readme!!!.txt",
"readme_to_decrypt.txt",
"decrypt_instruction.txt"
)
function Initialize-RansomwareDetection {
if ($script:Initialized) {
return
}
Write-Log "INFO" "Initializing Ransomware Detection module"
$script:Initialized = $true
}
function Get-ProcessList {
# Get process list similar to GEDR's EdrProcess.GetProcesses
try {
$processes = Get-CimInstance -ClassName Win32_Process -ErrorAction SilentlyContinue |
Select-Object ProcessId, Name, CommandLine, ExecutablePath, ParentProcessId |
Where-Object { $_.ProcessId -ne $PID }
return $processes
}
catch {
Write-Log "ERROR" "Failed to get process list: $($_.Exception.Message)"
return @()
}
}
function Test-RansomwareCommand {
param([string]$CommandLine)
if ([string]::IsNullOrEmpty($CommandLine)) {
return $false
}
$cmdLower = $CommandLine.ToLowerInvariant()
foreach ($pattern in $script:RansomwarePatterns) {
if ($cmdLower.Contains($pattern.ToLowerInvariant())) {
return $true
}
}
return $false
}
function Find-RansomNotes {
# Check for ransom notes in user directories
try {
$userProfile = $env:USERPROFILE
if ([string]::IsNullOrEmpty($userProfile)) {
return
}
$directories = @(
Join-Path $userProfile "Documents",
Join-Path $userProfile "Desktop",
Join-Path $userProfile "Pictures"
)
foreach ($directory in $directories) {
if (-not (Test-Path $directory)) {
continue
}
foreach ($noteName in $script:RansomNoteNames) {
$fullPath = Join-Path $directory $noteName
if (Test-Path $fullPath) {
$dedupeKey = "Ransomware_Note_$($fullPath)"
if (Test-Deduplication -Key $dedupeKey -Category "ransomware") {
Write-Log "THREAT" "RANSOMWARE: Ransom note detected: $fullPath" -Category "ransomware_detections"
$script:ThreatCount++
# Trigger response
Invoke-ThreatResponse -ProcessId 0 -ProcessName "RansomNote" -ExecutablePath $fullPath -ThreatLevel "Critical"
}
}
}
}
}
catch {
Write-Log "ERROR" "Error checking for ransom notes: $($_.Exception.Message)"
}
}
function Test-ShadowCopyDeletion {
# Check if shadow copies exist (ransomware often deletes them)
try {
$shadowCopies = Get-CimInstance -ClassName Win32_ShadowCopy -ErrorAction SilentlyContinue
$count = if ($shadowCopies) { $shadowCopies.Count } else { 0 }
if ($count -eq 0) {
$dedupeKey = "Ransomware_ShadowCopyZero"
if (Test-Deduplication -Key $dedupeKey -Category "ransomware") {
Write-Log "THREAT" "RANSOMWARE: No shadow copies present (possible ransomware deletion)" -Category "ransomware_detections"
$script:ThreatCount++
}
}
}
catch {
Write-Log "ERROR" "Error checking shadow copies: $($_.Exception.Message)"
}
}
function Invoke-ThreatResponse {
param(
[int]$ProcessId,
[string]$ProcessName,
[string]$ExecutablePath,
[string]$ThreatLevel
)
try {
# Log threat response
Write-Log "ACTION" "THREAT RESPONSE: Triggering response for $ProcessName (PID: $ProcessId) - Level: $ThreatLevel" -Category "threat_responses"
# Implement response actions based on threat level
switch ($ThreatLevel) {
"Critical" {
# For critical threats, consider terminating process
if ($ProcessId -gt 0) {
try {
Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue
Write-Log "ACTION" "THREAT RESPONSE: Terminated critical process $ProcessName (PID: $ProcessId)" -Category "threat_responses"
}
catch {
Write-Log "WARNING" "Failed to terminate process $ProcessName (PID: $ProcessId): $($_.Exception.Message)"
}
}
# Quarantine file if it exists
if ($ExecutablePath -and (Test-Path $ExecutablePath)) {
Invoke-QuarantineFile -FilePath $ExecutablePath -Reason "Ransomware detection"
}
}
}
}
catch {
Write-Log "ERROR" "Error in threat response: $($_.Exception.Message)"
}
}
function Invoke-QuarantineFile {
param([string]$FilePath, [string]$Reason)
try {
$quarantinePath = "$env:ProgramData\Antivirus\Quarantine"
if (-not (Test-Path $quarantinePath)) {
New-Item -Path $quarantinePath -ItemType Directory -Force | Out-Null
}
$fileName = Split-Path $FilePath -Leaf
$quarantineFile = Join-Path $quarantinePath "$fileName-$([Guid]::NewGuid()).quar"
Move-Item -Path $FilePath -Destination $quarantineFile -Force
Write-Log "ACTION" "QUARANTINE: $FilePath moved to $quarantineFile (Reason: $Reason)" -Category "quarantine"
}
catch {
Write-Log "ERROR" "Failed to quarantine file $FilePath`: $($_.Exception.Message)"
}
}
function Invoke-RansomwareDetection {
try {
Initialize-RansomwareDetection
$script:ThreatCount = 0
$processes = Get-ProcessList
Write-Log "INFO" "Scanning $($processes.Count) processes for ransomware patterns"
foreach ($process in $processes) {
$cmdLine = if ($process.CommandLine) { $process.CommandLine } else { "" }
if (Test-RansomwareCommand -CommandLine $cmdLine) {
$pattern = $script:RansomwarePatterns | Where-Object { $cmdLine.ToLowerInvariant().Contains($_.ToLowerInvariant()) } | Select-Object -First 1
$dedupeKey = "Ransomware_$($process.ProcessId)_$($pattern)"
if (Test-Deduplication -Key $dedupeKey -Category "ransomware") {
Write-Log "THREAT" "RANSOMWARE: $($process.Name) (PID: $($process.ProcessId)) | Pattern: $pattern" -Category "ransomware_detections"
$script:ThreatCount++
}
# Trigger threat response
Invoke-ThreatResponse -ProcessId $process.ProcessId -ProcessName $process.Name -ExecutablePath $process.ExecutablePath -ThreatLevel "Critical"
}
}
# Check for ransom notes
Find-RansomNotes
# Check shadow copy status
Test-ShadowCopyDeletion
Write-Log "INFO" "Ransomware detection completed. Threats found: $script:ThreatCount"
}
catch {
Write-Log "ERROR" "Error in RansomwareDetection: $($_.Exception.Message)"
}
}
# Module exports - scheduler will call Invoke-RansomwareDetection on appropriate interval
# --- NetworkAnomalyDetection ---
# Network Anomaly Detection Module
# Detects unusual network activity
$ModuleName = "NetworkAnomalyDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
$BaselineConnections = @{}
function Initialize-NetworkBaseline {
try {
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" }
foreach ($conn in $connections) {
$key = "$($conn.LocalAddress):$($conn.LocalPort)-$($conn.RemoteAddress):$($conn.RemotePort)"
if (-not $BaselineConnections.ContainsKey($key)) {
$BaselineConnections[$key] = @{
Count = 0
FirstSeen = Get-Date
}
}
$BaselineConnections[$key].Count++
}
} catch { }
}
function Invoke-NetworkAnomalyScan {
$detections = @()
try {
# Get current network connections
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" }
# Check for unusual destinations
$suspiciousIPs = @()
$suspiciousPorts = @(4444, 5555, 6666, 7777, 8888, 9999, 1337, 31337, 8080, 8443)
foreach ($conn in $connections) {
# Check for suspicious ports
if ($conn.RemotePort -in $suspiciousPorts) {
$detections += @{
LocalAddress = $conn.LocalAddress
LocalPort = $conn.LocalPort
RemoteAddress = $conn.RemoteAddress
RemotePort = $conn.RemotePort
State = $conn.State
Type = "Suspicious Port"
Risk = "High"
}
}
# Check for connections to known bad IPs
if ($conn.RemoteAddress -match '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)') {
# Private IP - check if it's unusual
$key = "$($conn.RemoteAddress):$($conn.RemotePort)"
if (-not $BaselineConnections.ContainsKey($key)) {
$detections += @{
LocalAddress = $conn.LocalAddress
LocalPort = $conn.LocalPort
RemoteAddress = $conn.RemoteAddress
RemotePort = $conn.RemotePort
Type = "New Connection to Private IP"
Risk = "Medium"
}
}
}
}
# Check for processes with unusual network activity
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath
foreach ($proc in $processes) {
try {
$procConnections = $connections | Where-Object {
$owner = (Get-NetTCPConnection -OwningProcess $proc.ProcessId -ErrorAction SilentlyContinue)
$owner.Count -gt 0
}
if ($procConnections.Count -gt 50) {
# High number of connections
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ConnectionCount = $procConnections.Count
Type = "High Network Activity"
Risk = "Medium"
}
}
} catch {
continue
}
}
} catch { }
# Check for DNS queries to suspicious domains
try {
$dnsQueries = Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-DNS-Client/Operational'; Id=3008} -ErrorAction SilentlyContinue -MaxEvents 100
$suspiciousDomains = @(".onion", ".bit", ".i2p", "pastebin.com", "githubusercontent.com")
foreach ($event in $dnsQueries) {
$message = $event.Message
foreach ($domain in $suspiciousDomains) {
if ($message -like "*$domain*") {
$detections += @{
EventId = $event.Id
Message = $message
Type = "Suspicious DNS Query"
Domain = $domain
Risk = "Medium"
}
}
}
}
} catch { }
# Check for unusual data transfer
try {
$netStats = Get-NetAdapterStatistics -ErrorAction SilentlyContinue
foreach ($adapter in $netStats) {
if ($adapter.SentBytes -gt 1GB -or $adapter.ReceivedBytes -gt 1GB) {
# High data transfer
$timeSpan = (Get-Date) - $LastTick
if ($timeSpan.TotalSeconds -gt 0) {
$bytesPerSec = $adapter.SentBytes / $timeSpan.TotalSeconds
if ($bytesPerSec -gt 10MB) {
$detections += @{
Adapter = $adapter.Name
SentBytes = $adapter.SentBytes
ReceivedBytes = $adapter.ReceivedBytes
Type = "High Data Transfer Rate"
Risk = "Medium"
}
}
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2015 `
-Message "NETWORK ANOMALY: $($detection.Type) - $($detection.ProcessName -or $detection.RemoteAddress -or $detection.Adapter)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\NetworkAnomaly_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.RemoteAddress)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) network anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
Initialize-NetworkBaseline
Start-Sleep -Seconds 10
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-NetworkAnomalyScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- DNSExfiltrationDetection ---
# DNS Exfiltration Detection Module
# Detects data exfiltration via DNS queries
$ModuleName = "DNSExfiltrationDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-DNSExfiltrationDetection {
$detections = @()
try {
# Monitor DNS queries
try {
$dnsEvents = Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-DNS-Client/Operational'; Id=3008} -ErrorAction SilentlyContinue -MaxEvents 500
$suspiciousQueries = @()
foreach ($event in $dnsEvents) {
try {
$xml = [xml]$event.ToXml()
$queryName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'QueryName'}).'#text'
$queryType = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'QueryType'}).'#text'
if ($queryName) {
# Check for base64-encoded subdomains (common in DNS exfiltration)
$subdomain = $queryName.Split('.')[0]
if ($subdomain.Length -gt 20 -and
$subdomain -match '^[A-Za-z0-9+/=]+$' -and
$subdomain.Length -gt 50) {
$suspiciousQueries += @{
QueryName = $queryName
QueryType = $queryType
TimeCreated = $event.TimeCreated
Type = "Base64-Encoded DNS Query"
Risk = "High"
}
}
# Check for hex-encoded subdomains
if ($subdomain.Length -gt 20 -and
$subdomain -match '^[A-Fa-f0-9]+$' -and
$subdomain.Length -gt 50) {
$suspiciousQueries += @{
QueryName = $queryName
QueryType = $queryType
TimeCreated = $event.TimeCreated
Type = "Hex-Encoded DNS Query"
Risk = "High"
}
}
# Check for unusually long domain names
if ($queryName.Length -gt 253) {
$suspiciousQueries += @{
QueryName = $queryName
QueryType = $queryType
TimeCreated = $event.TimeCreated
Type = "Unusually Long DNS Query"
Risk = "Medium"
}
}
# Check for queries to suspicious TLDs
$suspiciousTLDs = @(".onion", ".bit", ".i2p", ".test", ".local")
foreach ($tld in $suspiciousTLDs) {
if ($queryName -like "*$tld") {
$suspiciousQueries += @{
QueryName = $queryName
QueryType = $queryType
TimeCreated = $event.TimeCreated
Type = "DNS Query to Suspicious TLD"
TLD = $tld
Risk = "Medium"
}
}
}
}
} catch {
continue
}
}
$detections += $suspiciousQueries
# Check for excessive DNS queries from single process
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$procEvents = $dnsEvents | Where-Object {
$_.ProcessId -eq $proc.Id
} -ErrorAction SilentlyContinue
if ($procEvents.Count -gt 100) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
DNSQueryCount = $procEvents.Count
Type = "Excessive DNS Queries from Process"
Risk = "High"
}
}
} catch {
continue
}
}
} catch { }
} catch { }
# Monitor DNS traffic volume
try {
$dnsConnections = Get-NetUDPEndpoint -ErrorAction SilentlyContinue |
Where-Object { $_.LocalPort -eq 53 }
if ($dnsConnections.Count -gt 100) {
$detections += @{
ConnectionCount = $dnsConnections.Count
Type = "High DNS Traffic Volume"
Risk = "Medium"
}
}
} catch { }
# Check for DNS tunneling tools
try {
$processes = Get-CimInstance Win32_Process |
Where-Object {
$_.Name -match 'dnscat|iodine|dns2tcp|dnsperf'
}
foreach ($proc in $processes) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Type = "DNS Tunneling Tool Detected"
Risk = "Critical"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2029 `
-Message "DNS EXFILTRATION: $($detection.Type) - $($detection.QueryName -or $detection.ProcessName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\DNSExfiltration_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.QueryName -or $_.ProcessName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) DNS exfiltration indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-DNSExfiltrationDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- RootkitDetection ---
# Rootkit Detection Module
# Detects rootkit installation and activity
$ModuleName = "RootkitDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-RootkitScan {
$detections = @()
try {
# Check for hidden processes (rootkit indicator)
$processes = Get-Process -ErrorAction SilentlyContinue
$cimProcesses = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
Select-Object ProcessId, Name
$processIds = $processes | ForEach-Object { $_.Id } | Sort-Object -Unique
$cimProcessIds = $cimProcesses | ForEach-Object { $_.ProcessId } | Sort-Object -Unique
$hiddenProcesses = Compare-Object -ReferenceObject $processIds -DifferenceObject $cimProcessIds
if ($hiddenProcesses) {
foreach ($hidden in $hiddenProcesses) {
$detections += @{
ProcessId = $hidden.InputObject
Type = "Hidden Process Detected"
Risk = "Critical"
}
}
}
# Check for hidden files/directories
try {
$systemDirs = @("$env:SystemRoot\System32", "$env:SystemRoot\SysWOW64")
foreach ($dir in $systemDirs) {
if (Test-Path $dir) {
$files = Get-ChildItem -Path $dir -Force -ErrorAction SilentlyContinue |
Where-Object { $_.Attributes -match 'Hidden' -or $_.Attributes -match 'System' }
$suspiciousFiles = $files | Where-Object {
$_.Name -match '^(\.|\.\.|sys|drv)' -or
$_.Extension -match '^\.(sys|drv|dll)$'
}
if ($suspiciousFiles.Count -gt 10) {
$detections += @{
Directory = $dir
SuspiciousFiles = $suspiciousFiles.Count
Type = "Suspicious Hidden Files in System Directory"
Risk = "High"
}
}
}
}
} catch { }
# Check for kernel drivers
try {
$drivers = Get-CimInstance Win32_SystemDriver -ErrorAction SilentlyContinue |
Where-Object {
$_.State -eq "Running" -and
$_.PathName -notlike "$env:SystemRoot\*" -or
$_.Description -match 'rootkit|stealth|hook'
}
foreach ($driver in $drivers) {
$detections += @{
DriverName = $driver.Name
PathName = $driver.PathName
Description = $driver.Description
Type = "Suspicious Kernel Driver"
Risk = "Critical"
}
}
} catch { }
# Check for SSDT hooks (indirectly through Event Log)
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'; Id=6008} -ErrorAction SilentlyContinue -MaxEvents 50
$hookIndicators = $events | Where-Object {
$_.Message -match 'hook|SSDT|kernel|driver.*unexpected'
}
if ($hookIndicators.Count -gt 0) {
$detections += @{
EventCount = $hookIndicators.Count
Type = "SSDT Hook Indicators"
Risk = "Critical"
}
}
} catch { }
# Check for processes with unusual privileges
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath
foreach ($proc in $processes) {
try {
$procObj = Get-Process -Id $proc.ProcessId -ErrorAction Stop
# Check for SeDebugPrivilege (common in rootkits)
if ($procObj.PrivilegedProcessorTime.TotalSeconds -gt 0 -and
$proc.Name -notin @("csrss.exe", "winlogon.exe", "services.exe")) {
# Indirect check - process with unusual privileges
if ($proc.ExecutablePath -and (Test-Path $proc.ExecutablePath)) {
$sig = Get-AuthenticodeSignature -FilePath $proc.ExecutablePath -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid" -and $proc.ExecutablePath -like "$env:SystemRoot\*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ExecutablePath = $proc.ExecutablePath
Type = "Unsigned Process with System Privileges"
Risk = "High"
}
}
}
}
} catch {
continue
}
}
} catch { }
# Check for unusual boot entries
try {
$bootEntries = Get-CimInstance Win32_BootConfiguration -ErrorAction SilentlyContinue
foreach ($boot in $bootEntries) {
if ($boot.Description -match 'rootkit|stealth|hook' -or
$boot.Description -notlike '*Windows*') {
$detections += @{
BootEntry = $boot.Description
Type = "Suspicious Boot Entry"
Risk = "Critical"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2017 `
-Message "ROOTKIT DETECTED: $($detection.Type) - $($detection.ProcessName -or $detection.DriverName -or $detection.Directory)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\Rootkit_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.DriverName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) rootkit indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-RootkitScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ClipboardMonitoring ---
# Clipboard Monitoring Module
# Monitors clipboard for sensitive data
$ModuleName = "ClipboardMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 10 }
function Invoke-ClipboardMonitoring {
$detections = @()
try {
# Monitor clipboard content
Add-Type -AssemblyName System.Windows.Forms
if ([System.Windows.Forms.Clipboard]::ContainsText()) {
$clipboardText = [System.Windows.Forms.Clipboard]::GetText()
if (-not [string]::IsNullOrEmpty($clipboardText)) {
# Check for sensitive data patterns
$sensitivePatterns = @(
@{Pattern = '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'; Type = 'Email Address'},
@{Pattern = '\b\d{3}-\d{2}-\d{4}\b'; Type = 'SSN'},
@{Pattern = '\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b'; Type = 'Credit Card'},
@{Pattern = '(?i)(password|passwd|pwd|secret|api[_-]?key|token|bearer)'; Type = 'Password/Token'},
@{Pattern = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'; Type = 'IP Address'},
@{Pattern = '(?i)(https?://[^\s]+)'; Type = 'URL'}
)
foreach ($pattern in $sensitivePatterns) {
if ($clipboardText -match $pattern.Pattern) {
$matches = [regex]::Matches($clipboardText, $pattern.Pattern)
if ($matches.Count -gt 0) {
$detections += @{
Type = "Sensitive Data in Clipboard"
DataType = $pattern.Type
MatchCount = $matches.Count
Risk = if ($pattern.Type -match 'Password|SSN|Credit Card') { "High" } else { "Medium" }
}
}
}
}
# Check for large clipboard content (possible exfiltration)
if ($clipboardText.Length -gt 10000) {
$detections += @{
Type = "Large Clipboard Content"
ContentLength = $clipboardText.Length
Risk = "Medium"
}
}
# Check for base64 encoded content
if ($clipboardText -match '^[A-Za-z0-9+/]+={0,2}$' -and $clipboardText.Length -gt 100) {
try {
$decoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($clipboardText))
if ($decoded.Length -gt 0) {
$detections += @{
Type = "Base64 Encoded Content in Clipboard"
EncodedLength = $clipboardText.Length
DecodedLength = $decoded.Length
Risk = "Medium"
}
}
} catch { }
}
}
}
# Check for processes accessing clipboard
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules | Where-Object {
$_.ModuleName -match 'clipboard|clip'
}
if ($modules.Count -gt 0) {
# Exclude legitimate processes
$legitProcesses = @("explorer.exe", "dwm.exe", "mstsc.exe")
if ($proc.ProcessName -notin $legitProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
Type = "Process Accessing Clipboard"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2018 `
-Message "CLIPBOARD MONITORING: $($detection.Type) - $($detection.DataType -or $detection.ProcessName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\Clipboard_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.DataType -or $_.ProcessName)|$($_.Risk)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) clipboard anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ClipboardMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- COMMonitoring ---
# COM Object Monitoring Module
# Monitors COM object instantiation and usage
$ModuleName = "COMMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-COMMonitoring {
$detections = @()
try {
# Check for suspicious COM objects
$suspiciousCOMObjects = @(
"Shell.Application",
"WScript.Shell",
"Scripting.FileSystemObject",
"Excel.Application",
"Word.Application",
"InternetExplorer.Application"
)
# Check running processes for COM usage
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine
foreach ($proc in $processes) {
try {
# Check command line for COM object creation
if ($proc.CommandLine) {
foreach ($comObj in $suspiciousCOMObjects) {
if ($proc.CommandLine -like "*$comObj*" -or
$proc.CommandLine -like "*New-Object*$comObj*" -or
$proc.CommandLine -like "*CreateObject*$comObj*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
COMObject = $comObj
Type = "Suspicious COM Object Usage"
Risk = "Medium"
}
}
}
}
} catch {
continue
}
}
# Check Event Log for COM object registration
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Application'} -ErrorAction SilentlyContinue -MaxEvents 500 |
Where-Object { $_.Message -match 'COM|Component Object Model' }
$registrationEvents = $events | Where-Object {
$_.Message -match 'registration|registration.*failed|COM.*error'
}
if ($registrationEvents.Count -gt 5) {
$detections += @{
EventCount = $registrationEvents.Count
Type = "Unusual COM Registration Activity"
Risk = "Medium"
}
}
} catch { }
# Check for COM hijacking
try {
$comKeys = @(
"HKCU:\SOFTWARE\Classes\CLSID",
"HKLM:\SOFTWARE\Classes\CLSID"
)
foreach ($comKey in $comKeys) {
if (Test-Path $comKey) {
$clsidKeys = Get-ChildItem -Path $comKey -ErrorAction SilentlyContinue | Select-Object -First 100
foreach ($clsid in $clsidKeys) {
$inprocServer = Join-Path $clsid.PSPath "InprocServer32"
if (Test-Path $inprocServer) {
$default = (Get-ItemProperty -Path $inprocServer -Name "(default)" -ErrorAction SilentlyContinue).'(default)'
if ($default -and $default -notlike "$env:SystemRoot\*") {
$detections += @{
CLSID = $clsid.Name
InprocServer = $default
Type = "COM Hijacking - Non-System InprocServer"
Risk = "High"
}
}
}
}
}
}
} catch { }
# Check for Excel/Word automation (common in malware)
try {
$excelProcs = Get-Process -Name "EXCEL" -ErrorAction SilentlyContinue
$wordProcs = Get-Process -Name "WINWORD" -ErrorAction SilentlyContinue
foreach ($proc in ($excelProcs + $wordProcs)) {
try {
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.Id)").CommandLine
if ($commandLine -match '\.vbs|\.js|\.ps1|\.bat|powershell|cmd') {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
CommandLine = $commandLine
Type = "Office Application with Script Execution"
Risk = "High"
}
}
} catch { }
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2019 `
-Message "COM MONITORING: $($detection.Type) - $($detection.ProcessName -or $detection.CLSID -or $detection.COMObject)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\COMMonitoring_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.COMObject -or $_.CLSID)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) COM object anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-COMMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- BrowserExtensionMonitoring ---
# Browser Extension Monitoring Module
# Monitors browser extensions for malicious activity
$ModuleName = "BrowserExtensionMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-BrowserExtensionMonitoring {
$detections = @()
try {
# Check Chrome extensions
$chromeExtensionsPath = "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Extensions"
if (Test-Path $chromeExtensionsPath) {
$chromeExts = Get-ChildItem -Path $chromeExtensionsPath -Directory -ErrorAction SilentlyContinue
foreach ($ext in $chromeExts) {
$manifestPath = Join-Path $ext.FullName "*\manifest.json"
$manifests = Get-ChildItem -Path $manifestPath -ErrorAction SilentlyContinue
foreach ($manifest in $manifests) {
try {
$manifestContent = Get-Content $manifest.FullName -Raw | ConvertFrom-Json -ErrorAction Stop
# Check for suspicious permissions
$suspiciousPermissions = @("all_urls", "tabs", "cookies", "history", "downloads", "webRequest", "webRequestBlocking")
$hasSuspiciousPerms = $false
if ($manifestContent.permissions) {
foreach ($perm in $manifestContent.permissions) {
if ($perm -in $suspiciousPermissions) {
$hasSuspiciousPerms = $true
break
}
}
}
# Check for unsigned extensions
$isSigned = $manifestContent.key -ne $null
if ($hasSuspiciousPerms -or -not $isSigned) {
$detections += @{
Browser = "Chrome"
ExtensionId = $ext.Name
ExtensionName = $manifestContent.name
ManifestPath = $manifest.FullName
HasSuspiciousPermissions = $hasSuspiciousPerms
IsSigned = $isSigned
Type = "Suspicious Chrome Extension"
Risk = if ($hasSuspiciousPerms) { "High" } else { "Medium" }
}
}
} catch {
continue
}
}
}
}
# Check Edge extensions
$edgeExtensionsPath = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Extensions"
if (Test-Path $edgeExtensionsPath) {
$edgeExts = Get-ChildItem -Path $edgeExtensionsPath -Directory -ErrorAction SilentlyContinue
foreach ($ext in $edgeExts) {
$manifestPath = Join-Path $ext.FullName "*\manifest.json"
$manifests = Get-ChildItem -Path $manifestPath -ErrorAction SilentlyContinue
foreach ($manifest in $manifests) {
try {
$manifestContent = Get-Content $manifest.FullName -Raw | ConvertFrom-Json -ErrorAction Stop
if ($manifestContent.permissions) {
$suspiciousPerms = $manifestContent.permissions | Where-Object {
$_ -in @("all_urls", "tabs", "cookies", "webRequest")
}
if ($suspiciousPerms.Count -gt 0) {
$detections += @{
Browser = "Edge"
ExtensionId = $ext.Name
ExtensionName = $manifestContent.name
SuspiciousPermissions = $suspiciousPerms -join ','
Type = "Suspicious Edge Extension"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
}
}
# Check Firefox extensions
$firefoxProfilesPath = "$env:APPDATA\Mozilla\Firefox\Profiles"
if (Test-Path $firefoxProfilesPath) {
$profiles = Get-ChildItem -Path $firefoxProfilesPath -Directory -ErrorAction SilentlyContinue
foreach ($profile in $profiles) {
$extensionsPath = Join-Path $profile.FullName "extensions"
if (Test-Path $extensionsPath) {
$firefoxExts = Get-ChildItem -Path $extensionsPath -File -ErrorAction SilentlyContinue |
Where-Object { $_.Extension -eq ".xpi" -or $_.Extension -eq "" }
foreach ($ext in $firefoxExts) {
$detections += @{
Browser = "Firefox"
ExtensionPath = $ext.FullName
Type = "Firefox Extension Detected"
Risk = "Low"
}
}
}
}
}
# Check for browser processes with unusual activity
try {
$browserProcs = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.ProcessName -match 'chrome|edge|firefox|msedge' }
foreach ($proc in $browserProcs) {
try {
$conns = Get-NetTCPConnection -OwningProcess $proc.Id -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" }
# Check for connections to suspicious domains
$remoteIPs = $conns.RemoteAddress | Select-Object -Unique
foreach ($ip in $remoteIPs) {
try {
$hostname = [System.Net.Dns]::GetHostEntry($ip).HostName
$suspiciousDomains = @(".onion", ".bit", ".i2p", "pastebin", "githubusercontent")
foreach ($domain in $suspiciousDomains) {
if ($hostname -like "*$domain*") {
$detections += @{
BrowserProcess = $proc.ProcessName
ProcessId = $proc.Id
ConnectedDomain = $hostname
Type = "Browser Connecting to Suspicious Domain"
Risk = "Medium"
}
}
}
} catch { }
}
} catch {
continue
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2020 `
-Message "BROWSER EXTENSION: $($detection.Type) - $($detection.ExtensionName -or $detection.BrowserProcess)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\BrowserExtension_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ExtensionName -or $_.BrowserProcess)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) browser extension anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-BrowserExtensionMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ShadowCopyMonitoring ---
# Shadow Copy Monitoring Module
# Monitors shadow copy deletion (ransomware indicator)
$ModuleName = "ShadowCopyMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-ShadowCopyMonitoring {
$detections = @()
try {
# Check for shadow copies
$shadowCopies = Get-CimInstance Win32_ShadowCopy -ErrorAction SilentlyContinue
# Check shadow copy count
if ($shadowCopies.Count -eq 0) {
$detections += @{
Type = "No Shadow Copies Found"
ShadowCopyCount = 0
Risk = "Medium"
}
}
# Monitor shadow copy deletion
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'} -ErrorAction SilentlyContinue -MaxEvents 200 |
Where-Object {
$_.Message -match 'shadow|vss|volume.*snapshot' -or
$_.Id -in @(8221, 8222, 8223, 8224)
}
$deletionEvents = $events | Where-Object {
$_.Message -match 'delete|deleted|remove|removed'
}
if ($deletionEvents.Count -gt 0) {
foreach ($event in $deletionEvents) {
$detections += @{
EventId = $event.Id
TimeCreated = $event.TimeCreated
Message = $event.Message
Type = "Shadow Copy Deletion Detected"
Risk = "High"
}
}
}
} catch { }
# Check for VSSAdmin usage
try {
$processes = Get-CimInstance Win32_Process |
Where-Object { $_.Name -eq "vssadmin.exe" -or $_.CommandLine -like "*vssadmin*" }
foreach ($proc in $processes) {
if ($proc.CommandLine -match 'delete.*shadows|resize.*shadowstorage') {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Type = "VSSAdmin Shadow Copy Manipulation"
Risk = "Critical"
}
}
}
} catch { }
# Check for Volume Shadow Copy Service status
try {
$vssService = Get-CimInstance Win32_Service -Filter "Name='VSS'" -ErrorAction SilentlyContinue
if ($vssService) {
if ($vssService.State -ne "Running") {
$detections += @{
ServiceState = $vssService.State
Type = "Volume Shadow Copy Service Not Running"
Risk = "High"
}
}
}
} catch { }
# Check shadow storage configuration
try {
$shadowStorage = Get-CimInstance Win32_ShadowStorage -ErrorAction SilentlyContinue
foreach ($storage in $shadowStorage) {
# Check if shadow storage is disabled or too small
$allocated = $storage.AllocatedSpace
$maxSize = $storage.MaxSpace
if ($maxSize -eq 0 -or $allocated -eq 0) {
$detections += @{
Volume = $storage.Volume
AllocatedSpace = $allocated
MaxSpace = $maxSize
Type = "Shadow Storage Disabled or Empty"
Risk = "Medium"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2021 `
-Message "SHADOW COPY MONITORING: $($detection.Type) - $($detection.ProcessName -or $detection.Volume -or $detection.Message)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ShadowCopy_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.Volume)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) shadow copy anomalies"
}
Write-Output "STATS:$ModuleName`:Shadow copies=$($shadowCopies.Count)"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ShadowCopyMonitoring
$LastTick = $now
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- USBMonitoring ---
# USB Device Monitoring Module
# Monitors USB device connections and activity
$ModuleName = "USBMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-USBMonitoring {
$detections = @()
try {
# Get USB devices
$usbDevices = Get-CimInstance Win32_USBControllerDevice -ErrorAction SilentlyContinue
foreach ($usbDevice in $usbDevices) {
try {
$device = Get-CimInstance -InputObject $usbDevice.Dependent -ErrorAction SilentlyContinue
if ($device) {
# Check for suspicious USB device types
$suspiciousDevices = @{
"HID" = "Human Interface Device"
"USBSTOR" = "USB Mass Storage"
}
$deviceType = $device.DeviceID
# Check for HID devices (keyloggers, etc.)
if ($deviceType -match "HID") {
$detections += @{
DeviceId = $device.DeviceID
DeviceName = $device.Name
DeviceType = "HID Device"
Type = "USB HID Device Connected"
Risk = "Medium"
}
}
# Check for USB storage devices
if ($deviceType -match "USBSTOR") {
$detections += @{
DeviceId = $device.DeviceID
DeviceName = $device.Name
DeviceType = "USB Storage"
Type = "USB Storage Device Connected"
Risk = "Low"
}
}
}
} catch {
continue
}
}
# Check Event Log for USB device events
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'; Id=20001,20002,20003} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object { $_.Message -match 'USB|removable|storage' }
$recentEvents = $events | Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromMinutes(5)
}
if ($recentEvents.Count -gt 5) {
$detections += @{
EventCount = $recentEvents.Count
Type = "Excessive USB Device Activity"
Risk = "Medium"
}
}
} catch { }
# Check for USB device autorun
try {
$autorunKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AutoplayHandlers",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer"
)
foreach ($key in $autorunKeys) {
if (Test-Path $key) {
$noDriveAutorun = Get-ItemProperty -Path $key -Name "NoDriveTypeAutoRun" -ErrorAction SilentlyContinue
if ($noDriveAutorun -and $noDriveAutorun.NoDriveTypeAutoRun -eq 0) {
$detections += @{
RegistryKey = $key
Type = "USB Autorun Enabled"
Risk = "High"
}
}
}
}
} catch { }
# Check for processes accessing USB devices
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules | Where-Object {
$_.ModuleName -match 'usb|hid|storage'
}
if ($modules.Count -gt 0) {
# Exclude legitimate processes
$legitProcesses = @("explorer.exe", "svchost.exe", "services.exe")
if ($proc.ProcessName -notin $legitProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
USBModules = $modules.ModuleName -join ','
Type = "Process Accessing USB Devices"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
} catch { }
# Check for USB device driver modifications
try {
$usbDrivers = Get-CimInstance Win32_SystemDriver -ErrorAction SilentlyContinue |
Where-Object {
$_.PathName -match 'usb|hid' -and
$_.PathName -notlike "$env:SystemRoot\*"
}
foreach ($driver in $usbDrivers) {
$detections += @{
DriverName = $driver.Name
DriverPath = $driver.PathName
Type = "Non-Standard USB Driver"
Risk = "High"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Information -EventId 2022 `
-Message "USB MONITORING: $($detection.Type) - $($detection.DeviceName -or $detection.ProcessName -or $detection.DriverName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\USBMonitoring_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.DeviceName -or $_.ProcessName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) USB device anomalies"
}
Write-Output "STATS:$ModuleName`:USB devices=$($usbDevices.Count)"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-USBMonitoring
$LastTick = $now
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- WebcamGuardian ---
# Webcam Guardian Module
# Monitors webcam access and protects privacy
$ModuleName = "WebcamGuardian"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 20 }
function Invoke-WebcamGuardian {
$detections = @()
try {
# Check for webcam devices
try {
$webcamDevices = Get-CimInstance Win32_PnPEntity -ErrorAction SilentlyContinue |
Where-Object {
$_.Name -match 'camera|webcam|video|imaging|usb.*video' -or
$_.PNPDeviceID -match 'VID_.*PID_.*.*CAMERA'
}
if ($webcamDevices.Count -gt 0) {
Write-Output "STATS:$ModuleName`:Webcam devices=$($webcamDevices.Count)"
}
} catch { }
# Check for processes accessing webcam
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
# Check for webcam-related modules
$modules = $proc.Modules | Where-Object {
$_.ModuleName -match 'ksuser|avicap32|msvfw32|amstream|qcap|vidcap'
}
if ($modules.Count -gt 0) {
# Check if process is authorized
$authorizedProcesses = @("explorer.exe", "dwm.exe", "chrome.exe", "firefox.exe", "msedge.exe", "teams.exe", "zoom.exe", "skype.exe")
if ($proc.ProcessName -notin $authorizedProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
ProcessPath = $proc.Path
WebcamModules = $modules.ModuleName -join ','
Type = "Unauthorized Webcam Access"
Risk = "High"
}
}
}
# Check for video capture libraries
$videoModules = $proc.Modules | Where-Object {
$_.ModuleName -match 'video|capture|stream|directshow|media'
}
if ($videoModules.Count -gt 3 -and
$proc.ProcessName -notin $authorizedProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
VideoModules = $videoModules.ModuleName -join ','
Type = "Process with Many Video Capture Modules"
Risk = "Medium"
}
}
} catch {
continue
}
}
} catch { }
# Check for webcam-related registry keys
try {
$webcamRegKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam"
)
foreach ($regKey in $webcamRegKeys) {
if (Test-Path $regKey) {
$values = Get-ItemProperty -Path $regKey -ErrorAction SilentlyContinue
if ($values) {
# Check for applications with webcam access
$appAccess = $values.PSObject.Properties | Where-Object {
$_.Name -notin @('PSPath','PSParentPath','PSChildName','PSDrive','PSProvider') -and
$_.Value -ne "Deny"
}
foreach ($app in $appAccess) {
# Check if app is suspicious
if ($app.Name -notmatch 'microsoft|windows|explorer|chrome|firefox|edge|teams|zoom|skype') {
$detections += @{
RegistryKey = $regKey
AppName = $app.Name
Access = $app.Value
Type = "Suspicious App with Webcam Access"
Risk = "High"
}
}
}
}
}
}
} catch { }
# Check Event Log for webcam access
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Application'} -ErrorAction SilentlyContinue -MaxEvents 500 |
Where-Object {
$_.Message -match 'camera|webcam|video.*capture|imaging.*device'
}
$webcamEvents = $events | Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromMinutes(5)
}
if ($webcamEvents.Count -gt 10) {
$detections += @{
EventCount = $webcamEvents.Count
Type = "Excessive Webcam Access Activity"
Risk = "Medium"
}
}
} catch { }
# Check for webcam blocking/monitoring tools
try {
$processes = Get-CimInstance Win32_Process |
Where-Object {
$_.Name -match 'camtasia|obs|webcam|camera|guardian|privacy'
}
foreach ($proc in $processes) {
# These are usually legitimate, but log them
Write-Output "STATS:$ModuleName`:Webcam-related process=$($proc.Name)"
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2031 `
-Message "WEBCAM GUARDIAN: $($detection.Type) - $($detection.ProcessName -or $detection.AppName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\WebcamGuardian_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.AppName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) webcam access anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-WebcamGuardian
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- AttackToolsDetection ---
# Attack Tools Detection
# Detects Mimikatz, Cobalt Strike, Metasploit, etc.
$ModuleName = "AttackToolsDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 90 }
$AttackTools = @("mimikatz", "pwdump", "procdump", "wce", "gsecdump", "cain", "john", "hashcat", "hydra", "medusa", "nmap", "metasploit", "armitage", "cobalt")
function Invoke-AttackToolsScan {
$detections = @()
try {
$processes = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Select-Object ProcessId, Name, CommandLine
foreach ($proc in $processes) {
$name = if ($proc.Name) { $proc.Name.ToLower() } else { "" }
$cmd = if ($proc.CommandLine) { $proc.CommandLine.ToLower() } else { "" }
foreach ($tool in $AttackTools) {
if ($name -like "*$tool*" -or $cmd -like "*$tool*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Tool = $tool
Type = "Attack Tool Detected"
Risk = "Critical"
}
break
}
}
}
if ($detections.Count -gt 0) {
foreach ($d in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2092 -Message "ATTACK TOOL: $($d.Tool) - $($d.ProcessName) (PID: $($d.ProcessId))" -ErrorAction SilentlyContinue
}
$logPath = "$env:ProgramData\Antivirus\Logs\attack_tools_detection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Tool)|$($_.ProcessName)|PID:$($_.ProcessId)" | Add-Content -Path $logPath }
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) attack tools"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-AttackToolsScan | Out-Null
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- AdvancedThreatDetection ---
# Advanced Threat Detection
# High-entropy files in Windows\Temp, System32\Tasks
$ModuleName = "AdvancedThreatDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 90 }
$ScanPaths = @("$env:SystemRoot\Temp", "$env:SystemRoot\System32\Tasks")
$Extensions = @("*.exe", "*.dll", "*.ps1", "*.vbs")
function Measure-FileEntropy {
param([string]$FilePath)
try {
$bytes = [System.IO.File]::ReadAllBytes($FilePath)
if ($bytes.Length -eq 0) { return 0 }
$sample = if ($bytes.Length -gt 4096) { $bytes[0..4095] } else { $bytes }
$freq = @{}
foreach ($b in $sample) {
if (-not $freq.ContainsKey($b)) { $freq[$b] = 0 }
$freq[$b]++
}
$entropy = 0
foreach ($c in $freq.Values) {
$p = $c / $sample.Count
$entropy -= $p * [Math]::Log($p, 2)
}
return $entropy
} catch { return 0 }
}
function Invoke-AdvancedThreatScan {
$detections = @()
foreach ($basePath in $ScanPaths) {
if (-not (Test-Path $basePath)) { continue }
foreach ($ext in $Extensions) {
try {
Get-ChildItem -Path $basePath -Filter $ext -File -ErrorAction SilentlyContinue | ForEach-Object {
$ent = Measure-FileEntropy -FilePath $_.FullName
if ($ent -gt 7.5) {
$detections += @{
Path = $_.FullName
Entropy = [Math]::Round($ent, 2)
Type = "High-Entropy File"
Risk = "High"
}
}
}
} catch { }
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\advanced_threat_detection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Path)|Entropy:$($_.Entropy)" | Add-Content -Path $logPath
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2091 -Message "ADVANCED THREAT: $($_.Path)" -ErrorAction SilentlyContinue
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) high-entropy files"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-AdvancedThreatScan | Out-Null
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- FirewallRuleMonitoring ---
# Firewall Rule Monitoring Module
# Monitors firewall rules for suspicious changes
$ModuleName = "FirewallRuleMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
$BaselineRules = @{}
function Initialize-FirewallBaseline {
try {
$rules = Get-NetFirewallRule -ErrorAction SilentlyContinue
foreach ($rule in $rules) {
$key = "$($rule.Name)|$($rule.Direction)|$($rule.Action)"
if (-not $BaselineRules.ContainsKey($key)) {
$BaselineRules[$key] = @{
Name = $rule.Name
Direction = $rule.Direction
Action = $rule.Action
Enabled = $rule.Enabled
FirstSeen = Get-Date
}
}
}
} catch { }
}
function Invoke-FirewallRuleMonitoring {
$detections = @()
try {
# Get current firewall rules
$rules = Get-NetFirewallRule -ErrorAction SilentlyContinue
# Check for new or modified rules
foreach ($rule in $rules) {
$key = "$($rule.Name)|$($rule.Direction)|$($rule.Action)"
if (-not $BaselineRules.ContainsKey($key)) {
# New rule detected
$detections += @{
RuleName = $rule.Name
Direction = $rule.Direction
Action = $rule.Action
Enabled = $rule.Enabled
Type = "New Firewall Rule"
Risk = "Medium"
}
# Update baseline
$BaselineRules[$key] = @{
Name = $rule.Name
Direction = $rule.Direction
Action = $rule.Action
Enabled = $rule.Enabled
FirstSeen = Get-Date
}
} else {
# Check if rule was modified
$baseline = $BaselineRules[$key]
if ($rule.Enabled -ne $baseline.Enabled) {
$detections += @{
RuleName = $rule.Name
OldState = $baseline.Enabled
NewState = $rule.Enabled
Type = "Firewall Rule State Changed"
Risk = "High"
}
$baseline.Enabled = $rule.Enabled
}
}
}
# Check for suspicious firewall rules
foreach ($rule in $rules) {
try {
$ruleFilters = Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $rule -ErrorAction SilentlyContinue
$ruleAppFilters = Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $rule -ErrorAction SilentlyContinue
# Check for rules allowing all traffic
if ($ruleFilters) {
if ($ruleFilters.RemoteAddress -eq "*" -and $rule.Action -eq "Allow") {
$detections += @{
RuleName = $rule.Name
RemoteAddress = $ruleFilters.RemoteAddress
Type = "Firewall Rule Allows All Traffic"
Risk = "High"
}
}
}
# Check for rules allowing unsigned applications
if ($ruleAppFilters -and $ruleAppFilters.Program) {
foreach ($program in $ruleAppFilters.Program) {
if ($program -and (Test-Path $program)) {
$sig = Get-AuthenticodeSignature -FilePath $program -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid" -and $rule.Action -eq "Allow") {
$detections += @{
RuleName = $rule.Name
Program = $program
Type = "Firewall Rule Allows Unsigned Application"
Risk = "Medium"
}
}
}
}
}
# Check for rules with unusual port ranges
$portFilters = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule -ErrorAction SilentlyContinue
if ($portFilters) {
if ($portFilters.LocalPort -eq "*" -or
($portFilters.LocalPort -is [Array] -and $portFilters.LocalPort.Count -gt 100)) {
$detections += @{
RuleName = $rule.Name
LocalPort = $portFilters.LocalPort
Type = "Firewall Rule with Unusual Port Range"
Risk = "Medium"
}
}
}
} catch {
continue
}
}
# Check for firewall service status
try {
$fwService = Get-CimInstance Win32_Service -Filter "Name='MpsSvc'" -ErrorAction SilentlyContinue
if ($fwService -and $fwService.State -ne "Running") {
$detections += @{
ServiceState = $fwService.State
Type = "Windows Firewall Service Not Running"
Risk = "Critical"
}
}
} catch { }
# Check for firewall profiles
try {
$profiles = Get-NetFirewallProfile -ErrorAction SilentlyContinue
foreach ($profile in $profiles) {
if ($profile.Enabled -eq $false) {
$detections += @{
ProfileName = $profile.Name
Type = "Firewall Profile Disabled"
Risk = "Critical"
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2024 `
-Message "FIREWALL RULE MONITORING: $($detection.Type) - $($detection.RuleName -or $detection.ProfileName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\FirewallRule_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.RuleName -or $_.ProfileName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) firewall rule anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
Initialize-FirewallBaseline
Start-Sleep -Seconds 10
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-FirewallRuleMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ServiceMonitoring ---
# Service Monitoring Module
# Monitors Windows services for suspicious activity
$ModuleName = "ServiceMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
$BaselineServices = @{}
function Initialize-ServiceBaseline {
try {
$services = Get-CimInstance Win32_Service -ErrorAction SilentlyContinue
foreach ($svc in $services) {
$key = "$($svc.Name)|$($svc.PathName)"
if (-not $BaselineServices.ContainsKey($key)) {
$BaselineServices[$key] = @{
Name = $svc.Name
DisplayName = $svc.DisplayName
PathName = $svc.PathName
State = $svc.State
StartMode = $svc.StartMode
StartName = $svc.StartName
FirstSeen = Get-Date
}
}
}
} catch { }
}
function Invoke-ServiceMonitoring {
$detections = @()
try {
$services = Get-CimInstance Win32_Service -ErrorAction SilentlyContinue
foreach ($svc in $services) {
$key = "$($svc.Name)|$($svc.PathName)"
# Check for new services
if (-not $BaselineServices.ContainsKey($key)) {
$detections += @{
ServiceName = $svc.Name
DisplayName = $svc.DisplayName
PathName = $svc.PathName
State = $svc.State
StartMode = $svc.StartMode
Type = "New Service Detected"
Risk = "High"
}
# Update baseline
$BaselineServices[$key] = @{
Name = $svc.Name
DisplayName = $svc.DisplayName
PathName = $svc.PathName
State = $svc.State
StartMode = $svc.StartMode
StartName = $svc.StartName
FirstSeen = Get-Date
}
} else {
# Check for service state changes
$baseline = $BaselineServices[$key]
if ($svc.State -ne $baseline.State) {
$detections += @{
ServiceName = $svc.Name
OldState = $baseline.State
NewState = $svc.State
Type = "Service State Changed"
Risk = "Medium"
}
$baseline.State = $svc.State
}
}
# Check for suspicious service properties
if ($svc.PathName -and (Test-Path $svc.PathName)) {
# Check for unsigned service executables
$sig = Get-AuthenticodeSignature -FilePath $svc.PathName -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
$detections += @{
ServiceName = $svc.Name
PathName = $svc.PathName
Type = "Unsigned Service Executable"
Risk = "High"
}
}
# Check for services not in system directories
if ($svc.PathName -notlike "$env:SystemRoot\*" -and
$svc.PathName -notlike "$env:ProgramFiles*") {
$detections += @{
ServiceName = $svc.Name
PathName = $svc.PathName
Type = "Service Executable Outside System/Program Directories"
Risk = "Medium"
}
}
# Check for services with suspicious command line arguments
if ($svc.PathName -match 'powershell|cmd|wscript|cscript|http') {
$detections += @{
ServiceName = $svc.Name
PathName = $svc.PathName
Type = "Service with Suspicious Command Line"
Risk = "High"
}
}
}
# Check for services running as SYSTEM with suspicious paths
if ($svc.StartName -eq "LocalSystem" -or $svc.StartName -eq "NT AUTHORITY\SYSTEM") {
if ($svc.PathName -notlike "$env:SystemRoot\*") {
$detections += @{
ServiceName = $svc.Name
StartName = $svc.StartName
PathName = $svc.PathName
Type = "SYSTEM Service Outside System Directory"
Risk = "Critical"
}
}
}
# Check for services with unusual display names
if ($svc.DisplayName -match 'update|installer|system|security|windows' -and
$svc.Name -notmatch '^[A-Z][a-z]') {
# Suspicious display name pattern
$detections += @{
ServiceName = $svc.Name
DisplayName = $svc.DisplayName
Type = "Service with Suspicious Display Name"
Risk = "Medium"
}
}
}
# Check for stopped critical services
$criticalServices = @("WinDefend", "SecurityHealthService", "MpsSvc", "BITS")
foreach ($criticalSvc in $criticalServices) {
$svc = $services | Where-Object { $_.Name -eq $criticalSvc } | Select-Object -First 1
if ($svc -and $svc.State -ne "Running") {
$detections += @{
ServiceName = $svc.Name
State = $svc.State
Type = "Critical Service Stopped"
Risk = "High"
}
}
}
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2025 `
-Message "SERVICE MONITORING: $($detection.Type) - $($detection.ServiceName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ServiceMonitoring_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ServiceName)|$($_.PathName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) service anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
Initialize-ServiceBaseline
Start-Sleep -Seconds 10
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ServiceMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- FilelessDetection ---
# Fileless Malware Detection Module
# Detects fileless malware techniques
$ModuleName = "FilelessDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 20 }
function Invoke-FilelessDetection {
$detections = @()
try {
# Check for PowerShell in memory execution
$psProcesses = Get-Process -Name "powershell*","pwsh*" -ErrorAction SilentlyContinue
foreach ($psProc in $psProcesses) {
try {
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$($psProc.Id)").CommandLine
if ($commandLine) {
# Check for encoded commands
if ($commandLine -match '-encodedcommand|-enc|-e\s+[A-Za-z0-9+/=]{100,}') {
$detections += @{
ProcessId = $psProc.Id
ProcessName = $psProc.ProcessName
CommandLine = $commandLine
Type = "PowerShell Encoded Command Execution"
Risk = "High"
}
}
# Check for IEX/Invoke-Expression usage
if ($commandLine -match '(?i)(iex|invoke-expression|invoke-expression)') {
$detections += @{
ProcessId = $psProc.Id
ProcessName = $psProc.ProcessName
CommandLine = $commandLine
Type = "PowerShell IEX Execution"
Risk = "High"
}
}
# Check for download and execute
if ($commandLine -match '(?i)(downloadstring|downloadfile|webclient|invoke-webrequest).*(http|https|ftp)') {
$detections += @{
ProcessId = $psProc.Id
ProcessName = $psProc.ProcessName
CommandLine = $commandLine
Type = "PowerShell Download and Execute"
Risk = "Critical"
}
}
}
} catch {
continue
}
}
# Check for WMI event consumers (fileless persistence)
try {
$wmiConsumers = Get-CimInstance -Namespace root\subscription -ClassName __EventConsumer -ErrorAction SilentlyContinue
foreach ($consumer in $wmiConsumers) {
if ($consumer.__CLASS -match 'ActiveScript|CommandLine') {
$detections += @{
ConsumerName = $consumer.Name
ConsumerClass = $consumer.__CLASS
Type = "WMI Fileless Persistence"
Risk = "High"
}
}
}
} catch { }
# Check for Registry-based fileless execution
try {
$regKeys = @(
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
)
foreach ($regKey in $regKeys) {
if (Test-Path $regKey) {
$values = Get-ItemProperty -Path $regKey -ErrorAction SilentlyContinue
if ($values) {
$valueProps = $values.PSObject.Properties | Where-Object {
$_.Name -notin @('PSPath','PSParentPath','PSChildName','PSDrive','PSProvider')
}
foreach ($prop in $valueProps) {
$value = $prop.Value
# Check for registry-based script execution
if ($value -match 'powershell.*-enc|wscript|javascript|vbscript' -and
-not (Test-Path $value)) {
$detections += @{
RegistryPath = $regKey
ValueName = $prop.Name
Value = $value
Type = "Registry-Based Fileless Execution"
Risk = "High"
}
}
}
}
}
}
} catch { }
# Check for .NET reflection-based execution
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules | Where-Object {
$_.ModuleName -match 'System\.Reflection|System\.CodeDom'
}
if ($modules.Count -gt 0) {
# Check for unsigned processes using reflection
if ($proc.Path -and (Test-Path $proc.Path)) {
$sig = Get-AuthenticodeSignature -FilePath $proc.Path -ErrorAction SilentlyContinue
if ($sig.Status -ne "Valid") {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
ReflectionModules = $modules.ModuleName -join ','
Type = "Unsigned Process Using Reflection"
Risk = "Medium"
}
}
}
}
} catch {
continue
}
}
} catch { }
# Check for memory-only modules
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules | Where-Object {
$_.FileName -notlike "$env:SystemRoot\*" -and
$_.FileName -notlike "$env:ProgramFiles*" -and
-not (Test-Path $_.FileName)
}
if ($modules.Count -gt 5) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
MemoryModules = $modules.Count
Type = "Process with Many Memory-Only Modules"
Risk = "High"
}
}
} catch {
continue
}
}
} catch { }
# Check Event Log for fileless execution indicators
try {
$events = Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'} -ErrorAction SilentlyContinue -MaxEvents 200 |
Where-Object {
$_.Message -match 'encodedcommand|iex|invoke-expression|downloadstring'
}
foreach ($event in $events) {
$detections += @{
EventId = $event.Id
TimeCreated = $event.TimeCreated
Message = $event.Message
Type = "Event Log Fileless Execution Indicator"
Risk = "Medium"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2026 `
-Message "FILELESS DETECTION: $($detection.Type) - $($detection.ProcessName -or $detection.ConsumerName -or $detection.ValueName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\FilelessDetection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.ConsumerName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) fileless malware indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-FilelessDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- MemoryScanning ---
# Optimized Memory Scanning Module
# Reduced CPU/RAM/Disk usage with caching and batching
$ModuleName = "MemoryScanning"
$script:LastTick = Get-Date
$TickInterval = Get-TickInterval -ModuleName $ModuleName
$script:ProcessBaseline = @{}
$script:LastBaselineUpdate = Get-Date
function Update-ProcessBaseline {
$now = Get-Date
if (($now - $script:LastBaselineUpdate).TotalMinutes -lt 5) {
return
}
$script:LastBaselineUpdate = $now
$maxProcs = Get-ScanLimit -LimitName "MaxProcesses"
try {
$processes = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.WorkingSet64 -gt 10MB } |
Select-Object -First $maxProcs
foreach ($proc in $processes) {
$key = "$($proc.ProcessName)|$($proc.Id)"
if (-not $script:ProcessBaseline.ContainsKey($key)) {
$script:ProcessBaseline[$key] = @{
FirstSeen = $now
Scanned = $false
}
}
}
$toRemove = @()
foreach ($key in $script:ProcessBaseline.Keys) {
$pid = $key.Split('|')[1]
try {
$null = Get-Process -Id $pid -ErrorAction Stop
} catch {
$toRemove += $key
}
}
foreach ($key in $toRemove) {
$script:ProcessBaseline.Remove($key)
}
} catch { }
}
function Invoke-MemoryScanningOptimized {
$detections = @()
$batchSettings = Get-BatchSettings
$maxProcs = Get-ScanLimit -LimitName "MaxProcesses"
try {
Update-ProcessBaseline
$processes = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.WorkingSet64 -gt 10MB } |
Select-Object -First $maxProcs
$batchCount = 0
foreach ($proc in $processes) {
try {
$key = "$($proc.ProcessName)|$($proc.Id)"
if ($script:ProcessBaseline.ContainsKey($key) -and $script:ProcessBaseline[$key].Scanned) {
continue
}
$batchCount++
if ($batchCount % $batchSettings.BatchSize -eq 0 -and $batchSettings.BatchDelayMs -gt 0) {
Start-Sleep -Milliseconds $batchSettings.BatchDelayMs
}
$modules = $proc.Modules | Where-Object {
$_.FileName -notlike "$env:SystemRoot\*" -and
$_.FileName -notlike "$env:ProgramFiles*"
}
if ($modules.Count -gt 5) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
SuspiciousModules = $modules.Count
Type = "Process with Many Non-System Modules"
Risk = "Medium"
}
}
if ($script:ProcessBaseline.ContainsKey($key)) {
$script:ProcessBaseline[$key].Scanned = $true
}
} catch {
continue
}
}
$now = Get-Date
foreach ($key in $script:ProcessBaseline.Keys) {
if (($now - $script:ProcessBaseline[$key].FirstSeen).TotalSeconds -gt $TickInterval) {
$script:ProcessBaseline[$key].Scanned = $false
$script:ProcessBaseline[$key].FirstSeen = $now
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\MemoryScanning_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName)|$($_.ProcessId)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) memory anomalies"
}
Write-Output "STATS:$ModuleName`:Scanned $($processes.Count) processes"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
Clear-ExpiredCache
return $detections.Count
}
function Start-Module {
$loopSleep = Get-LoopSleep
while ($true) {
try {
# CPU throttling - skip scan if CPU load is too high
if (Test-CPULoadThreshold) {
$cpuLoad = Get-CPULoad
Write-Output "STATS:$ModuleName`:CPU load too high ($cpuLoad%), skipping scan"
Start-Sleep -Seconds ($loopSleep * 2) # Sleep longer when CPU is high
continue
}
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-MemoryScanningOptimized
$script:LastTick = $now
}
Start-Sleep -Seconds $loopSleep
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 120 # Longer sleep on error
}
}
}
# --- NamedPipeMonitoring ---
# Named Pipe Monitoring Module
# Monitors named pipes for malicious activity
$ModuleName = "NamedPipeMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-NamedPipeMonitoring {
$detections = @()
try {
# Get named pipes using WMI
$pipes = Get-CimInstance Win32_NamedPipe -ErrorAction SilentlyContinue
# Check for suspicious named pipes
$suspiciousPatterns = @(
"paexec",
"svchost",
"lsass",
"spoolsv",
"psexec",
"mimikatz",
"impacket"
)
foreach ($pipe in $pipes) {
$pipeNameLower = $pipe.Name.ToLower()
foreach ($pattern in $suspiciousPatterns) {
if ($pipeNameLower -match $pattern) {
$detections += @{
PipeName = $pipe.Name
Pattern = $pattern
Type = "Suspicious Named Pipe Pattern"
Risk = "Medium"
}
break
}
}
# Check for pipes with unusual names (random characters)
if ($pipe.Name -match '^[A-Za-z0-9]{32,}$' -and
$pipe.Name -notmatch 'microsoft|windows|system') {
$detections += @{
PipeName = $pipe.Name
Type = "Named Pipe with Random-Like Name"
Risk = "Low"
}
}
}
# Check for processes creating named pipes
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$procPipes = $pipes | Where-Object {
$_.Instances -gt 0
}
# Check for processes creating many named pipes
$pipeCount = ($procPipes | Measure-Object).Count
if ($pipeCount -gt 10 -and
$proc.ProcessName -notin @("svchost.exe", "spoolsv.exe", "services.exe")) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
PipeCount = $pipeCount
Type = "Process Creating Many Named Pipes"
Risk = "Medium"
}
}
} catch {
continue
}
}
} catch { }
# Check Event Log for named pipe errors
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'} -ErrorAction SilentlyContinue -MaxEvents 200 |
Where-Object {
$_.Message -match 'named.*pipe|pipe.*error|pipe.*failed'
}
$pipeErrors = $events | Where-Object {
$_.LevelDisplayName -eq "Error"
}
if ($pipeErrors.Count -gt 5) {
$detections += @{
EventCount = $pipeErrors.Count
Type = "Excessive Named Pipe Errors"
Risk = "Low"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Information -EventId 2028 `
-Message "NAMED PIPE MONITORING: $($detection.Type) - $($detection.PipeName -or $detection.ProcessName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\NamedPipe_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.PipeName -or $_.ProcessName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) named pipe anomalies"
}
Write-Output "STATS:$ModuleName`:Active pipes=$($pipes.Count)"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-NamedPipeMonitoring
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- CodeInjectionDetection ---
# Code Injection Detection Module
# Detects various code injection techniques
$ModuleName = "CodeInjectionDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-CodeInjectionDetection {
$detections = @()
try {
# Check for processes with unusual memory regions (injection indicator)
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$modules = $proc.Modules
# Check for RWX memory regions (code injection indicator)
# We'll use heuristics since we can't directly query memory protection
# Check for processes with modules in unusual locations
$unusualModules = $modules | Where-Object {
$_.FileName -notlike "$env:SystemRoot\*" -and
$_.FileName -notlike "$env:ProgramFiles*" -and
-not (Test-Path $_.FileName) -and
$_.ModuleName -like "*.dll"
}
if ($unusualModules.Count -gt 5) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
UnusualModules = $unusualModules.Count
Type = "Many Unusual Memory Modules (Code Injection)"
Risk = "High"
}
}
# Check for processes with unusual thread counts (injection indicator)
if ($proc.Threads.Count -gt 50 -and $proc.ProcessName -notin @("chrome.exe", "msedge.exe", "firefox.exe")) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
ThreadCount = $proc.Threads.Count
Type = "Unusual Thread Count (Possible Injection)"
Risk = "Medium"
}
}
} catch {
continue
}
}
# Check for processes using injection APIs
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine
foreach ($proc in $processes) {
if ($proc.CommandLine) {
# Check for code injection API usage
$injectionPatterns = @(
'VirtualAllocEx',
'WriteProcessMemory',
'CreateRemoteThread',
'NtCreateThreadEx',
'RtlCreateUserThread',
'SetThreadContext',
'QueueUserAPC',
'ProcessHollowing',
'DLL.*injection',
'code.*injection'
)
foreach ($pattern in $injectionPatterns) {
if ($proc.CommandLine -match $pattern) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
InjectionPattern = $pattern
Type = "Code Injection API Usage"
Risk = "High"
}
break
}
}
}
}
} catch { }
# Check for processes with unusual handle counts (injection indicator)
try {
$processes = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.HandleCount -gt 1000 }
foreach ($proc in $processes) {
# Exclude legitimate processes
$legitProcesses = @("chrome.exe", "msedge.exe", "firefox.exe", "explorer.exe", "svchost.exe")
if ($proc.ProcessName -notin $legitProcesses) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
HandleCount = $proc.HandleCount
Type = "Unusual Handle Count (Possible Injection)"
Risk = "Medium"
}
}
}
} catch { }
# Check for processes accessing other processes (injection indicator)
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ExecutablePath
foreach ($proc in $processes) {
try {
# Check if process has SeDebugPrivilege (enables injection)
# Indirect check through process properties
if ($proc.ExecutablePath -and (Test-Path $proc.ExecutablePath)) {
$sig = Get-AuthenticodeSignature -FilePath $proc.ExecutablePath -ErrorAction SilentlyContinue
# Unsigned processes accessing system processes
if ($sig.Status -ne "Valid" -and $proc.Name -match 'debug|inject|hollow') {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ExecutablePath = $proc.ExecutablePath
Type = "Suspicious Process Name (Injection Tool)"
Risk = "High"
}
}
}
} catch {
continue
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2038 `
-Message "CODE INJECTION: $($detection.Type) - $($detection.ProcessName) (PID: $($detection.ProcessId))"
}
$logPath = "$env:ProgramData\Antivirus\Logs\CodeInjection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|PID:$($_.ProcessId)|$($_.ProcessName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) code injection indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-CodeInjectionDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- DataExfiltrationDetection ---
# Data Exfiltration Detection Module
# Comprehensive data exfiltration detection beyond DNS
$ModuleName = "DataExfiltrationDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
$BaselineTransfer = @{}
function Invoke-DataExfiltrationDetection {
$detections = @()
try {
# Check for large outbound data transfers
try {
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" -and $_.RemoteAddress -notmatch '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)' }
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$procConns = $connections | Where-Object { $_.OwningProcess -eq $proc.Id }
if ($procConns.Count -gt 0) {
# Check network statistics
$netStats = Get-Counter "\Process($($proc.ProcessName))\IO Data Bytes/sec" -ErrorAction SilentlyContinue
if ($netStats) {
$bytesPerSec = $netStats.CounterSamples[0].CookedValue
# Large outbound transfer
if ($bytesPerSec -gt 1MB) {
$baselineKey = $proc.ProcessName
$baseline = if ($BaselineTransfer.ContainsKey($baselineKey)) { $BaselineTransfer[$baselineKey] } else { 0 }
if ($bytesPerSec -gt $baseline * 2 -and $bytesPerSec -gt 1MB) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
BytesPerSecond = [Math]::Round($bytesPerSec / 1MB, 2)
ConnectionCount = $procConns.Count
Type = "Large Outbound Data Transfer"
Risk = "High"
}
}
$BaselineTransfer[$baselineKey] = $bytesPerSec
}
}
}
} catch {
continue
}
}
} catch { }
# Check for file uploads to cloud storage/suspicious domains
try {
$processes = Get-Process -ErrorAction SilentlyContinue |
Where-Object { $_.ProcessName -match 'curl|wget|powershell|certutil|bitsadmin' }
foreach ($proc in $processes) {
try {
$procObj = Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.Id)" -ErrorAction SilentlyContinue
if ($procObj.CommandLine) {
$uploadPatterns = @(
'upload|PUT|POST',
'dropbox|google.*drive|onedrive|mega|wetransfer',
'pastebin|github|paste.*bin',
'http.*upload|ftp.*put',
'-OutFile.*http',
'Invoke-WebRequest.*-Method.*Put'
)
foreach ($pattern in $uploadPatterns) {
if ($procObj.CommandLine -match $pattern -and
$procObj.CommandLine -notmatch 'download|get|GET') {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
CommandLine = $procObj.CommandLine
Pattern = $pattern
Type = "File Upload to External Service"
Risk = "High"
}
break
}
}
}
} catch {
continue
}
}
} catch { }
# Check for clipboard with large data (possible exfiltration)
try {
Add-Type -AssemblyName System.Windows.Forms
if ([System.Windows.Forms.Clipboard]::ContainsText()) {
$clipboardText = [System.Windows.Forms.Clipboard]::GetText()
if ($clipboardText.Length -gt 50000) {
# Large clipboard content
$detections += @{
ClipboardSize = $clipboardText.Length
Type = "Large Clipboard Content (Possible Exfiltration)"
Risk = "Medium"
}
}
}
} catch { }
# Check for processes accessing many files then connecting externally
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$handles = Get-CimInstance Win32_ProcessHandle -Filter "ProcessId=$($proc.Id)" -ErrorAction SilentlyContinue
$fileHandles = $handles | Where-Object { $_.Name -like "*.txt" -or $_.Name -like "*.doc*" -or $_.Name -like "*.pdf" -or $_.Name -like "*.xls*" }
if ($fileHandles.Count -gt 20) {
$conns = Get-NetTCPConnection -OwningProcess $proc.Id -ErrorAction SilentlyContinue |
Where-Object {
$_.State -eq "Established" -and
$_.RemoteAddress -notmatch '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|127\.)'
}
if ($conns.Count -gt 0) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
FileHandleCount = $fileHandles.Count
ExternalConnections = $conns.Count
Type = "File Access Followed by External Connection"
Risk = "High"
}
}
}
} catch {
continue
}
}
} catch { }
# Check for processes reading sensitive files then connecting externally
try {
$sensitivePaths = @(
"$env:USERPROFILE\Documents",
"$env:USERPROFILE\Desktop",
"$env:APPDATA\..\Local\Credentials"
)
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
foreach ($sensitivePath in $sensitivePaths) {
if (Test-Path $sensitivePath) {
$files = Get-ChildItem -Path $sensitivePath -File -ErrorAction SilentlyContinue |
Where-Object { (Get-Date) - $_.LastAccessTime -lt [TimeSpan]::FromMinutes(5) }
if ($files.Count -gt 5) {
$conns = Get-NetTCPConnection -OwningProcess $proc.Id -ErrorAction SilentlyContinue |
Where-Object { $_.State -eq "Established" -and $_.RemoteAddress -notmatch '^(10\.|192\.168\.)' }
if ($conns.Count -gt 0) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
SensitiveFilesAccessed = $files.Count
ExternalConnections = $conns.Count
Type = "Sensitive File Access Followed by External Connection"
Risk = "Critical"
}
break
}
}
}
}
} catch {
continue
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2040 `
-Message "DATA EXFILTRATION: $($detection.Type) - $($detection.ProcessName -or 'System')"
}
$logPath = "$env:ProgramData\Antivirus\Logs\DataExfiltration_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) data exfiltration indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-DataExfiltrationDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- HoneypotMonitoring ---
# Honeypot Monitoring
# Creates decoy files and processes to detect unauthorized access
$ModuleName = "HoneypotMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 300 }
$HoneypotFiles = @()
$HoneypotPaths = @(
"$env:USERPROFILE\Desktop\passwords.txt",
"$env:USERPROFILE\Documents\credentials.xlsx",
"$env:USERPROFILE\Documents\credit_cards.txt",
"$env:USERPROFILE\Desktop\private_keys.txt",
"$env:APPDATA\credentials.db",
"$env:USERPROFILE\Documents\financial_data.xlsx"
)
function Initialize-Honeypots {
try {
foreach ($honeypotPath in $HoneypotPaths) {
$dir = Split-Path -Parent $honeypotPath
if (-not (Test-Path $dir)) {
New-Item -Path $dir -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
}
if (-not (Test-Path $honeypotPath)) {
# Create honeypot file with fake but realistic content
$content = switch -Wildcard ([System.IO.Path]::GetFileName($honeypotPath)) {
"*password*" { "FAKE_PASSWORD_FILE_DO_NOT_USE`r`nusername: admin`r`npassword: fake_password_123`r`nLastModified: $(Get-Date -Format 'yyyy-MM-dd')" }
"*credential*" { "FAKE_CREDENTIAL_FILE_DO_NOT_USE`r`nAccount: fake_account`r`nPassword: fake_pass_123`r`nCreated: $(Get-Date -Format 'yyyy-MM-dd')" }
"*credit*" { "FAKE_CREDIT_CARD_FILE_DO_NOT_USE`r`nCard: 4111-1111-1111-1111`r`nCVV: 123`r`nExpiry: 12/25" }
"*key*" { "FAKE_PRIVATE_KEY_FILE_DO_NOT_USE`r`n-----BEGIN FAKE RSA PRIVATE KEY-----`r`nFAKE_KEY_DATA`r`n-----END FAKE RSA PRIVATE KEY-----" }
"*financial*" { "FAKE_FINANCIAL_DATA_FILE_DO_NOT_USE`r`nAccount: 123456789`r`nBalance: $0.00`r`nTransaction: None" }
default { "FAKE_FILE_DO_NOT_USE - Created: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" }
}
Set-Content -Path $honeypotPath -Value $content -ErrorAction SilentlyContinue
# Mark as honeypot with file attribute
try {
$file = Get-Item $honeypotPath -ErrorAction Stop
$file.Attributes = $file.Attributes -bor [System.IO.FileAttributes]::Hidden
} catch { }
$script:HoneypotFiles += @{
Path = $honeypotPath
Created = Get-Date
LastAccessed = $null
AccessCount = 0
}
Write-Output "STATS:$ModuleName`:Created honeypot: $honeypotPath"
}
}
} catch {
Write-Output "ERROR:$ModuleName`:Failed to initialize honeypots: $_"
}
}
function Invoke-HoneypotMonitoring {
$detections = @()
try {
# Check honeypot file access
foreach ($honeypot in $script:HoneypotFiles) {
$honeypotPath = $honeypot.Path
if (Test-Path $honeypotPath) {
try {
$file = Get-Item $honeypotPath -ErrorAction Stop
$lastAccess = $file.LastAccessTime
# Check if file was accessed recently
if ($honeypot.LastAccessed -and $lastAccess -gt $honeypot.LastAccessed) {
$honeypot.AccessCount++
# Detect unauthorized access
if ($honeypot.AccessCount -gt 0) {
# Find process that accessed the file
$accessingProcesses = @()
try {
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
try {
$procObj = Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.Id)" -ErrorAction SilentlyContinue
if ($procObj.CommandLine -like "*$([System.IO.Path]::GetFileName($honeypotPath))*") {
$accessingProcesses += $proc.ProcessName
}
} catch { }
}
} catch { }
$detections += @{
HoneypotPath = $honeypotPath
LastAccess = $lastAccess
AccessCount = $honeypot.AccessCount
AccessingProcesses = $accessingProcesses -join ','
Type = "Honeypot File Accessed"
Risk = "Critical"
}
# Log honeypot trigger
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2041 `
-Message "HONEYPOT TRIGGERED: $honeypotPath was accessed - Processes: $($accessingProcesses -join ', ')"
}
$honeypot.LastAccessed = $lastAccess
}
} catch {
# File may have been deleted or moved
if (-not $honeypot.LastAccessed -or ((Get-Date) - $honeypot.Created).TotalMinutes -lt 5) {
$detections += @{
HoneypotPath = $honeypotPath
Type = "Honeypot File Deleted/Moved"
Risk = "Critical"
}
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2041 `
-Message "HONEYPOT DELETED: $honeypotPath was deleted or moved"
# Recreate honeypot
Initialize-Honeypots
}
}
} else {
# File doesn't exist - recreate
Initialize-Honeypots
}
}
# Check for processes accessing multiple honeypots (malware scanning)
if ($detections.Count -gt 2) {
$detections += @{
HoneypotCount = $detections.Count
Type = "Multiple Honeypots Accessed (Systematic Scanning)"
Risk = "Critical"
}
}
if ($detections.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\Honeypot_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.HoneypotPath)|$($_.AccessingProcesses)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) honeypot access events"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
Initialize-Honeypots
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$count = Invoke-HoneypotMonitoring
$script:LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- LateralMovementDetection ---
# Lateral Movement Detection Module
# Detects lateral movement techniques (SMB, RDP, WMI, PsExec, etc.)
$ModuleName = "LateralMovementDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
function Invoke-LateralMovementDetection {
$detections = @()
try {
# Check for SMB shares enumeration/access
try {
$smbEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=5145} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(1) -and
$_.Message -match 'SMB|share|\\\\.*\\'
}
if ($smbEvents.Count -gt 10) {
$detections += @{
EventCount = $smbEvents.Count
Type = "Excessive SMB Share Access (Lateral Movement)"
Risk = "Medium"
}
}
} catch { }
# Check for RDP connections
try {
$rdpEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624} -ErrorAction SilentlyContinue -MaxEvents 200 |
Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(1) -and
$_.Message -match 'RDP|Terminal Services|logon.*type.*10'
}
if ($rdpEvents.Count -gt 5) {
foreach ($event in $rdpEvents) {
$xml = [xml]$event.ToXml()
$subjectUserName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'SubjectUserName'}).'#text'
$targetUserName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'TargetUserName'}).'#text'
if ($subjectUserName -ne $targetUserName) {
$detections += @{
EventId = $event.Id
SubjectUser = $subjectUserName
TargetUser = $targetUserName
TimeCreated = $event.TimeCreated
Type = "RDP Lateral Movement"
Risk = "High"
}
}
}
}
} catch { }
# Check for PsExec usage
try {
$processes = Get-CimInstance Win32_Process |
Where-Object {
$_.Name -eq "psexec.exe" -or
$_.CommandLine -like "*psexec*" -or
$_.CommandLine -like "*paexec*"
}
foreach ($proc in $processes) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Type = "PsExec Lateral Movement Tool"
Risk = "High"
}
}
} catch { }
# Check for WMI remote execution
try {
$wmiEvents = Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-WMI-Activity/Trace'} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(1) -and
($_.Message -match 'remote|Win32_Process.*Create' -or $_.Message -match '\\\\')
}
if ($wmiEvents.Count -gt 5) {
$detections += @{
EventCount = $wmiEvents.Count
Type = "WMI Remote Execution (Lateral Movement)"
Risk = "High"
}
}
} catch { }
# Check for pass-the-hash tools
try {
$pthTools = @("mimikatz", "psexec", "wmiexec", "pth-winexe", "crackmapexec")
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
foreach ($tool in $pthTools) {
if ($proc.ProcessName -like "*$tool*" -or $proc.Path -like "*$tool*") {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
Tool = $tool
Type = "Pass-the-Hash Tool Detected"
Risk = "Critical"
}
}
}
}
} catch { }
# Check for suspicious network connections to internal IPs
try {
$connections = Get-NetTCPConnection -ErrorAction SilentlyContinue |
Where-Object {
$_.State -eq "Established" -and
$_.RemoteAddress -match '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)' -and
$_.RemotePort -in @(445, 3389, 135, 5985, 5986) # SMB, RDP, RPC, WinRM
}
$procGroups = $connections | Group-Object OwningProcess
foreach ($group in $procGroups) {
$uniqueIPs = ($group.Group | Select-Object -Unique RemoteAddress).RemoteAddress.Count
if ($uniqueIPs -gt 5) {
try {
$proc = Get-Process -Id $group.Name -ErrorAction SilentlyContinue
if ($proc) {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
InternalIPCount = $uniqueIPs
ConnectionCount = $group.Count
Type = "Multiple Internal Network Connections (Lateral Movement)"
Risk = "High"
}
}
} catch { }
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2039 `
-Message "LATERAL MOVEMENT: $($detection.Type) - $($detection.ProcessName -or $detection.Tool -or $detection.SubjectUser)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\LateralMovement_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.Tool -or $_.SubjectUser)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) lateral movement indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-LateralMovementDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- ProcessCreationDetection ---
# Process Creation Detection Module
# Detects WMI-based process creation blocking and suspicious process creation patterns
$ModuleName = "ProcessCreationDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
function Invoke-ProcessCreationDetection {
$detections = @()
try {
# Check for WMI process creation filters (blockers)
try {
$filters = Get-CimInstance -Namespace root\subscription -ClassName __EventFilter -ErrorAction SilentlyContinue |
Where-Object {
$_.Query -match 'Win32_ProcessStartTrace|__InstanceCreationEvent.*Win32_Process'
}
foreach ($filter in $filters) {
# Check if filter is bound to a consumer that blocks processes
$bindings = Get-CimInstance -Namespace root\subscription -ClassName __FilterToConsumerBinding -ErrorAction SilentlyContinue |
Where-Object { $_.Filter -like "*$($filter.Name)*" }
if ($bindings) {
foreach ($binding in $bindings) {
$consumer = Get-CimInstance -Namespace root\subscription -ClassName CommandLineEventConsumer -ErrorAction SilentlyContinue |
Where-Object { $_.Name -like "*$($binding.Consumer)*" }
if ($consumer) {
# Check if consumer command blocks process creation
if ($consumer.CommandLineTemplate -match 'taskkill|Stop-Process|Remove-Process' -or
$consumer.CommandLineTemplate -match 'block|deny|prevent') {
$detections += @{
FilterName = $filter.Name
ConsumerName = $consumer.Name
CommandLine = $consumer.CommandLineTemplate
Type = "WMI Process Creation Blocker Detected"
Risk = "High"
}
}
}
}
}
}
} catch { }
# Check Event Log for process creation failures
try {
$events = Get-WinEvent -FilterHashtable @{LogName='System'; Id=7034} -ErrorAction SilentlyContinue -MaxEvents 100 |
Where-Object {
$_.Message -match 'process.*failed|service.*failed.*start|start.*failed'
}
$processFailures = $events | Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(1)
}
if ($processFailures.Count -gt 10) {
$detections += @{
EventCount = $processFailures.Count
Type = "Excessive Process Creation Failures"
Risk = "Medium"
}
}
} catch { }
# Check for processes with unusual creation patterns
try {
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ParentProcessId, CreationDate, ExecutablePath
# Check for processes spawned in rapid succession
$recentProcs = $processes | Where-Object {
(Get-Date) - $_.CreationDate -lt [TimeSpan]::FromMinutes(5)
}
# Group by parent process
$parentGroups = $recentProcs | Group-Object ParentProcessId
foreach ($group in $parentGroups) {
if ($group.Count -gt 20) {
try {
$parent = Get-CimInstance Win32_Process -Filter "ProcessId=$($group.Name)" -ErrorAction SilentlyContinue
if ($parent) {
$detections += @{
ParentProcessId = $group.Name
ParentProcessName = $parent.Name
ChildCount = $group.Count
Type = "Rapid Process Creation Spawning"
Risk = "Medium"
}
}
} catch { }
}
}
} catch { }
# Check for processes with unusual parent relationships
try {
$suspiciousParents = @{
"winlogon.exe" = @("cmd.exe", "powershell.exe", "wmic.exe")
"services.exe" = @("cmd.exe", "powershell.exe", "rundll32.exe")
"explorer.exe" = @("notepad.exe", "calc.exe")
}
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, ParentProcessId
foreach ($proc in $processes) {
if ($proc.ParentProcessId) {
try {
$parent = Get-CimInstance Win32_Process -Filter "ProcessId=$($proc.ParentProcessId)" -ErrorAction SilentlyContinue
if ($parent) {
foreach ($suspParent in $suspiciousParents.Keys) {
if ($parent.Name -eq $suspParent -and
$proc.Name -in $suspiciousParents[$suspParent]) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
ParentProcessId = $proc.ParentProcessId
ParentProcessName = $parent.Name
Type = "Suspicious Parent-Child Process Relationship"
Risk = "Medium"
}
}
}
}
} catch { }
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2035 `
-Message "PROCESS CREATION: $($detection.Type) - $($detection.ProcessName -or $detection.FilterName -or $detection.ParentProcessName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\ProcessCreation_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.FilterName)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) process creation anomalies"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-ProcessCreationDetection
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- QuarantineManagement ---
# Quarantine Management Module
# Manages file quarantine operations and tracks quarantined files
$ModuleName = "QuarantineManagement"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 300 }
$QuarantinePath = "$env:ProgramData\Antivirus\Quarantine"
function Initialize-Quarantine {
try {
if (-not (Test-Path $QuarantinePath)) {
New-Item -Path $QuarantinePath -ItemType Directory -Force | Out-Null
}
# Create quarantine log
$quarantineLog = Join-Path $QuarantinePath "quarantine_log.txt"
if (-not (Test-Path $quarantineLog)) {
"Timestamp|FilePath|QuarantinePath|Reason|FileHash" | Add-Content -Path $quarantineLog
}
return $true
} catch {
Write-Output "ERROR:$ModuleName`:Failed to initialize quarantine: $_"
return $false
}
}
function Invoke-QuarantineFile {
param(
[string]$FilePath,
[string]$Reason = "Threat Detected",
[string]$Source = "Unknown"
)
try {
if (-not (Test-Path $FilePath)) {
Write-Output "ERROR:$ModuleName`:File not found: $FilePath"
return $false
}
$fileName = Split-Path -Leaf $FilePath
$fileDir = Split-Path -Parent $FilePath
$fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)
$fileExt = [System.IO.Path]::GetExtension($fileName)
# Generate unique quarantine filename with timestamp
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$quarantineFileName = "${fileBaseName}_${timestamp}${fileExt}"
$quarantineFilePath = Join-Path $QuarantinePath $quarantineFileName
# Calculate file hash before moving
$fileHash = $null
try {
$hashObj = Get-FileHash -Path $FilePath -Algorithm SHA256 -ErrorAction SilentlyContinue
$fileHash = $hashObj.Hash
} catch { }
# Move file to quarantine
Move-Item -Path $FilePath -Destination $quarantineFilePath -Force -ErrorAction Stop
# Log quarantine action
$quarantineLog = Join-Path $QuarantinePath "quarantine_log.txt"
$logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$FilePath|$quarantineFilePath|$Reason|$fileHash"
Add-Content -Path $quarantineLog -Value $logEntry
# Write Event Log
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2034 `
-Message "QUARANTINE: File quarantined: $fileName - Reason: $Reason - Source: $Source"
Write-Output "STATS:$ModuleName`:File quarantined: $fileName"
return $true
} catch {
Write-Output "ERROR:$ModuleName`:Failed to quarantine $FilePath`: $_"
return $false
}
}
function Invoke-QuarantineManagement {
$stats = @{
QuarantinedFiles = 0
QuarantineSize = 0
OldFiles = 0
}
try {
# Initialize quarantine if needed
if (-not (Test-Path $QuarantinePath)) {
Initialize-Quarantine
}
# Check quarantine status
if (Test-Path $QuarantinePath) {
$quarantinedFiles = Get-ChildItem -Path $QuarantinePath -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne "quarantine_log.txt" }
$stats.QuarantinedFiles = $quarantinedFiles.Count
# Calculate total quarantine size
foreach ($file in $quarantinedFiles) {
$stats.QuarantineSize += $file.Length
}
# Check for old quarantined files (older than 90 days)
$cutoffDate = (Get-Date).AddDays(-90)
$oldFiles = $quarantinedFiles | Where-Object { $_.LastWriteTime -lt $cutoffDate }
$stats.OldFiles = $oldFiles.Count
# Optionally remove old files
if ($stats.OldFiles -gt 0 -and $stats.QuarantineSize -gt 1GB) {
foreach ($oldFile in $oldFiles) {
try {
Remove-Item -Path $oldFile.FullName -Force -ErrorAction SilentlyContinue
Write-Output "STATS:$ModuleName`:Removed old quarantined file: $($oldFile.Name)"
} catch { }
}
}
}
# Check quarantine log integrity
$quarantineLog = Join-Path $QuarantinePath "quarantine_log.txt"
if (Test-Path $quarantineLog) {
$logEntries = Get-Content -Path $quarantineLog -ErrorAction SilentlyContinue
if ($logEntries.Count -gt 10000) {
# Archive old log entries
$archivePath = Join-Path $QuarantinePath "quarantine_log_$(Get-Date -Format 'yyyy-MM-dd').txt"
Copy-Item -Path $quarantineLog -Destination $archivePath -ErrorAction SilentlyContinue
"Timestamp|FilePath|QuarantinePath|Reason|FileHash" | Set-Content -Path $quarantineLog
}
}
Write-Output "STATS:$ModuleName`:Quarantined=$($stats.QuarantinedFiles), Size=$([Math]::Round($stats.QuarantineSize/1MB, 2))MB, Old=$($stats.OldFiles)"
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $stats
}
function Start-Module {
Initialize-Quarantine
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$stats = Invoke-QuarantineManagement
$LastTick = $now
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# Export quarantine function for use by other modules
if ($ModuleConfig) {
$ModuleConfig.QuarantineFunction = ${function:Invoke-QuarantineFile}
}
# --- PrivacyForgeSpoofing ---
# PrivacyForge Spoofing Module
# Identity and Fingerprint Spoofing - Generates fake identity data to prevent browser fingerprinting
#Requires -Version 5.1
$ModuleName = "PrivacyForgeSpoofing"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { (Get-TickInterval $ModuleName) }
# PrivacyForge Configuration
$Script:Config = @{
BaseDir = "$env:ProgramData\Antivirus"
LogDir = "$env:ProgramData\Antivirus\Logs"
RotationIntervalSeconds = 3600 # 1 hour
DataThreshold = 50 # Rotate after this much simulated data collection
EnableClipboardSpoofing = $false # Disabled by default - can overwrite user clipboard
EnableNetworkSpoofing = $true
DebugMode = $false
}
# State variables
$Script:PrivacyForgeIdentity = @{}
$Script:PrivacyForgeDataCollected = 0
$Script:PrivacyForgeLastRotation = $null
# ===================== Logging =====================
# Uses standard Write-Log from imported modules
# ===================== Identity Generation =====================
function Invoke-PrivacyForgeGenerateIdentity {
<#
.SYNOPSIS
Generates a fake identity profile for spoofing purposes
#>
$firstNames = @("John", "Jane", "Michael", "Sarah", "David", "Emily", "James", "Jessica",
"Robert", "Amanda", "William", "Ashley", "Richard", "Melissa", "Joseph", "Nicole",
"Thomas", "Jennifer", "Charles", "Elizabeth", "Christopher", "Samantha", "Daniel", "Rebecca")
$lastNames = @("Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
"Rodriguez", "Martinez", "Hernandez", "Lopez", "Wilson", "Anderson", "Thomas", "Taylor",
"Moore", "Jackson", "Martin", "Lee", "Thompson", "White", "Harris", "Clark")
$domains = @("gmail.com", "yahoo.com", "outlook.com", "hotmail.com", "protonmail.com", "icloud.com", "aol.com")
$cities = @("New York", "Los Angeles", "Chicago", "Houston", "Phoenix", "Philadelphia",
"San Antonio", "San Diego", "Dallas", "San Jose", "Austin", "Jacksonville",
"Fort Worth", "Columbus", "Charlotte", "Seattle", "Denver", "Boston")
$countries = @("United States", "Canada", "United Kingdom", "Australia", "Germany", "France", "Spain", "Italy", "Netherlands", "Sweden")
$languages = @("en-US", "en-GB", "fr-FR", "es-ES", "de-DE", "it-IT", "pt-BR", "nl-NL", "sv-SE")
$interests = @("tech", "gaming", "news", "sports", "music", "movies", "travel", "food",
"fitness", "books", "photography", "cooking", "art", "science", "finance")
$firstName = Get-Random -InputObject $firstNames
$lastName = Get-Random -InputObject $lastNames
$username = "$firstName$lastName" + (Get-Random -Minimum 100 -Maximum 9999)
$domain = Get-Random -InputObject $domains
$email = "$username@$domain".ToLower()
$userAgents = @(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
)
$resolutions = @("1920x1080", "2560x1440", "1366x768", "1536x864", "1440x900", "1280x720", "3840x2160")
return @{
"name" = "$firstName $lastName"
"email" = $email
"username" = $username
"location" = Get-Random -InputObject $cities
"country" = Get-Random -InputObject $countries
"user_agent" = Get-Random -InputObject $userAgents
"screen_resolution" = Get-Random -InputObject $resolutions
"interests" = (Get-Random -InputObject $interests -Count 4)
"device_id" = [System.Guid]::NewGuid().ToString()
"mac_address" = "{0:X2}-{1:X2}-{2:X2}-{3:X2}-{4:X2}-{5:X2}" -f `
(Get-Random -Minimum 0 -Maximum 256), (Get-Random -Minimum 0 -Maximum 256), `
(Get-Random -Minimum 0 -Maximum 256), (Get-Random -Minimum 0 -Maximum 256), `
(Get-Random -Minimum 0 -Maximum 256), (Get-Random -Minimum 0 -Maximum 256)
"language" = Get-Random -InputObject $languages
"timezone" = (Get-TimeZone).Id
"timestamp" = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
"canvas_hash" = [System.Guid]::NewGuid().ToString("N").Substring(0, 16)
"webgl_vendor" = Get-Random -InputObject @("Google Inc.", "Intel Inc.", "NVIDIA Corporation", "AMD")
"webgl_renderer" = Get-Random -InputObject @("ANGLE (Intel, Intel(R) UHD Graphics 630)", "ANGLE (NVIDIA, GeForce GTX 1080)", "ANGLE (AMD, Radeon RX 580)")
"platform" = Get-Random -InputObject @("Win32", "Win64", "MacIntel", "Linux x86_64")
"cpu_cores" = Get-Random -InputObject @(4, 6, 8, 12, 16)
"memory_gb" = Get-Random -InputObject @(8, 16, 32, 64)
}
}
function Invoke-PrivacyForgeRotateIdentity {
<#
.SYNOPSIS
Rotates to a new fake identity
#>
$Script:PrivacyForgeIdentity = Invoke-PrivacyForgeGenerateIdentity
$Script:PrivacyForgeDataCollected = 0
$Script:PrivacyForgeLastRotation = Get-Date
Write-Log "INFO" "Identity rotated - Name: $($Script:PrivacyForgeIdentity.name), Username: $($Script:PrivacyForgeIdentity.username)"
# Output identity rotation in standard format
Write-Output "SPOOF:$ModuleName`:Identity rotated - $($Script:PrivacyForgeIdentity.name)"
}
# ===================== Spoofing Functions =====================
function Invoke-PrivacyForgeSpoofSoftwareMetadata {
<#
.SYNOPSIS
Sends spoofed HTTP headers to confuse trackers
#>
if (-not $Script:Config.EnableNetworkSpoofing) { return }
try {
$headers = @{
"User-Agent" = $Script:PrivacyForgeIdentity.user_agent
"Cookie" = "session_id=$(Get-Random -Minimum 1000 -Maximum 9999); fake_id=$([System.Guid]::NewGuid().ToString())"
"X-Device-ID" = $Script:PrivacyForgeIdentity.device_id
"Accept-Language" = $Script:PrivacyForgeIdentity.language
"X-Timezone" = $Script:PrivacyForgeIdentity.timezone
"X-Screen-Resolution" = $Script:PrivacyForgeIdentity.screen_resolution
}
# Send to a test endpoint (non-blocking, fire and forget)
$null = Start-Job -ScriptBlock {
param($headers)
try {
Invoke-WebRequest -Uri "https://httpbin.org/headers" -Headers $headers -TimeoutSec 5 -UseBasicParsing -ErrorAction SilentlyContinue | Out-Null
} catch {}
} -ArgumentList $headers
Write-Log "DEBUG" "Sent spoofed software metadata headers"
} catch {
Write-Log "WARN" "Error spoofing software metadata - $_"
}
}
function Invoke-PrivacyForgeSpoofGameTelemetry {
<#
.SYNOPSIS
Generates fake game telemetry data
#>
try {
$fakeTelemetry = @{
"player_id" = [System.Guid]::NewGuid().ToString()
"hardware_id" = -join ((1..32) | ForEach-Object { '{0:X}' -f (Get-Random -Maximum 16) })
"latency" = Get-Random -Minimum 20 -Maximum 200
"game_version" = "$(Get-Random -Minimum 1 -Maximum 5).$(Get-Random -Minimum 0 -Maximum 9).$(Get-Random -Minimum 0 -Maximum 99)"
"fps" = Get-Random -Minimum 30 -Maximum 144
"session_id" = [System.Guid]::NewGuid().ToString()
"playtime_minutes" = Get-Random -Minimum 10 -Maximum 500
}
Write-Log "DEBUG" "Spoofed game telemetry - Player ID: $($fakeTelemetry.player_id)"
} catch {
Write-Log "WARN" "Error spoofing game telemetry - $_"
}
}
function Invoke-PrivacyForgeSpoofSensors {
<#
.SYNOPSIS
Generates random sensor data to confuse fingerprinting
#>
try {
# Generate sensor data for fingerprinting confusion
# Data is generated but not used - the purpose is to create noise for trackers
[math]::Round((Get-Random -Minimum -1000 -Maximum 1000) / 100.0, 2) | Out-Null # accelerometer
[math]::Round((Get-Random -Minimum -18000 -Maximum 18000) / 100.0, 2) | Out-Null # gyroscope
[math]::Round((Get-Random -Minimum -5000 -Maximum 5000) / 100.0, 2) | Out-Null # magnetometer
Get-Random -Minimum 0 -Maximum 1000 | Out-Null # light sensor
Get-Random -InputObject @(0, 5, 10) | Out-Null # proximity sensor
[math]::Round((Get-Random -Minimum 1500 -Maximum 3500) / 100.0, 1) | Out-Null # ambient temp
[math]::Round((Get-Random -Minimum 2000 -Maximum 4000) / 100.0, 1) | Out-Null # battery temp
Write-Log "DEBUG" "Spoofed sensor data"
} catch {
Write-Log "WARN" "Error spoofing sensors - $_"
}
}
function Invoke-PrivacyForgeSpoofSystemMetrics {
<#
.SYNOPSIS
Generates fake system performance metrics
#>
try {
$fakeMetrics = @{
"cpu_usage" = [math]::Round((Get-Random -Minimum 500 -Maximum 5000) / 100.0, 1)
"memory_usage" = [math]::Round((Get-Random -Minimum 3000 -Maximum 8500) / 100.0, 1)
"battery_level" = Get-Random -Minimum 20 -Maximum 100
"charging" = (Get-Random -InputObject @($true, $false))
"disk_usage" = [math]::Round((Get-Random -Minimum 2000 -Maximum 9000) / 100.0, 1)
"network_latency" = Get-Random -Minimum 5 -Maximum 150
"uptime_hours" = Get-Random -Minimum 1 -Maximum 720
}
Write-Log "DEBUG" "Spoofed system metrics - CPU: $($fakeMetrics.cpu_usage)%, Memory: $($fakeMetrics.memory_usage)%"
} catch {
Write-Log "WARN" "Error spoofing system metrics - $_"
}
}
function Invoke-PrivacyForgeSpoofClipboard {
<#
.SYNOPSIS
Overwrites clipboard with fake data (disabled by default)
#>
if (-not $Script:Config.EnableClipboardSpoofing) { return }
try {
$fakeContent = "PrivacyForge: $(Get-Random -Minimum 100000 -Maximum 999999) - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Set-Clipboard -Value $fakeContent -ErrorAction SilentlyContinue
Write-Log "DEBUG" "Spoofed clipboard content"
} catch {
Write-Log "WARN" "Error spoofing clipboard - $_"
}
}
# ===================== Main Detection Function =====================
function Invoke-PrivacyForgeSpoofing {
<#
.SYNOPSIS
Main spoofing tick function - manages identity rotation and spoofing operations
#>
# Initialize on first run
if (-not $Script:PrivacyForgeLastRotation) {
$Script:PrivacyForgeLastRotation = Get-Date
Invoke-PrivacyForgeRotateIdentity
}
try {
# Check if rotation is needed
$timeSinceRotation = (Get-Date) - $Script:PrivacyForgeLastRotation
$shouldRotate = $false
if ($timeSinceRotation.TotalSeconds -ge $Script:Config.RotationIntervalSeconds) {
$shouldRotate = $true
Write-Log "INFO" "Time-based rotation triggered"
}
if ($Script:PrivacyForgeDataCollected -ge $Script:Config.DataThreshold) {
$shouldRotate = $true
Write-Log "INFO" "Data threshold reached ($Script:PrivacyForgeDataCollected/$($Script:Config.DataThreshold))"
}
if ($shouldRotate -or (-not $Script:PrivacyForgeIdentity.ContainsKey("name"))) {
Invoke-PrivacyForgeRotateIdentity
}
# Simulate data collection increment
$Script:PrivacyForgeDataCollected += Get-Random -Minimum 1 -Maximum 6
# Perform spoofing operations
Invoke-PrivacyForgeSpoofSoftwareMetadata
Invoke-PrivacyForgeSpoofGameTelemetry
Invoke-PrivacyForgeSpoofSensors
Invoke-PrivacyForgeSpoofSystemMetrics
Invoke-PrivacyForgeSpoofClipboard
Write-Log "INFO" "Spoofing active - Data collected: $Script:PrivacyForgeDataCollected/$($Script:Config.DataThreshold)"
# Output spoofing activity in standard format
Write-Output "SPOOF:$ModuleName`:Identity rotation active - Data: $Script:PrivacyForgeDataCollected/$($Script:Config.DataThreshold)"
} catch {
Write-Log "ERROR" "Error in main spoofing loop - $_"
}
}
# ===================== Module Start Function =====================
function Start-Module {
Write-Log "INFO" "========================================"
Write-Log "INFO" "PrivacyForge Spoofing Module Starting"
Write-Log "INFO" "Tick Interval: $TickInterval seconds"
Write-Log "INFO" "Rotation Interval: $($Script:Config.RotationIntervalSeconds)s"
Write-Log "INFO" "Data Threshold: $($Script:Config.DataThreshold)"
Write-Log "INFO" "Clipboard Spoofing: $($Script:Config.EnableClipboardSpoofing)"
Write-Log "INFO" "Network Spoofing: $($Script:Config.EnableNetworkSpoofing)"
Write-Log "INFO" "========================================"
# Initial identity generation
Invoke-PrivacyForgeRotateIdentity
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-PrivacyForgeSpoofing
}
Start-Sleep -Seconds (Get-LoopSleep)
} catch {
Write-Output "ERROR:$ModuleName`':$_"
Start-Sleep -Seconds 10
}
}
}
# Start module if not running with configuration
# --- PasswordManagement ---
# Password Management Module
# Monitors password policies and storage
$ModuleName = "PasswordManagement"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 300 }
function Invoke-PasswordManagement {
$detections = @()
try {
# Check password policy
try {
$passwordPolicy = Get-LocalUser | ForEach-Object {
$_.PasswordNeverExpires
}
$expiredPasswords = $passwordPolicy | Where-Object { $_ -eq $true }
if ($expiredPasswords.Count -gt 0) {
$detections += @{
ExpiredPasswordCount = $expiredPasswords.Count
Type = "Accounts with Non-Expiring Passwords"
Risk = "Medium"
}
}
} catch { }
# Check for weak passwords (indirectly through failed logon attempts)
try {
$securityEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} -ErrorAction SilentlyContinue -MaxEvents 100
$failedLogons = $securityEvents | Where-Object {
(Get-Date) - $_.TimeCreated -lt [TimeSpan]::FromHours(24)
}
if ($failedLogons.Count -gt 50) {
$detections += @{
FailedLogonCount = $failedLogons.Count
Type = "Excessive Failed Logon Attempts - Possible Weak Passwords"
Risk = "Medium"
}
}
} catch { }
# Check for password storage in plain text
try {
$searchPaths = @(
"$env:USERPROFILE\Desktop",
"$env:USERPROFILE\Documents",
"$env:USERPROFILE\Downloads",
"$env:TEMP"
)
$passwordFiles = @()
foreach ($path in $searchPaths) {
if (Test-Path $path) {
try {
$files = Get-ChildItem -Path $path -Filter "*.txt","*.log","*.csv" -File -ErrorAction SilentlyContinue |
Select-Object -First 50
foreach ($file in $files) {
try {
$content = Get-Content $file.FullName -Raw -ErrorAction SilentlyContinue
if ($content -match '(?i)(password|pwd|passwd)\s*[:=]\s*\S+') {
$passwordFiles += @{
File = $file.FullName
Type = "Plain Text Password Storage"
Risk = "High"
}
}
} catch { }
}
} catch { }
}
}
$detections += $passwordFiles
} catch { }
# Check for credential dumping tools
try {
$credDumpTools = @("mimikatz", "lsadump", "pwdump", "fgdump", "hashdump")
$processes = Get-Process -ErrorAction SilentlyContinue
foreach ($proc in $processes) {
foreach ($tool in $credDumpTools) {
if ($proc.ProcessName -like "*$tool*" -or
$proc.Path -like "*$tool*") {
$detections += @{
ProcessId = $proc.Id
ProcessName = $proc.ProcessName
Tool = $tool
Type = "Credential Dumping Tool"
Risk = "Critical"
}
}
}
}
} catch { }
# Check for SAM database access
try {
$securityEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4656,4663} -ErrorAction SilentlyContinue -MaxEvents 500 |
Where-Object { $_.Message -match 'SAM|SECURITY|SYSTEM' -and $_.Message -match 'Read|Write' }
if ($securityEvents.Count -gt 0) {
foreach ($event in $securityEvents) {
$detections += @{
EventId = $event.Id
TimeCreated = $event.TimeCreated
Message = $event.Message
Type = "SAM Database Access Attempt"
Risk = "High"
}
}
}
} catch { }
# Check for LSA secrets access
try {
$lsaEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4656} -ErrorAction SilentlyContinue -MaxEvents 200 |
Where-Object { $_.Message -match 'LSA|Local.*Security.*Authority' }
if ($lsaEvents.Count -gt 5) {
$detections += @{
EventCount = $lsaEvents.Count
Type = "Excessive LSA Access Attempts"
Risk = "High"
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2030 `
-Message "PASSWORD MANAGEMENT: $($detection.Type) - $($detection.ProcessName -or $detection.File -or $detection.Tool)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\PasswordManagement_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.Risk)|$($_.ProcessName -or $_.File)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) password management issues"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-PasswordManagement
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- IdsDetection ---
# IDS Detection
# Command-line IDS patterns (meterpreter, certutil -urlcache, etc.)
$ModuleName = "IdsDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 60 }
$Patterns = @(
@{ Pattern = "meterpreter"; Desc = "Metasploit meterpreter" }
@{ Pattern = "certutil\s+-urlcache"; Desc = "Certutil download" }
@{ Pattern = "bitsadmin\s+/transfer"; Desc = "Bitsadmin download" }
@{ Pattern = "powershell\s+-enc"; Desc = "Base64 encoded PS" }
@{ Pattern = "powershell\s+-w\s+hidden"; Desc = "Hidden window PS" }
@{ Pattern = "invoke-expression"; Desc = "IEX usage" }
@{ Pattern = "iex\s*\("; Desc = "IEX usage" }
@{ Pattern = "downloadstring"; Desc = "DownloadString" }
@{ Pattern = "downloadfile"; Desc = "DownloadFile" }
@{ Pattern = "webclient"; Desc = "WebClient" }
@{ Pattern = "net\.webclient"; Desc = "Net.WebClient" }
@{ Pattern = "bypass.*-executionpolicy"; Desc = "Execution policy bypass" }
@{ Pattern = "wmic\s+process\s+call\s+create"; Desc = "WMI process creation" }
@{ Pattern = "reg\s+add.*HKLM.*Run"; Desc = "Registry Run key" }
@{ Pattern = "schtasks\s+/create"; Desc = "Scheduled task creation" }
@{ Pattern = "netsh\s+firewall"; Desc = "Firewall modification" }
@{ Pattern = "sc\s+create"; Desc = "Service creation" }
@{ Pattern = "rundll32.*\.dll"; Desc = "Rundll32 DLL" }
@{ Pattern = "regsvr32\s+.*/s"; Desc = "Regsvr32 silent" }
@{ Pattern = "mshta\s+http"; Desc = "Mshta remote script" }
)
function Invoke-IdsScan {
$detections = @()
try {
$processes = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Select-Object ProcessId, Name, CommandLine
foreach ($proc in $processes) {
$cmd = if ($proc.CommandLine) { $proc.CommandLine } else { "" }
foreach ($p in $Patterns) {
if ($cmd -match $p.Pattern) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
Pattern = $p.Pattern
Description = $p.Desc
CommandLine = $cmd.Substring(0, [Math]::Min(500, $cmd.Length))
}
break
}
}
}
if ($detections.Count -gt 0) {
foreach ($d in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2095 -Message "IDS: $($d.Description) - $($d.ProcessName) PID:$($d.ProcessId)" -ErrorAction SilentlyContinue
}
$logPath = "$env:ProgramData\Antivirus\Logs\ids_detection_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Description)|$($_.ProcessName)|PID:$($_.ProcessId)" | Add-Content -Path $logPath }
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) IDS matches"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-IdsScan
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- CredentialDumpDetection ---
# Credential Dumping Detection Module
# Detects attempts to dump credentials from memory
$ModuleName = "CredentialDumpDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 20 }
$CredentialDumpTools = @(
"mimikatz", "sekurlsa", "lsadump", "wce", "fgdump",
"pwdump", "hashdump", "gsecdump", "cachedump",
"procDump", "dumpert", "nanodump", "mslsa"
)
function Invoke-CredentialDumpScan {
$detections = @()
try {
# Check running processes
$processes = Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine, ExecutablePath
foreach ($proc in $processes) {
$procNameLower = $proc.Name.ToLower()
$cmdLineLower = if ($proc.CommandLine) { $proc.CommandLine.ToLower() } else { "" }
$pathLower = if ($proc.ExecutablePath) { $proc.ExecutablePath.ToLower() } else { "" }
# Check for credential dumping tools
foreach ($tool in $CredentialDumpTools) {
if ($procNameLower -like "*$tool*" -or
$cmdLineLower -like "*$tool*" -or
$pathLower -like "*$tool*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Tool = $tool
Risk = "Critical"
}
break
}
}
# Check for suspicious LSASS access
if ($proc.Name -match "lsass|sam|security") {
try {
$lsassProc = Get-Process -Name "lsass" -ErrorAction SilentlyContinue
if ($lsassProc) {
# Check if process has handle to LSASS
$handles = Get-CimInstance Win32_ProcessHandle -Filter "ProcessId=$($proc.ProcessId)" -ErrorAction SilentlyContinue
if ($handles) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
Type = "LSASS Memory Access"
Risk = "High"
}
}
}
} catch { }
}
}
# Check for credential dumping API calls in Event Log
try {
$securityEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4656,4663} -ErrorAction SilentlyContinue -MaxEvents 500
foreach ($event in $securityEvents) {
if ($event.Message -match 'lsass|sam|security' -and
$event.Message -match 'Read|Write') {
$xml = [xml]$event.ToXml()
$objectName = ($xml.Event.EventData.Data | Where-Object {$_.Name -eq 'ObjectName'}).'#text'
if ($objectName -match 'SAM|SECURITY|SYSTEM') {
$detections += @{
EventId = $event.Id
Type = "Registry Credential Access"
ObjectName = $objectName
Risk = "High"
}
}
}
}
} catch { }
if ($detections.Count -gt 0) {
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2005 `
-Message "CREDENTIAL DUMP DETECTED: $($detection.ProcessName -or $detection.Type) - $($detection.Tool -or $detection.ObjectName)"
}
$logPath = "$env:ProgramData\Antivirus\Logs\CredentialDump_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.ProcessName -or $_.Type)|$($_.Tool -or $_.ObjectName)|$($_.Risk)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) credential dump attempts"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-CredentialDumpScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- LOLBinDetection ---
# Living-Off-The-Land Binary Detection
# Detects legitimate tools used maliciously
$ModuleName = "LOLBinDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 30 }
$LOLBinPatterns = @{
"cmd.exe" = @("\/c.*certutil|powershell|bitsadmin|regsvr32")
"powershell.exe" = @("-nop.*-w.*hidden|-EncodedCommand|-ExecutionPolicy.*Bypass")
"wmic.exe" = @("process.*call.*create")
"mshta.exe" = @("http|https|\.hta")
"rundll32.exe" = @("javascript:|\.dll.*\,")
"regsvr32.exe" = @("\/s.*\/i.*http|\.sct")
"certutil.exe" = @("-urlcache|-decode|\.exe")
"bitsadmin.exe" = @("/transfer|/rawreturn")
"schtasks.exe" = @("/create.*/tn.*http|/create.*/tr.*powershell")
"msbuild.exe" = @("\.xml.*http|\.csproj.*http")
"csc.exe" = @("\.cs.*http")
}
$DetectionCount = 0
function Get-RunningProcesses {
try {
return Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine, CreationDate, ParentProcessId
} catch {
return @()
}
}
function Test-LOLBinCommandLine {
param(
[string]$ProcessName,
[string]$CommandLine
)
if ([string]::IsNullOrEmpty($CommandLine)) { return $null }
$processNameLower = $ProcessName.ToLower()
$cmdLineLower = $CommandLine.ToLower()
if ($LOLBinPatterns.ContainsKey($processNameLower)) {
foreach ($pattern in $LOLBinPatterns[$processNameLower]) {
if ($cmdLineLower -match $pattern) {
return @{
Process = $ProcessName
CommandLine = $CommandLine
Pattern = $pattern
Risk = "High"
}
}
}
}
# Additional heuristics
if ($cmdLineLower -match 'powershell.*-encodedcommand' -and
$cmdLineLower.Length -gt 500) {
return @{
Process = $ProcessName
CommandLine = $CommandLine
Pattern = "Long encoded PowerShell command"
Risk = "High"
}
}
if ($cmdLineLower -match '(http|https)://[^\s]+' -and
$processNameLower -in @('cmd.exe','rundll32.exe','mshta.exe')) {
return @{
Process = $ProcessName
CommandLine = $CommandLine
Pattern = "Network download from LOLBin"
Risk = "High"
}
}
return $null
}
function Invoke-LOLBinScan {
$detections = @()
$processes = Get-RunningProcesses
foreach ($proc in $processes) {
$result = Test-LOLBinCommandLine -ProcessName $proc.Name -CommandLine $proc.CommandLine
if ($result) {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
CommandLine = $proc.CommandLine
Pattern = $result.Pattern
Risk = $result.Risk
ParentProcessId = $proc.ParentProcessId
CreationDate = $proc.CreationDate
}
}
}
if ($detections.Count -gt 0) {
$script:DetectionCount += $detections.Count
foreach ($detection in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Warning -EventId 2002 `
-Message "LOLBIN DETECTED: $($detection.ProcessName) (PID: $($detection.ProcessId)) - $($detection.Pattern)"
# Log details
$logPath = "$env:ProgramData\Antivirus\Logs\LOLBinDetection_$(Get-Date -Format 'yyyy-MM-dd').log"
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|PID:$($detection.ProcessId)|$($detection.ProcessName)|$($detection.Pattern)|$($detection.CommandLine)" |
Add-Content -Path $logPath
}
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) LOLBin instances"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $LastTick).TotalSeconds -ge $TickInterval) {
$count = Invoke-LOLBinScan
$LastTick = $now
Write-Output "STATS:$ModuleName`:Scanned processes, Detections=$count"
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- MemoryAcquisitionDetection ---
# Memory Acquisition Detection
# Detects WinPmem, pmem, FTK Imager, etc.
$ModuleName = "MemoryAcquisitionDetection"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 90 }
$ProcessPatterns = @("winpmem", "pmem", "osxpmem", "aff4imager", "winpmem_mini", "memdump", "rawdump")
$CmdPatterns = @("winpmem", "pmem", "\.\pmem", "/dev/pmem", ".aff4", "-o .raw", "-o .aff4", "image.raw", "memory.raw", "physical memory", "memory acquisition", "physicalmemory")
function Invoke-MemoryAcquisitionScan {
$detections = @()
try {
$processes = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Select-Object ProcessId, Name, CommandLine, ExecutablePath
foreach ($proc in $processes) {
$name = if ($proc.Name) { $proc.Name.ToLower() } else { "" }
$cmd = (if ($proc.CommandLine) { $proc.CommandLine } else { "" }) + " " + (if ($proc.ExecutablePath) { $proc.ExecutablePath } else { "" })
foreach ($pat in $ProcessPatterns) {
if ($name -like "*$pat*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
Pattern = $pat
Type = "Memory Acquisition Tool"
Risk = "Critical"
}
break
}
}
if ($detections[-1].ProcessId -eq $proc.ProcessId) { continue }
foreach ($pat in $CmdPatterns) {
if ($cmd -like "*$pat*") {
$detections += @{
ProcessId = $proc.ProcessId
ProcessName = $proc.Name
Pattern = "cmd:$pat"
Type = "Memory Acquisition (cmd)"
Risk = "Critical"
}
break
}
}
}
if ($detections.Count -gt 0) {
foreach ($d in $detections) {
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Error -EventId 2093 -Message "MEMORY ACQUISITION: $($d.Pattern) - $($d.ProcessName) (PID: $($d.ProcessId))" -ErrorAction SilentlyContinue
}
$logPath = "$env:ProgramData\Antivirus\Logs\memory_acquisition_detections_$(Get-Date -Format 'yyyy-MM-dd').log"
$detections | ForEach-Object { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|$($_.Type)|$($_.ProcessName)|PID:$($_.ProcessId)" | Add-Content -Path $logPath }
Write-Output "DETECTION:$ModuleName`:Found $($detections.Count) memory acquisition indicators"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
return $detections.Count
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-MemoryAcquisitionScan | Out-Null
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- MobileDeviceMonitoring ---
# Mobile Device Monitoring
# Win32_PnPEntity for portable/USB/MTP devices
$ModuleName = "MobileDeviceMonitoring"
$LastTick = Get-Date
$TickInterval = if ($ModuleConfig.TickInterval) { $ModuleConfig.TickInterval } else { 90 }
$DeviceClasses = @("USB", "Bluetooth", "Image", "WPD", "PortableDevice", "MTP")
$KnownDevices = @{}
function Invoke-MobileDeviceScan {
$newDevices = @()
try {
$devices = Get-CimInstance Win32_PnPEntity -ErrorAction SilentlyContinue | Where-Object {
foreach ($cls in $DeviceClasses) {
if (($_.PNPClass -eq $cls) -or ($_.Service -like "*$cls*")) {
return $true
}
}
return $false
}
foreach ($d in $devices) {
$key = $d.DeviceID
if (-not $script:KnownDevices.ContainsKey($key)) {
$script:KnownDevices[$key] = $true
$newDevices += @{
DeviceID = $d.DeviceID
Name = $d.Name
PNPClass = $d.PNPClass
Status = $d.Status
}
}
}
if ($newDevices.Count -gt 0) {
$logPath = "$env:ProgramData\Antivirus\Logs\mobile_device_$(Get-Date -Format 'yyyy-MM-dd').log"
foreach ($nd in $newDevices) {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')|New device|$($nd.Name)|$($nd.PNPClass)|$($nd.DeviceID)" | Add-Content -Path $logPath
Write-EventLog -LogName Application -Source "AntivirusEDR" -EntryType Information -EventId 2094 -Message "MOBILE DEVICE: $($nd.Name) - $($nd.PNPClass)" -ErrorAction SilentlyContinue
}
Write-Output "STATS:$ModuleName`:Logged $($newDevices.Count) new mobile/USB devices"
}
} catch {
Write-Output "ERROR:$ModuleName`:$_"
}
}
function Start-Module {
while ($true) {
try {
$now = Get-Date
if (($now - $script:LastTick).TotalSeconds -ge $script:TickInterval) {
$script:LastTick = $now
Invoke-MobileDeviceScan
}
Start-Sleep -Seconds 5
} catch {
Write-Output "ERROR:$ModuleName`:$_"
Start-Sleep -Seconds 10
}
}
}
# --- Scheduler ---
$script:ModuleLastRun = @{}
$schedule = @(
@{ Name = 'Initializer'; Interval = 300; Invoke = 'Invoke-Initialization' }
@{ Name = 'HashDetection'; Interval = 90; Invoke = 'Invoke-HashScanOptimized' }
@{ Name = 'AMSIBypassDetection'; Interval = 90; Invoke = 'Invoke-AMSIBypassScan' }
@{ Name = 'GFocus'; Interval = 2; Invoke = 'Invoke-GFocusTick' }
@{ Name = 'ResponseEngine'; Interval = 180; Invoke = 'Invoke-ResponseEngine' }
@{ Name = 'BeaconDetection'; Interval = 60; Invoke = 'Invoke-BeaconDetection' }
@{ Name = 'NetworkTrafficMonitoring'; Interval = 45; Invoke = 'Invoke-NetworkTrafficMonitoringOptimized' }
@{ Name = 'ProcessAnomalyDetection'; Interval = 90; Invoke = 'Invoke-ProcessAnomalyScanOptimized' }
@{ Name = 'EventLogMonitoring'; Interval = 90; Invoke = 'Invoke-EventLogMonitoringOptimized' }
@{ Name = 'FileEntropyDetection'; Interval = 120; Invoke = 'Invoke-FileEntropyDetectionOptimized' }
@{ Name = 'YaraDetection'; Interval = 120; Invoke = 'Invoke-YaraScan' }
@{ Name = 'WMIPersistenceDetection'; Interval = 60; Invoke = 'Invoke-WMIPersistenceScan' }
@{ Name = 'ScheduledTaskDetection'; Interval = 60; Invoke = 'Invoke-ScheduledTaskScan' }
@{ Name = 'RegistryPersistenceDetection'; Interval = 60; Invoke = 'Invoke-RegistryPersistenceScan' }
@{ Name = 'DLLHijackingDetection'; Interval = 60; Invoke = 'Invoke-DLLHijackingScan' }
@{ Name = 'TokenManipulationDetection'; Interval = 30; Invoke = 'Invoke-TokenManipulationScan' }
@{ Name = 'ProcessHollowingDetection'; Interval = 20; Invoke = 'Invoke-ProcessHollowingScan' }
@{ Name = 'KeyloggerDetection'; Interval = 30; Invoke = 'Invoke-KeyloggerScan' }
@{ Name = 'ReflectiveDLLInjectionDetection'; Interval = 30; Invoke = 'Invoke-ReflectiveDLLInjectionDetection' }
@{ Name = 'RansomwareDetection'; Interval = 15; Invoke = 'Invoke-RansomwareScan' }
@{ Name = 'NetworkAnomalyDetection'; Interval = 30; Invoke = 'Invoke-NetworkAnomalyScan' }
@{ Name = 'DNSExfiltrationDetection'; Interval = 60; Invoke = 'Invoke-DNSExfiltrationDetection' }
@{ Name = 'RootkitDetection'; Interval = 60; Invoke = 'Invoke-RootkitScan' }
@{ Name = 'ClipboardMonitoring'; Interval = 10; Invoke = 'Invoke-ClipboardMonitoring' }
@{ Name = 'COMMonitoring'; Interval = 60; Invoke = 'Invoke-COMMonitoring' }
@{ Name = 'BrowserExtensionMonitoring'; Interval = 60; Invoke = 'Invoke-BrowserExtensionMonitoring' }
@{ Name = 'ShadowCopyMonitoring'; Interval = 30; Invoke = 'Invoke-ShadowCopyMonitoring' }
@{ Name = 'USBMonitoring'; Interval = 30; Invoke = 'Invoke-USBMonitoring' }
@{ Name = 'WebcamGuardian'; Interval = 20; Invoke = 'Invoke-WebcamGuardian' }
@{ Name = 'AttackToolsDetection'; Interval = 60; Invoke = 'Invoke-AttackToolsScan' }
@{ Name = 'AdvancedThreatDetection'; Interval = 60; Invoke = 'Invoke-AdvancedThreatScan' }
@{ Name = 'FirewallRuleMonitoring'; Interval = 60; Invoke = 'Invoke-FirewallRuleMonitoring' }
@{ Name = 'ServiceMonitoring'; Interval = 60; Invoke = 'Invoke-ServiceMonitoring' }
@{ Name = 'FilelessDetection'; Interval = 20; Invoke = 'Invoke-FilelessDetection' }
@{ Name = 'MemoryScanning'; Interval = 90; Invoke = 'Invoke-MemoryScanningOptimized' }
@{ Name = 'NamedPipeMonitoring'; Interval = 60; Invoke = 'Invoke-NamedPipeMonitoring' }
@{ Name = 'CodeInjectionDetection'; Interval = 30; Invoke = 'Invoke-CodeInjectionDetection' }
@{ Name = 'DataExfiltrationDetection'; Interval = 60; Invoke = 'Invoke-DataExfiltrationDetection' }
@{ Name = 'HoneypotMonitoring'; Interval = 300; Invoke = 'Invoke-HoneypotMonitoring' }
@{ Name = 'LateralMovementDetection'; Interval = 30; Invoke = 'Invoke-LateralMovementDetection' }
@{ Name = 'ProcessCreationDetection'; Interval = 60; Invoke = 'Invoke-ProcessCreationDetection' }
@{ Name = 'QuarantineManagement'; Interval = 300; Invoke = 'Invoke-QuarantineManagement' }
@{ Name = 'PrivacyForgeSpoofing'; Interval = 300; Invoke = 'Invoke-PrivacyForgeSpoofing' }
@{ Name = 'PasswordManagement'; Interval = 300; Invoke = 'Invoke-PasswordManagement' }
@{ Name = 'IdsDetection'; Interval = 60; Invoke = 'Invoke-IdsScan' }
@{ Name = 'CredentialDumpDetection'; Interval = 20; Invoke = 'Invoke-CredentialDumpScan' }
@{ Name = 'LOLBinDetection'; Interval = 30; Invoke = 'Invoke-LOLBinScan' }
@{ Name = 'MemoryAcquisitionDetection'; Interval = 90; Invoke = 'Invoke-MemoryAcquisitionScan' }
@{ Name = 'MobileDeviceMonitoring'; Interval = 90; Invoke = 'Invoke-MobileDeviceScan' }
)
if ($RemoveRules) {
if (Get-Command Remove-BlockedRules -ErrorAction SilentlyContinue) { Remove-BlockedRules }; exit 0
}
Invoke-Initialization | Out-Null
$loopSleep = 5
while ($true) {
$now = Get-Date
foreach ($m in $schedule) {
if (-not $script:ModuleLastRun.ContainsKey($m.Name)) { $script:ModuleLastRun[$m.Name] = [datetime]::MinValue }
if (($now - $script:ModuleLastRun[$m.Name]).TotalSeconds -ge $m.Interval) {
$script:ModuleName = $m.Name
try { & $m.Invoke | Out-Null } catch { Write-Output "ERROR:$($m.Name):$_" }
$script:ModuleLastRun[$m.Name] = $now
}
}
Start-Sleep -Seconds $loopSleep
}
Editor is loading...
Leave a Comment