No description
Find a file
2026-08-09 18:45:41 +07:00
gui GUI: drop post-fix recheck — registry fix is one-time 2026-08-09 18:37:51 +07:00
wiki Add project wiki: UAC/winruntime pages (schema, registry, events, index, log) 2026-08-09 18:45:41 +07:00
.gitignore winruntime: SYSTEM UAC one-shot clicker with armed-mode + Wails arm GUI 2026-08-09 18:26:55 +07:00
Program.cs winruntime: SYSTEM UAC one-shot clicker with armed-mode + Wails arm GUI 2026-08-09 18:26:55 +07:00
README.md Add UAC registry prerequisites: setup-uac.cmd + README setup docs 2026-08-09 18:33:33 +07:00
run_helper.cmd winruntime: SYSTEM UAC one-shot clicker with armed-mode + Wails arm GUI 2026-08-09 18:26:55 +07:00
setup-uac.cmd Add UAC registry prerequisites: setup-uac.cmd + README setup docs 2026-08-09 18:33:33 +07:00
winruntime.csproj winruntime: SYSTEM UAC one-shot clicker with armed-mode + Wails arm GUI 2026-08-09 18:26:55 +07:00

WinRuntime

A SYSTEM-integrity helper that clicks Yes on a Windows UAC prompt exactly once, when explicitly armed. Built to automate UniGetUI's "Update as administrator" flow without you babysitting the elevation dialog.

Why it exists

When UniGetUI updates packages as administrator, Windows shows a UAC consent dialog ("Do you want to allow this app to make changes to your device?"). Normally you must click Yes manually, and on Win11 the secure-desktop UAC can't be automated with normal input simulation. This project runs a tiny helper at System integrity that listens for the UAC window and posts the keyboard messages that activate the Yes button — but only when you have armed it, and for exactly one prompt.

Architecture

Two components:

Component Runs as Role
winruntime.exe (C# / .NET 8) System (via gsudo -i System) Tray icon + listens for UAC window + performs the one-shot Yes click
winruntimeui.exe (Go / Wails) normal user (elevated for password setup) Password gate: arm / disarm / status, first-run password setup
winruntimeui.exe ──named pipe──▶ winruntime.exe (System)
  (arm with password)            \__ clicks UAC Yes once, then disarms

The click

On this machine UAC is configured to show inline on the Default desktop (PromptOnSecureDesktop=0). Win11's UAC is DirectUI — EnumChildWindows returns zero button HWNDs, and SendInput from System integrity is denied (err=5). The working strategy is message-based:

PostMessage(hwnd, WM_SYSKEYDOWN, VK_Y, 0x20150001)   // Alt held, 'Y' pressed
PostMessage(hwnd, WM_SYSKEYUP,   VK_Y, 0xE0150001)

This activates the Yes accelerator. Note: posting plain Enter clicks No (the safe default) on Win11, so it is only a last-resort fallback.

Security model

The helper is disarmed by default and will never click unless armed:

  • One-shot: each arm is consumed by exactly one UAC prompt, then the helper re-disarms (also on a 60 s timeout).
  • Password: arming requires the password, verified against a salted SHA-256 hash. The plaintext password is never stored, logged, or sent in the clear over the pipe.
  • Protected config: the hash lives in C:\ProgramData\WinRuntime\winruntime.hash with an ACL allowing only SYSTEM/Administrators — a non-elevated process can't delete it to force a reset.
  • Elevation-gated setup: the initial password can only be set by an elevated caller (verified via the pipe client's token). A non-elevated process gets NEED_ADMIN.
  • Brute-force lockout: 3 wrong ARM attempts → 30 s lock, doubling each round.
  • Password policy: minimum 8 characters.

Honest caveat: UAC in the default same-desktop configuration is a consent prompt, not a malware boundary. An already-elevated attacker on this machine can bypass all of this — that is by design.

Build

Helper (C#)

cd winruntime
dotnet publish -c Release -r win-x64 -o out

GUI (Wails / Go)

cd gui
wails build
copy build\bin\winruntimeui.exe ..\out\

Deploy & first run

0. One-time UAC prerequisites (per machine, elevated)

The whole approach depends on the UAC prompt appearing inline on your desktop rather than on the secure Winlogon desktop. A System helper in WinSta0 simply cannot see (or reach) the secure desktop.

Run as Administrator (or use the included script):

# setup-uac.cmd  — must be elevated
.\setup-uac.cmd

That sets (under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System):

Key Value Why
EnableLUA 1 UAC exists at all
PromptOnSecureDesktop 0 UAC shows inline on the Default desktop — required
ConsentPromptBehaviorAdmin 5 Keep "prompt for consent" (do NOT set 0, that silently auto-elevates everything and defeats the purpose)
ValidateAdminCodeSignatures 0 Don't require signed binaries for elevation

Changes to EnableLUA/PromptOnSecureDesktop require a reboot to take effect. After the script, verify:

reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v PromptOnSecureDesktop

You should see 0x0. The helper logs the detected input desktop at startup (input desktop = 'Default'); if you see Winlogon, the prompt is on the secure desktop and the inline prerequisite is missing.

1. Build

Helper (C#)

cd winruntime
dotnet publish -c Release -r win-x64 -o out

GUI (Wails / Go)

cd gui
wails build
copy build\bin\winruntimeui.exe ..\out\

2. Launch the helper as System

Requires gsudo:

gsudo -i System -- .\winruntime\run_helper.cmd

You'll see the WinRuntime shield icon in the tray.

3. One-time password setup (elevated)

Open the GUI as Administrator (elevation is required for the one-time password setup):

Start-Process .\winruntime\out\winruntimeui.exe -Verb RunAs

In the GUI: Set password (min 8 chars). From then on, normal launches can arm.

4. Arm & trigger

Click Arm (one click) with the password → trigger "Update as administrator" in UniGetUI → the helper clicks Yes once and disarms.

Daily use

  • Arm: open the GUI (double-click the tray icon), enter password, click Arm. You have 60 s.
  • Tray icon: double-click opens the GUI. Closing the GUI window hides it to the tray (process stays alive); re-open via the tray icon. Right-click → Exit / stop auto-click kills helper + GUI.
  • Status sync: the GUI polls the helper every 2 s, so it flips to IDLE automatically after the one-shot click is consumed.

Files

winruntime/
├── Program.cs              # helper: UAC detection + click strategies + pipe auth
├── winruntime.csproj
├── run_helper.cmd          # gsudo System launcher for the helper
├── setup-uac.cmd           # one-time registry prerequisites (elevated)
└── gui/                    # Wails arm GUI (Go + vanilla JS)
    ├── main.go             # app entry, hide-to-tray on close
    ├── app.go              # pipe client: ARM/STATUS/SETUP/DISARM
    └── frontend/           # UI (password field, arm/disarm, status)

Troubleshooting

  • ERR: helper not reachable — the helper isn't running (or not as System). Check the tray icon / restart via run_helper.cmd.
  • NEED_ADMIN on Set password — run the GUI as Administrator.
  • LOCKED:… — too many wrong ARM attempts; wait out the lockout.
  • No click happens — the helper must run at System integrity (S-1-16-16384) and the UAC must be inline (not on the secure desktop). Check winruntime.log for the detected integrity level and input desktop; if it shows Winlogon, run setup-uac.cmd (elevated) and reboot.

Verification probe

uac_elev_probe.cmd (outside this repo) writes a marker to C:\Program Files\ from an elevated child — if the marker exists and the child reports ADMIN=YES, the Yes-click genuinely elevated the process. This is how the Alt+Y strategy was verified end-to-end.