I did a test on Windows 10 22H2 ESU. Because the secure desktop (Winlogon) has a very restrictive security descriptor only the SYSTEM account has the necessary permissions to manipulate the UAC consent prompt dialog.
A process running in the user's interactive session as SYSTEM received the EVENT_SYSTEM_DESKTOPSWITCH notification that the secure desktop was active (displaying UAC consent prompt). Upon receiving the notication the process starts a new thread that connects to the secure desktop using the Windows API function SetThreadDesktop. The thread initializes COM in the MTA, creates the Automation COM object and uses the Windows API FindWindow function to obtain a handle to the consent prompt dialog. Then it obtained the dialog's IUIAutomationElement and used that to locate and invoke IUIAutomationElement of the "Yes" button to allow the elevation request. The test did not use keystrokes.
Following is the thread procedure that does the work -
DWORD __stdcall UIAConsentProc(PVOID pv) // Handle to Winlogon Desktop obtained from Winevent handler
{
CCoInitialize init(COINIT_MULTITHREADED);
HRESULT hr{ E_FAIL };
HDESK hDesk = *((HDESK*)pv);
if (!SetThreadDesktop(hDesk))
Report(_T("SetThreadDesktop failed with %d\n"), GetLastError());
// Sleep to allow time for UAC consent prompt to be created on the secure desktop
Sleep(1000);
if (SUCCEEDED(init))
{
CComPtr<IUIAutomation> pAuto;
hr = pAuto.CoCreateInstance(CLSID_CUIAutomation8, nullptr, CLSCTX_INPROC_SERVER);
if (SUCCEEDED(hr))
{
HWND hwndCreds = FindWindow(_T("Credential Dialog Xaml Host"), nullptr);
if (hwndCreds)
{
CComPtr<IUIAutomationElement> pWindow;
hr = pAuto->ElementFromHandle(hwndCreds, &pWindow);
if (SUCCEEDED(hr) && pWindow)
{
CComPtr<IUIAutomationCacheRequest> pCacheRequest;
hr = pAuto->CreateCacheRequest(&pCacheRequest);
if (SUCCEEDED(hr) && pCacheRequest)
{
hr = pCacheRequest->AddPattern(UIA_InvokePatternId);
}
else
Report(_T("CreateCacheRequest, hr: 0x%X, pCacheRequest: %p\n"), hr, pCacheRequest);
CComPtr<IUIAutomationCondition> pTypeCondition, pIdCondition, pCondition;
CComVariant vButton(UIA_ButtonControlTypeId), vID(L"OkButton");
hr = pAuto->CreatePropertyCondition(UIA_ControlTypePropertyId, vButton, &pTypeCondition);
hr = pAuto->CreatePropertyCondition(UIA_AutomationIdPropertyId, vID, &pIdCondition);
hr = pAuto->CreateAndCondition(pTypeCondition, pIdCondition, &pCondition);
if (FAILED(hr) || !pCondition)
Report(_T("CreatePropertyCondition, hr: 0x%X, pCondition: %p\n"), hr, pCondition);
CComPtr<IUIAutomationElement> pYesButton;
hr = pWindow->FindFirstBuildCache(TreeScope_Children, pCondition, pCacheRequest, &pYesButton);
if (SUCCEEDED(hr) && pYesButton)
{
CComPtr<IUIAutomationInvokePattern> pInvoke;
hr = pYesButton->GetCachedPatternAs(UIA_InvokePatternId, IID_PPV_ARGS(&pInvoke));
if (SUCCEEDED(hr) && pInvoke)
pInvoke->Invoke();
}
else
Report(_T("FindFirstBuildCache failed hr: 0x%X, pOK: %p\n"), hr, pYesButton);
}
else
Report(_T("Failed to obtain IUIAutomation element, hr: 0x%X, pWindow: %p\n"), hr, pWindow);
}
else
Report(_T("Failed to find UAC consent prompt window\n"));
}
else
Report(_T("Failed to create Automation Object, 0x%X\n"), hr);
}
else
Report(_T("COM initialization failed: 0x%X\n"), (HRESULT)init);
return 0;
}