GShield

 avatar
unknown
powershell
2 days ago
10 kB
2
No Index
# GShield.ps1
# Author: Gorstak
#Requires -RunAsAdministrator

# Self-contained AV - copies to ProgramData\GShield and installs as service
param([string]$Path='C:\', [int]$IntervalMinutes=60)

# ==================== CONFIG ====================
$ServiceName = 'GShield'
$InstallDir = "$env:ProgramData\GShield"
$LogDir = "$InstallDir\logs"
$QuarDir = "$InstallDir\quarantine"
$YaraDir = "$InstallDir\yara"
$RulesDir = "$InstallDir\rules"
$LogFile = "$LogDir\service.log"
$Cache = "$InstallDir\av.csv"
$HashCache = "$InstallDir\hashes.csv"
$ScriptName = 'Antivirus.ps1'
$ScriptPath = "$InstallDir\$ScriptName"

$YaraUrl = "https://github.com/VirusTotal/yara/releases/download/v4.5.5/yara-4.5.5-2368-win64.zip"
$YaraHash = "2cc0b3388039629653b2ef581ab2553670f021a88c9b0fe1d0e35151317399f3"
$RulesUrl = "https://github.com/Yara-Rules/rules/archive/refs/heads/master.zip"

$Ext = '*.exe','*.msi','*.dll','*.ocx','*.winmd','*.ps1','*.vbs','*.js','*.bat','*.cmd','*.scr'
$Exclusions = @(
    "$env:ProgramFiles", "$env:ProgramFiles(x86)", "$env:windir",
    "$InstallDir", "C:\Windows\System32", "C:\Windows\SysWOW64"
)
$SuspiciousAPIs = 'VirtualAlloc|WriteProcessMemory|CreateRemoteThread|NtUnmapViewOfSection|ReadProcessMemory|OpenProcess|VirtualProtect|LoadLibrary|GetProcAddress|WinExec|CreateProcess|ShellExecute|URLDownloadToFile|InternetOpen'

# ===============================================

# Logging function for service mode (no console)
function Write-Log {
    param([string]$Message, [string]$Level = 'INFO')
    $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $logEntry = "$timestamp [$Level] $Message"
    $logEntry | Add-Content $LogFile -Force -ErrorAction SilentlyContinue
}

# Self-installation: copy to ProgramData and create service
function Install-Self {
    # Create directory structure
    @($InstallDir, $LogDir, $QuarDir, $YaraDir, $RulesDir) | ForEach-Object {
        if (!(Test-Path $_)) { New-Item $_ -ItemType Directory -Force | Out-Null }
    }

    # Copy script to install location if not already there
    $currentScript = $PSCommandPath
    if ($currentScript -ne $ScriptPath) {
        Write-Host "Installing GShield AV to $InstallDir..." -ForegroundColor Cyan
        Copy-Item $currentScript $ScriptPath -Force
        Write-Host "Copied script to $ScriptPath" -ForegroundColor Green
    }

    # Check if service exists
    $svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    if (!$svc) {
        Write-Host "Creating Windows service $ServiceName..." -ForegroundColor Cyan
        $binPath = "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$ScriptPath`" -Path `"$Path`" -IntervalMinutes $IntervalMinutes"
        $scArgs = "create $ServiceName binPath= `"$binPath`" start= auto DisplayName= `"GShield Antivirus`""
        $proc = Start-Process sc.exe -ArgumentList $scArgs -Wait -PassThru -WindowStyle Hidden
        if ($proc.ExitCode -eq 0) {
            Write-Host "Service created successfully" -ForegroundColor Green
            Start-Service $ServiceName -ErrorAction SilentlyContinue
            Write-Host "GShield AV service started!" -ForegroundColor Green
            Write-Host "Logs: $LogFile" -ForegroundColor Gray
            Write-Host "Quarantine: $QuarDir" -ForegroundColor Gray
            exit 0
        } else {
            Write-Host "Failed to create service (exit code: $($proc.ExitCode))" -ForegroundColor Red
            exit 1
        }
    } else {
        Write-Host "Service $ServiceName already exists" -ForegroundColor Yellow
        $svcStatus = $svc.Status
        Write-Host "Current status: $svcStatus" -ForegroundColor Gray
        if ($svcStatus -ne 'Running') {
            Start-Service $ServiceName
            Write-Host "Service started" -ForegroundColor Green
        }
    }
}

# Run self-install if not running from install directory
if ($PSCommandPath -ne $ScriptPath) {
    Install-Self
}

# Helper functions
function Get-SHA256 { param($file); (Get-FileHash $file -Algorithm SHA256).Hash }
function Test-Excluded { param($p); $Exclusions | Where-Object { $p -like "$_*" } }

function Ensure-Setup {
    # Ensure all dirs exist
    @($LogDir, $QuarDir, $YaraDir, $RulesDir) | ForEach-Object {
        if (!(Test-Path $_)) { New-Item $_ -ItemType Directory -Force | Out-Null }
    }

    $yaraExe = (Get-ChildItem $YaraDir -Filter yara64.exe -EA 0 | Select -First 1).FullName
    if (!$yaraExe) {
        Write-Log "Downloading YARA..."
        $z = "$env:TEMP\yara.zip"
        try {
            Invoke-WebRequest $YaraUrl -OutFile $z -UseBasicParsing
            if ((Get-SHA256 $z) -ne $YaraHash) { 
                Write-Log "YARA hash mismatch!" "ERROR"
                Remove-Item $z -Force
                return
            }
            Expand-Archive $z -DestinationPath $YaraDir -Force
            # Move yara64.exe to root of yara dir
            Get-ChildItem $YaraDir -Recurse -Filter yara64.exe | Select -First 1 | ForEach-Object {
                Copy-Item $_.FullName "$YaraDir\yara64.exe" -Force
            }
            Remove-Item $z -Force
            Write-Log "YARA installed"
        } catch {
            Write-Log "Failed to download YARA: $_" "ERROR"
        }
    }

    if (!(Test-Path "$RulesDir\index.yar")) {
        Write-Log "Downloading YARA rules..."
        $z = "$env:TEMP\rules.zip"
        try {
            Invoke-WebRequest $RulesUrl -OutFile $z -UseBasicParsing
            Expand-Archive $z -DestinationPath $env:TEMP -Force
            # Find extracted folder and move rules
            $extracted = Get-ChildItem $env:TEMP -Directory | Where-Object { $_.Name -like 'rules-*' } | Select -First 1
            if ($extracted) {
                Copy-Item "$($extracted.FullName)\*" $RulesDir -Recurse -Force
                Remove-Item $extracted.FullName -Recurse -Force
            }
            Remove-Item $z -Force
            Write-Log "YARA rules installed"
        } catch {
            Write-Log "Failed to download rules: $_" "ERROR"
        }
    }
}

# AMSI Wrapper
Add-Type -TypeDefinition @'
using System;using System.Runtime.InteropServices;
public class Amsi{[DllImport("amsi.dll")]public static extern int AmsiInitialize(string a,out IntPtr c);[DllImport("amsi.dll")]public static extern int AmsiScanString(IntPtr c,string s,string n,string sess,out IntPtr r);[DllImport("amsi.dll")]public static extern void AmsiUninitialize(IntPtr c);
public static int Scan(string s){IntPtr ctx,rs;int hr=AmsiInitialize("GShield",out ctx);if(hr!=0)return 0;AmsiScanString(ctx,s,"", "",out rs);int res=(int)rs;AmsiUninitialize(ctx);return res;}}
'@

function Test-Amsi { param([string]$c); if(!$c) {return 0}; return [Amsi]::Scan($c) -ge 1 }

function Get-Entropy { param([byte[]]$b)
    if(!$b.Length) {return 0}
    $f=@{}; foreach($c in $b){$f[$c]++}
    $e=0; foreach($c in $f.Keys){$p=$f[$c]/$b.Length; $e-=$p*([Math]::Log($p)/[Math]::Log(2))}
    return $e
}

function Test-Heuristic {
    param([string]$path)
    $warn = @()
    $ext = [IO.Path]::GetExtension($path).ToLower()
    try {
        $b = [IO.File]::ReadAllBytes($path)
        if ((Get-Entropy $b) -gt 7.2) { $warn += "high-entropy" }
        if ($ext -in '.exe','.dll') {
            $str = [Text.Encoding]::ASCII.GetString($b)
            if ($str -match $SuspiciousAPIs) { $warn += "susp-api" }
        }
        if ($ext -in '.ps1','.vbs','.js','.bat') {
            $c = Get-Content $path -Raw -EA 0
            if ($c -match '[A-Za-z0-9+/]{80,}={0,2}') { $warn += "b64" }
            if ($c -match 'IEX|Invoke-Expression|FromBase64String|DownloadString|Hidden') { $warn += "obf" }
        }
    } catch {}
    return ($warn -join ',')
}

function Invoke-Scan {
    param([string]$p)
    $yaraExe = (Get-ChildItem $YaraDir -Filter yara64.exe -EA 0 | Select -First 1).FullName

    Get-ChildItem $p -Recurse -Include $Ext -EA 0 | Where-Object { !(Test-Excluded $_.FullName) } | ForEach-Object {
        $f = $_
        try {
            $h = (Get-FileHash $f.FullName -A SHA1).Hash
            $heur = Test-Heuristic $f.FullName
            if ($heur -match "high-entropy|susp-api|obf") { 
                Write-Log "QUARANTINED: $($f.FullName) [$heur]" "ALERT"
                Move-Item $f.FullName "$QuarDir\$($f.Name)" -Force -EA 0
            }
            if ($f.Extension -in '.ps1','.vbs','.js' -and (Test-Amsi (Get-Content $f.FullName -Raw))) {
                Write-Log "QUARANTINED (AMSI): $($f.FullName)" "ALERT"
                Move-Item $f.FullName "$QuarDir\$($f.Name)" -Force -EA 0
            }
            if ($yaraExe) {
                $y = & $yaraExe -r "$RulesDir" $f.FullName 2>$null
                if ($y) { 
                    Write-Log "QUARANTINED (YARA): $($f.FullName) - $y" "ALERT"
                    Move-Item $f.FullName "$QuarDir\$($f.Name)" -Force -EA 0
                }
            }
        } catch {}
    }
    Write-Log "Scan completed: $p"
}

# Service startup
Write-Log "GShield AV starting - PID: $PID"
Write-Log "Install dir: $InstallDir"
Write-Log "Log file: $LogFile"
Write-Log "Quarantine: $QuarDir"

Ensure-Setup

if ($IntervalMinutes -le 0) { 
    Invoke-Scan $Path
    exit 
}

Write-Log "Real-time protection enabled"

# Real-time Process Guard
Register-WmiEvent -Query "SELECT * FROM Win32_ProcessStartTrace" -SourceIdentifier "ProcGuard" -Action {
    $e = $Event.SourceEventArgs.NewEvent
    $procId = $e.ProcessID
    try {
        $proc = Get-CimInstance Win32_Process -Filter "ProcessId=$procId"
        $procPath = $proc.ExecutablePath
        if (!$procPath -or (Test-Excluded $procPath)) { return }
        $heur = Test-Heuristic $procPath
        if ($heur -match "high-entropy|susp-api|obf") {
            Stop-Process -Id $procId -Force -EA 0
            Write-Log "BLOCKED: $procPath [$heur]" "ALERT"
        }
    } catch {}
} | Out-Null

# Main service loop
while ($true) {
    Write-Log "Periodic scan starting: $Path"
    Invoke-Scan $Path
    Start-Sleep -Seconds ($IntervalMinutes * 60)
}
Editor is loading...
Leave a Comment