From e4bbbd5cf07c582833e1ef79a6b00c6d99621f40 Mon Sep 17 00:00:00 2001 From: egieb <93350544+beigeworm@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:09:13 +0000 Subject: [PATCH] Update main.ps1 --- Screenshare-Over-LAN/main.ps1 | 383 ++++++++++++++++++++++++---------- 1 file changed, 274 insertions(+), 109 deletions(-) diff --git a/Screenshare-Over-LAN/main.ps1 b/Screenshare-Over-LAN/main.ps1 index 2b5cb3a..7808599 100644 --- a/Screenshare-Over-LAN/main.ps1 +++ b/Screenshare-Over-LAN/main.ps1 @@ -1,30 +1,24 @@ <# -================================================= Beigeworm's Screen Stream over HTTP ========================================================== +================================================= Beigeworm's VNC over HTTP ========================================================== SYNOPSIS -Start up a HTTP server and stream the desktop to a browser window on another device on the network. +Start up a HTTP server and stream the desktop to a browser window on another device on LAN with basic mouse and keyboard functionality. USAGE 1. Run this script on target computer and note the URL provided -2. on another device on the same network, enter the provided URL in a browser window +2. On another device on the same network, enter the provided URL in a browser window 3. Hold escape key on target for 5 seconds to exit screenshare. +4. You mayneed to resize window for mouse calibration! #> - # Hide the powershell console (1 = yes) $hide = 1 -# WRITE AS ADMIN! -If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator')) { - Start-Process PowerShell.exe -ArgumentList ("-NoProfile -Ep Bypass -File `"{0}`"" -f $PSCommandPath) -Verb RunAs - Exit -} - [Console]::BackgroundColor = "Black" Clear-Host [Console]::SetWindowSize(88,30) -[Console]::Title = "HTTP Screenshare" +[Console]::Title = "VNC over LAN" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName PresentationCore,PresentationFramework Add-Type -AssemblyName System.Windows.Forms @@ -32,77 +26,70 @@ Add-Type -AssemblyName System.Windows.Forms # Define port number if ($port.length -lt 1){ - Write-Host "Using default port.. (8080)" -ForegroundColor Green $port = 8080 } -Write-Host "Detecting primary network interface." -ForegroundColor DarkGray -$networkInterfaces = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' -and $_.InterfaceDescription -notmatch 'Virtual' } -$filteredInterfaces = $networkInterfaces | Where-Object { $_.Name -match 'Wi*' -or $_.Name -match 'Eth*'} -$primaryInterface = $filteredInterfaces | Select-Object -First 1 -if ($primaryInterface) { - if ($primaryInterface.Name -match 'Wi*') { - Write-Output "Wi-Fi is the primary internet connection." - $localIP = Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Wi*" | Select-Object -ExpandProperty IPAddress - } elseif ($primaryInterface.Name -match 'Eth*') { - Write-Output "Ethernet is the primary internet connection." - $localIP = Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Eth*" | Select-Object -ExpandProperty IPAddress - } else { - Write-Output "Unknown primary internet connection." - } - } else {Write-Output "No primary internet connection found."} +Add-Type @" +using System; +using System.Runtime.InteropServices; +public class MouseSimulator { + [DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] + public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo); -New-NetFirewallRule -DisplayName "AllowWebServer" -Direction Inbound -Protocol TCP -LocalPort $port -Action Allow | Out-Null -$webServer = New-Object System.Net.HttpListener -$webServer.Prefixes.Add("http://"+$localIP+":$port/") -$webServer.Prefixes.Add("http://localhost:$port/") -$webServer.Start() -Write-Host ("Network Devices Can Reach the server at : http://"+$localIP+":$port") -Write-Host "Press escape key for 5 seconds to exit" -f Cyan -Write-Host "Hiding this window.." -f Yellow -sleep 4 + public const int MOUSEEVENTF_LEFTDOWN = 0x02; + public const int MOUSEEVENTF_LEFTUP = 0x04; + public const int MOUSEEVENTF_RIGHTDOWN = 0x08; + public const int MOUSEEVENTF_RIGHTUP = 0x10; -# Code to hide the console on Windows 10 and 11 -if ($hide -eq 1){ - $Async = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' - $Type = Add-Type -MemberDefinition $Async -name Win32ShowWindowAsync -namespace Win32Functions -PassThru - $hwnd = (Get-Process -PID $pid).MainWindowHandle - - if ($hwnd -ne [System.IntPtr]::Zero) { - $Type::ShowWindowAsync($hwnd, 0) + public static void LeftClick() { + mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + System.Threading.Thread.Sleep(50); + mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); } - else { - $Host.UI.RawUI.WindowTitle = 'hideme' - $Proc = (Get-Process | Where-Object { $_.MainWindowTitle -eq 'hideme' }) - $hwnd = $Proc.MainWindowHandle - $Type::ShowWindowAsync($hwnd, 0) + + public static void RightClick() { + mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0); + System.Threading.Thread.Sleep(50); + mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0); } } +"@ + # Escape to exit key detection -Add-Type @" -using System; -using System.Runtime.InteropServices; - -public class Keyboard -{ - [DllImport("user32.dll")] - public static extern short GetAsyncKeyState(int vKey); -} -"@ -$VK_ESCAPE = 0x1B +Add-Type @" +using System; +using System.Runtime.InteropServices; + +public class Keyboard +{ + [DllImport("user32.dll")] + public static extern short GetAsyncKeyState(int vKey); +} +"@ +$VK_ESCAPE = 0x1B $startTime = $null -while ($true) { - try { - $context = $webServer.GetContext() - $response = $context.Response - if ($context.Request.RawUrl -eq "/stream") { - $response.ContentType = "multipart/x-mixed-replace; boundary=frame" - $response.Headers.Add("Cache-Control", "no-cache") - $boundary = "--frame" - while ($context.Response.OutputStream.CanWrite) { +If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator')) { + Start-Process PowerShell.exe -ArgumentList ("-NoProfile -Ep Bypass -File `"{0}`"" -f $PSCommandPath) -Verb RunAs + Exit +} + +function Start-Streaming { + param ($context, $imgWidth, $imgHeight) + + $streamRunspace = [runspacefactory]::CreateRunspace() + $streamRunspace.Open() + $streamPowerShell = [powershell]::Create().AddScript({ + param ($context, $imgWidth, $imgHeight) + $response = $context.Response + $response.ContentType = "multipart/x-mixed-replace; boundary=frame" + $response.Headers.Add("Cache-Control", "no-cache") + $boundary = "--frame" + + try { + while ($response.OutputStream.CanWrite) { $screen = [System.Windows.Forms.Screen]::PrimaryScreen $bitmap = New-Object System.Drawing.Bitmap $screen.Bounds.Width, $screen.Bounds.Height $graphics = [System.Drawing.Graphics]::FromImage($bitmap) @@ -122,61 +109,239 @@ while ($true) { $boundaryWriter = [System.Text.Encoding]::ASCII.GetBytes("`r`n") $response.OutputStream.Write($boundaryWriter, 0, $boundaryWriter.Length) - Start-Sleep -Milliseconds 33 - - # Check for the escape key press to exit - $isEscapePressed = [Keyboard]::GetAsyncKeyState($VK_ESCAPE) -lt 0 - if ($isEscapePressed) { - if (-not $startTime) { - $startTime = Get-Date - } - $elapsedTime = (Get-Date) - $startTime - if ($elapsedTime.TotalSeconds -ge 5) { - (New-Object -ComObject Wscript.Shell).Popup("Screenshare Closed.",3,"Information",0x0) - sleep 1 - exit - } - } else { - $startTime = $null - } + Start-Sleep -Milliseconds 100 } - } else { + } catch { + Write-Host "Stream closed: $_" + } finally { + $response.OutputStream.Close() + } + }).AddArgument($context).AddArgument($imgWidth).AddArgument($imgHeight) + + $streamPowerShell.Runspace = $streamRunspace + $streamPowerShell.BeginInvoke() +} + +$port = 8080 + +# Get primary network interface and IP +$networkInterfaces = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' -and $_.InterfaceDescription -notmatch 'Virtual' } +$filteredInterfaces = $networkInterfaces | Where-Object { $_.Name -match 'Wi*' -or $_.Name -match 'Eth*'} +$primaryInterface = $filteredInterfaces | Select-Object -First 1 +if ($primaryInterface) { + if ($primaryInterface.Name -match 'Wi*') { + $localIP = Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Wi*" | Select-Object -ExpandProperty IPAddress + } elseif ($primaryInterface.Name -match 'Eth*') { + $localIP = Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Eth*" | Select-Object -ExpandProperty IPAddress + } +} + +New-NetFirewallRule -DisplayName "AllowWebServer" -Direction Inbound -Protocol TCP -LocalPort $port -Action Allow | Out-Null + +$webServer = New-Object System.Net.HttpListener +$webServer.Prefixes.Add("http://$localIP`:$port/") +$webServer.Prefixes.Add("http://localhost`:$port/") +$webServer.Start() + +Write-Host "Server started at http://$localIP`:$port" -f Cyan + +$screenWidth = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width +$screenHeight = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height +$imgWidth = $screenWidth +$imgHeight = $screenHeight + +Write-Host "`nPress escape key for 5 seconds to exit" -f Gray + + +# Code to hide the console on Windows 10 and 11 +if ($hide -eq 1){ + Write-Host "Hiding this window.." -f Yellow + sleep 4 + $Async = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' + $Type = Add-Type -MemberDefinition $Async -name Win32ShowWindowAsync -namespace Win32Functions -PassThru + $hwnd = (Get-Process -PID $pid).MainWindowHandle + + if ($hwnd -ne [System.IntPtr]::Zero) { + $Type::ShowWindowAsync($hwnd, 0) + } + else { + $Host.UI.RawUI.WindowTitle = 'hideme' + $Proc = (Get-Process | Where-Object { $_.MainWindowTitle -eq 'hideme' }) + $hwnd = $Proc.MainWindowHandle + $Type::ShowWindowAsync($hwnd, 0) + } +} + + + +while ($true) { + + # Check for the escape key press to exit + $isEscapePressed = [Keyboard]::GetAsyncKeyState($VK_ESCAPE) -lt 0 + if ($isEscapePressed) { + if (-not $startTime) { + $startTime = Get-Date + } + $elapsedTime = (Get-Date) - $startTime + if ($elapsedTime.TotalSeconds -ge 5) { + (New-Object -ComObject Wscript.Shell).Popup("Screenshare Closed.",3,"Information",0x0) + sleep 1 + exit + } + } else { + $startTime = $null + } + + + try { + $context = $webServer.GetContext() + $request = $context.Request + $response = $context.Response + + if ($request.RawUrl.StartsWith("/stream?")) { + $query = $request.RawUrl -replace "/stream\?", "" + $params = $query -split "&" + $imgWidth = ($params -match "w=").Split("=")[1] + $imgHeight = ($params -match "h=").Split("=")[1] + + if (-not $imgHeight -or $imgHeight -eq "0") { + Write-Host "Received imgHeight = 0, defaulting to screen height: $screenHeight" + $imgHeight = $screenHeight + } + + Write-Host "Stream started with img size: ${imgWidth}x${imgHeight}" + Start-Streaming -context $context -imgWidth $imgWidth -imgHeight $imgHeight + + } + + elseif ($request.RawUrl.StartsWith("/keypress")) { + $query = $request.RawUrl -replace "/keypress\?", "" + $params = $query -split "&" + $key = ($params -match "key=").Split("=")[1] + + if ($key) { + $decodedKey = [System.Web.HttpUtility]::UrlDecode($key) + + switch ($decodedKey) { + "Backspace" { $decodedKey = "{BACKSPACE}" } + "Enter" { $decodedKey = "{ENTER}" } + } + + Write-Host "Key Pressed: $decodedKey" + [System.Windows.Forms.SendKeys]::SendWait($decodedKey) + } + + $response.StatusCode = 200 + $response.Close() + } + + + elseif ($request.RawUrl.StartsWith("/move")) { + $query = $request.RawUrl -replace "/move\?", "" + $params = $query -split "&" + $moveX = ($params -match "x=").Split("=")[1] + $moveY = ($params -match "y=").Split("=")[1] + + if ($moveX -and $moveY -and $imgWidth -and $imgHeight) { + $scaledX = [math]::Round(($moveX / $imgWidth) * $screenWidth) + $scaledY = [math]::Round(($moveY / $imgHeight) * $screenHeight) + + Write-Host "Move at Browser: ($moveX, $moveY) -> Adjusted to: ($scaledX, $scaledY)" + [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($scaledX, $scaledY) + } + + $response.StatusCode = 200 + $response.Close() + } + + elseif ($request.RawUrl.StartsWith("/click")) { + $query = $request.RawUrl -replace "/click\?", "" + $params = $query -split "&" + $clickX = ($params -match "x=").Split("=")[1] + $clickY = ($params -match "y=").Split("=")[1] + + if ($clickX -and $clickY -and $imgWidth -and $imgHeight) { + $scaledX = [math]::Round(($clickX / $imgWidth) * $screenWidth) + $scaledY = [math]::Round(($clickY / $imgHeight) * $screenHeight) + + Write-Host "Click at Browser: ($clickX, $clickY) -> Adjusted to: ($scaledX, $scaledY)" + [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($scaledX, $scaledY) + [MouseSimulator]::LeftClick() + } + + $response.StatusCode = 200 + $response.Close() + } + + else { $response.ContentType = "text/html" $html = @"
-