polish: UTF-8 batch scripts, drop redundant set-vnc-password, robust vnc password probe

- run.bat / open-firewall.bat: UTF-8 (no BOM) + chcp 65001 instead of cp866/chcp 866.
- scripts/set-vnc-password.bat: removed (run.bat syncs the UltraVNC password via ensure-vnc-password.ps1).
- scripts/ensure-vnc-password.ps1: use a real RFB VNC-Auth probe to 127.0.0.1:5900
  to decide if the password already matches (no UAC when it does); set via
  createpassword/setpasswd + service restart only when it differs. Works for
  any password length (no stored-password encoding assumptions).
- AGENTS.md: .bat encoding convention updated to UTF-8/chcp 65001; drop set-vnc-password refs.
This commit is contained in:
Codex
2026-07-30 20:03:43 +03:00
parent 6a1ee64b14
commit db4f33f725
5 changed files with 144 additions and 248 deletions
+87 -83
View File
@@ -1,59 +1,71 @@
# ensure-vnc-password.ps1 - keep the UltraVNC service VNC password in sync
# with the password the user types in run.bat. Called from run.bat.
# ensure-vnc-password.ps1 - keep the UltraVNC VNC password in sync with the
# password the user types in run.bat. Called from run.bat.
#
# It only WRITES when the password actually differs (so a normal launch with
# the same password does nothing and asks for NO admin rights). When it must
# change the password it re-launches itself elevated (one UAC prompt) and
# restarts the uvnc_service so the new password takes effect.
# It checks whether the running VNC server already ACCEPTS the given password
# (a real RFB VNC-Auth handshake against 127.0.0.1:5900 - the same mechanism
# noVNC uses). If it does, nothing happens and NO admin rights are needed.
# If it does not (or no server is up), it sets the UltraVNC service password
# to the given value (one UAC prompt) and restarts uvnc_service so it reloads.
#
# Usage: powershell -NoProfile -ExecutionPolicy Bypass -File ensure-vnc-password.ps1 -Password "<pw>"
# Exit codes: 0 = password matches (or was set OK); 1 = could not set it.
# Exit codes: 0 = password already accepted (or set OK); 1 = could not set it.
param([Parameter(Mandatory=$true)][string]$Password)
$ErrorActionPreference = "Stop"
$ini = Join-Path $env:ProgramData "UltraVNC\ultravnc.ini"
function Write-Info($m){ Write-Host "ensure-vnc-password: $m" }
if (-not (Test-Path $ini)) {
# No installed UltraVNC service config (e.g. portable copy / TightVNC) - nothing to sync.
Write-Info "no %ProgramData%\UltraVNC\ultravnc.ini - nothing to sync."
exit 0
}
# --- VNC password obfuscation: DES-ECB(key=bitrev([23,82,107,6,35,78,88,7]), pw8) + 1-byte checksum ---
# ---- bit-reverse a byte (VNC key bytes are bit-reversed) ----
function Invoke-BitRev([byte]$b){ $r=0; for($i=0;$i -lt 8;$i++){ $r = $r -bor ((($b -shr $i) -band 1) -shl (7-$i)) }; return [byte]$r }
function Get-ExpectedPasswd([string]$pw){
$fixedkey = [byte[]](23,82,107,6,35,78,88,7)
$kr = New-Object byte[] 8; for($i=0;$i -lt 8;$i++){ $kr[$i] = Invoke-BitRev $fixedkey[$i] }
$pb = [System.Text.Encoding]::ASCII.GetBytes($pw)
if ($pb.Length -gt 8) { $pb = $pb[0..7] }
$plain = New-Object byte[] 8; for($i=0;$i -lt 8;$i++){ if($i -lt $pb.Length){ $plain[$i] = $pb[$i] } }
$des = New-Object System.Security.Cryptography.DESCryptoServiceProvider
$des.Mode = [System.Security.Cryptography.CipherMode]::ECB
$des.Padding = [System.Security.Cryptography.PaddingMode]::None
$des.Key = $kr
$cipher = $des.CreateEncryptor().TransformFinalBlock($plain,0,8)
$sum = 0; foreach($b in $cipher){ $sum = ($sum + $b) -band 0xFF }
$h = ($cipher | ForEach-Object { $_.ToString("X2") }) -join ""
return $h + $sum.ToString("X2")
# ---- real RFB VNC-Auth probe. Returns 'ok','rejected','unreachable','noserver' ----
function Test-VncAuth([string]$pw,[string]$target,[int]$port){
$c = New-Object System.Net.Sockets.TcpClient
try { $c.Connect($target,$port) } catch { return 'unreachable' }
try {
$s = $c.GetStream(); $s.ReadTimeout = 8000; $s.WriteTimeout = 8000
$rb = New-Object byte[] 64
$got = 0
while($got -lt 12){ $n = $s.Read($rb,$got,12-$got); if($n -le 0){ return 'unreachable' }; $got += $n }
if (-not ([System.Text.Encoding]::ASCII.GetString($rb,0,12).StartsWith("RFB "))) { return 'noserver' }
$s.Write([System.Text.Encoding]::ASCII.GetBytes("RFB 003.008`n"),0,12)
$n = $s.Read($rb,0,64); if($n -lt 1){ return 'unreachable' }
$numTypes = $rb[0]
if($numTypes -eq 0 -or $n -lt (1+$numTypes)){ return 'noserver' }
$types = $rb[1..($numTypes)]
if(-not ($types -contains 2)){ return 'noserver' } # VNC-Auth not offered (e.g. MS-Logon only)
$s.Write([byte[]](2),0,1) # choose VNC-Auth
$got = 0
while($got -lt 16){ $n = $s.Read($rb,$got,16-$got); if($n -le 0){ return 'unreachable' }; $got += $n }
$challenge = $rb[0..15]
$pb = [System.Text.Encoding]::ASCII.GetBytes($pw)
if($pb.Length -gt 8){ $pb = $pb[0..7] }
$key = New-Object byte[] 8
for($i=0;$i -lt 8;$i++){ $kb = if($i -lt $pb.Length){[int]$pb[$i]}else{0}; $key[$i] = Invoke-BitRev ([byte]$kb) }
$des = New-Object System.Security.Cryptography.DESCryptoServiceProvider
$des.Mode = [System.Security.Cryptography.CipherMode]::ECB
$des.Padding = [System.Security.Cryptography.PaddingMode]::None
$des.Key = $key
$resp = $des.CreateEncryptor().TransformFinalBlock($challenge,0,16)
$s.Write($resp,0,16)
$n = $s.Read($rb,0,4); if($n -lt 4){ return 'rejected' }
$status = ($rb[0]*16777216)+($rb[1]*65536)+($rb[2]*256)+$rb[3]
if($status -eq 0){ return 'ok' } else { return 'rejected' }
} finally { $c.Close() }
}
function Get-CurrentPasswd{
$line = Get-Content $ini -ErrorAction SilentlyContinue | Where-Object { $_ -match '^\s*passwd\s*=' -and $_ -notmatch 'passwd2' } | Select-Object -First 1
if (-not $line) { return "" }
return ($line -split '=',2)[1].Trim()
}
$expected = Get-ExpectedPasswd $Password
$current = Get-CurrentPasswd
if ($current -ieq $expected) {
Write-Info "UltraVNC password already matches - nothing to do."
$probe = Test-VncAuth $Password "127.0.0.1" 5900
if($probe -eq 'ok'){
Write-Info "UltraVNC already accepts this password - nothing to do."
exit 0
}
Write-Info "UltraVNC password differs (ini=$current, expected=$expected). Need to set it (admin required)."
Write-Info "UltraVNC password needs setting (probe=$probe). Need admin."
# Locate UltraVNC install + password tools.
$uvncDirs = @(
@@ -63,64 +75,56 @@ $uvncDirs = @(
"${env:ProgramFiles(x86)}\UltraVNC"
)
$uvnc = $uvncDirs | Where-Object { Test-Path "$_\winvnc.exe" } | Select-Object -First 1
if (-not $uvnc) { Write-Info "UltraVNC install not found - cannot set password."; exit 1 }
if(-not $uvnc){ Write-Info "UltraVNC install not found - cannot set password."; exit 1 }
# Are we admin?
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Info "re-launching elevated to set the password..."
$p = Start-Process -FilePath "powershell.exe" -Verb RunAs -Wait -PassThru -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","`"$PSCommandPath`"","-Password","`"$Password`"")
if ($p.ExitCode -ne 0) { Write-Info "elevated run failed (exit $($p.ExitCode))."; exit 1 }
$now = Get-CurrentPasswd
if ($now -ieq $expected) { Write-Info "password set OK."; exit 0 }
Write-Info "password still not updated after elevated run (ini=$now)."; exit 1
function Get-IniPasswd{
$line = Get-Content $ini -ErrorAction SilentlyContinue | Where-Object { $_ -match '^\s*passwd\s*=' -and $_ -notmatch 'passwd2' } | Select-Object -First 1
if(-not $line){ return "" }
return ($line -split '=',2)[1].Trim()
}
# --- admin path: actually set the password ---
function Set-Tool{
param([string]$exe)
if (-not (Test-Path $exe)) { return $false }
function Invoke-SetTool([string]$exe,[string]$pw){
if(-not (Test-Path $exe)){ return $false }
try {
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $exe
$psi.Arguments = "`"$Password`""
$psi.UseShellExecute = $false
$psi.FileName = $exe; $psi.Arguments = "`"$pw`""; $psi.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($psi)
if (-not $p.WaitForExit(5000)) { $p.Kill() }
if(-not $p.WaitForExit(5000)){ $p.Kill() }
return ($p.ExitCode -eq 0)
} catch { return $false }
}
$ok = $false
if (Set-Tool (Join-Path $uvnc "createpassword.exe")) { $ok = $true }
$now = Get-CurrentPasswd
if ($now -ine $expected -and (Test-Path (Join-Path $uvnc "setpasswd.exe"))) {
# fallback to setpasswd.exe "<pw>"
try {
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = Join-Path $uvnc "setpasswd.exe"
$psi.Arguments = "`"$Password`""
$psi.UseShellExecute = $false
$p = [System.Diagnostics.Process]::Start($psi)
if (-not $p.WaitForExit(5000)) { $p.Kill() }
} catch {}
$now = Get-CurrentPasswd
function Do-Set([string]$pw){
$before = Get-IniPasswd
[void](Invoke-SetTool (Join-Path $uvnc "createpassword.exe") $pw)
$after = Get-IniPasswd
if($after -ieq $before){
[void](Invoke-SetTool (Join-Path $uvnc "setpasswd.exe") $pw)
$after = Get-IniPasswd
}
if($after -ieq $before){ Write-Info "password tools did not change $ini (still $after)."; return $false }
# restart the service so the running server reloads (only if it was running)
try { $q = (& sc.exe query uvnc_service 2>$null); $running = ($q -match 'RUNNING') } catch { $running = $false }
if($running){
Write-Info "restarting uvnc_service ..."
& net.exe stop uvnc_service 2>$null | Out-Null
& net.exe start uvnc_service 2>$null | Out-Null
}
return $true
}
if ($now -ine $expected) {
Write-Info "tools did not update the password (ini=$now). Set it manually via UltraVNC Admin Properties as admin."
exit 1
}
Write-Info "password updated in $ini."
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
# Restart the service so it reloads the new password.
$svc = "uvnc_service"
$svcExists = $false
try { $null = (& sc.exe query $svc 2>$null); $svcExists = ($LASTEXITCODE -eq 0) } catch {}
if ($svcExists) {
Write-Info "restarting service $svc ..."
& net.exe stop $svc 2>$null | Out-Null
& net.exe start $svc 2>$null | Out-Null
if(-not $isAdmin){
Write-Info "re-launching elevated to set the password..."
$p = Start-Process -FilePath "powershell.exe" -Verb RunAs -Wait -PassThru -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","`"$PSCommandPath`"","-Password","`"$Password`"")
if($p.ExitCode -ne 0){ Write-Info "elevated run failed (exit $($p.ExitCode))."; exit 1 }
# confirm by re-probing (if a server is up now)
$again = Test-VncAuth $Password "127.0.0.1" 5900
if($again -eq 'ok'){ Write-Info "password set OK."; exit 0 }
if($again -eq 'unreachable'){ Write-Info "password written; no server up to verify (will be used on next start)."; exit 0 }
Write-Info "password set but server still rejects it (probe=$again)."; exit 1
}
exit 0
# admin path
if(Do-Set $Password){ Write-Info "password set OK."; exit 0 } else { exit 1 }
+12 -12
View File
@@ -1,16 +1,16 @@
@echo off
REM ============================================================
REM open-firewall.bat - ®âªà뢠¥â ¯®àâ 8080 ¢ Windows Firewall.
REM ‡ ¯ã᪠âì ®â ¨¬¥­¨  ¤¬¨­¨áâà â®à  (®¤¨­ à §).
REM ‹¨¡® § ¯ãáâ¨â¥ ¤¢ ¦¤ë: ä ©« á ¬ § ¯à®á¨â ¯à ¢   ¤¬¨­¨áâà â®à .
REM open-firewall.bat - открывает порт 8080 в Windows Firewall.
REM Запускать от имени администратора (один раз).
REM Либо запустите дважды: файл сам запросит права администратора.
REM ============================================================
chcp 866 >nul
chcp 65001 >nul
cd /d "%~dp0"
REM ஢¥àª  ¯à ¢  ¤¬¨­¨áâà â®à  ¨  ¢â®-¯®¢ë襭¨¥.
REM Проверка прав администратора и авто-повышение.
net session >nul 2>nul
if errorlevel 1 (
echo ‡ ¯à®á ¯à ¢  ¤¬¨­¨áâà â®à  ...
echo Запрос прав администратора ...
powershell -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
exit /b
)
@@ -18,20 +18,20 @@ if errorlevel 1 (
set PORT=8080
set RULE=web-vnc
echo “¤ «ïî áâ à®¥ ¯à ¢¨«® (¥á«¨ ¥áâì) ...
echo Удаляю старое правило (если есть) ...
netsh advfirewall firewall delete rule name="%RULE%" >nul 2>nul
echo „®¡ ¢«ïî à §à¥è î饥 ¯à ¢¨«® ¤«ï ¢å®¤ï饣® TCP-âà ä¨ª  ­  ¯®àâ %PORT% ...
echo Добавляю разрешающее правило для входящего TCP-трафика на порт %PORT% ...
netsh advfirewall firewall add rule name="%RULE%" dir=in action=allow protocol=TCP localport=%PORT%
if errorlevel 1 (
echo [®è¨¡ª ] ¥ 㤠«®áì ¤®¡ ¢¨âì ¯à ¢¨«®.
echo [ошибка] Не удалось добавить правило.
pause
exit /b 1
)
echo.
echo ƒ®â®¢®. ®àâ %PORT% ®âªàëâ ¤«ï ¢å®¤ïé¨å ¯®¤ª«î祭¨©.
echo ’¥¯¥àì ª web-vnc ¬®¦­® ¯®¤ª«îç âìáï á ¤àã£¨å ¬ è¨­ á¥â¨ ¯®  ¤à¥áã:
echo http://IP_’މ_Œ€˜ˆ:%PORT%
echo Готово. Порт %PORT% открыт для входящих подключений.
echo Теперь к web-vnc можно подключаться с других машин сети по адресу:
echo http://IP_ЭТОЙ_МАШИНЫ:%PORT%
echo.
pause
-109
View File
@@ -1,109 +0,0 @@
@echo off
REM ============================================================
REM set-vnc-password.bat - reliably set the UltraVNC VNC password
REM for the running service (uvnc_service / LocalSystem), which
REM reads %ProgramData%\UltraVNC\ultravnc.ini.
REM
REM Runs AS ADMINISTRATOR (auto-elevates). It first tries the
REM UltraVNC CLI helpers (createpassword.exe / setpasswd.exe) and
REM VERIFIES the password actually changed in ultravnc.ini; if they
REM fail silently (as they can), it opens the UltraVNC settings GUI
REM so you can set "VNC Password" there. Then it restarts the
REM service. Use the SAME password in run.bat (ASCII, max 8 chars).
REM ============================================================
chcp 866 >nul
cd /d "%~dp0"
net session >nul 2>nul
if errorlevel 1 (
echo Requesting administrator rights ...
powershell -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
exit /b
)
set "UVNC="
for %%P in (
"C:\Program Files\uvnc bvba\UltraVNC"
"C:\Program Files\UltraVNC"
"C:\Program Files (x86)\uvnc bvba\UltraVNC"
"C:\Program Files (x86)\UltraVNC"
) do (
if exist "%%~P\winvnc.exe" if not defined UVNC set "UVNC=%%~P"
)
if not defined UVNC (
echo [error] UltraVNC installation not found.
pause
exit /b 1
)
echo UltraVNC: %UVNC%
set "INI=%ProgramData%\UltraVNC\ultravnc.ini"
:getpw
set "PW="
set /p "PW=Enter VNC password (ASCII, max 8 chars): "
if "%PW%"=="" ( echo Password cannot be empty. & goto getpw )
REM record old passwd
set "OLDPW="
if exist "%INI%" for /f "tokens=2 delims==" %%a in ('findstr /b /i "passwd=" "%INI%" 2^>nul ^| findstr /v /i "passwd2"') do set "OLDPW=%%a"
echo Old passwd=%OLDPW%
REM try CLI helpers, verify after each
set "DONE=0"
if exist "%UVNC%\createpassword.exe" (
echo Trying createpassword.exe ...
"%UVNC%\createpassword.exe" "%PW%" >nul 2>nul
call :checkchanged
)
if "%DONE%"=="0" if exist "%UVNC%\setpasswd.exe" (
echo Trying setpasswd.exe ...
"%UVNC%\setpasswd.exe" "%PW%" "%PW%" >nul 2>nul
call :checkchanged
)
if "%DONE%"=="0" (
echo.
echo CLI helpers did not change the password file. Opening UltraVNC settings...
echo -> right-click the UltraVNC tray icon, choose Admin Properties,
echo set the "VNC Password" to: %PW%
echo -> close the settings/tray app, then come back here and press a key.
echo.
start "" "%UVNC%\winvnc.exe"
pause
call :checkchanged
)
set "PW="
if "%DONE%"=="0" (
echo [warn] Password still not changed in %INI%.
echo Set it manually in UltraVNC Admin Properties as administrator.
pause
exit /b 1
)
REM restart the service so it reloads the password
set "SVC=uvnc_service"
sc query %SVC% >nul 2>nul
if errorlevel 1 (
echo [warn] Service '%SVC%' not found; restart winvnc manually if it runs in app mode.
goto showini
)
echo Restarting service %SVC% ...
net stop %SVC% >nul 2>nul
net start %SVC%
:showini
echo.
echo --- %INI% ---
if exist "%INI%" type "%INI%"
echo.
echo Done. Use the SAME password in run.bat, then reconnect in the browser.
pause
exit /b
:checkchanged
set "NEWPW="
if exist "%INI%" for /f "tokens=2 delims==" %%a in ('findstr /b /i "passwd=" "%INI%" 2^>nul ^| findstr /v /i "passwd2"') do set "NEWPW=%%a"
if not "%NEWPW%"=="%OLDPW%" (
echo Password file updated. New passwd=%NEWPW%
set "DONE=1"
)
goto :eof