我们正在编写一个仅运行的远程桌面应用程序,该应用程序使用SendInput进行键盘(和鼠标(交互。但是,它无法与 UAC 提示交互。
我们的应用程序为此需要哪些权限/权限?
背景信息:应用程序由复制 winlogon .exe 的访问令牌的另一个进程生成。这使可以在具有系统完整性级别的系统帐户下运行,附加到物理控制台会话,并具有与 winlogon 相同的 SE 权限.exe (https://learn.microsoft.com/en-us/windows/desktop/secauthz/privilege-constants(,尽管并非所有权限都已启用。
struct MY_TOKEN_PRIVILEGES {
DWORD PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[2];
};
int RunUnderWinLogon(LPCWSTR executableWithSendInput)
{
DWORD physicalConsoleSessionId = WTSGetActiveConsoleSessionId();
auto winlogonPid = GetWinLogonPid(); // external function
if (!winlogonPid)
{
std::cout << "ERROR getting winlogon pid" << std::endl;
return 0;
}
HANDLE hWinlogonToken, hProcess;
hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
| TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID
| TOKEN_READ | TOKEN_WRITE, &hWinlogonToken))
{
printf("Process token open Error: %un", GetLastError());
}
// Is security descriptor needed for SendInput?
PSECURITY_DESCRIPTOR pSD = NULL;
SECURITY_ATTRIBUTES saToken;
ZeroMemory(&saToken, sizeof(SECURITY_ATTRIBUTES));
saToken.nLength = sizeof (SECURITY_ATTRIBUTES);
saToken.lpSecurityDescriptor = pSD;
saToken.bInheritHandle = FALSE;
HANDLE hWinlogonTokenDup;
if (!DuplicateTokenEx(hWinlogonToken, TOKEN_ALL_ACCESS, &saToken, SecurityImpersonation, TokenPrimary, &hWinlogonTokenDup))
{
printf("DuplicateTokenEx Error: %un", GetLastError());
}
if (!SetTokenInformation(hWinlogonTokenDup, TokenSessionId, (void*)physicalConsoleSessionId, sizeof(DWORD)))
{
printf("SetTokenInformation Error: %un", GetLastError());
}
//Adjust Token privilege
LUID luidSeDebugName;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidSeDebugName))
{
printf("Lookup Privilege value Error: %un", GetLastError());
}
LUID luidSeTcbName;
if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luidSeTcbName))
{
printf("Lookup Privilege value Error: %un", GetLastError());
}
MY_TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 2;
tp.Privileges[0].Luid = luidSeDebugName;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[1].Luid = luidSeTcbName;
tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hWinlogonTokenDup, FALSE, (PTOKEN_PRIVILEGES)&tp, /*BufferLength*/0, /*PreviousState*/(PTOKEN_PRIVILEGES)NULL, NULL))
{
printf("Adjust Privilege value Error: %un", GetLastError());
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("Token does not have the privilegen");
}
DWORD creationFlags;
creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
LPVOID pEnv = NULL;
if (CreateEnvironmentBlock(&pEnv, hWinlogonTokenDup, TRUE))
{
std::cout << "CreateEnvironmentBlock() success" << std::endl;
creationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
SECURITY_ATTRIBUTES saProcess, saThread;
ZeroMemory(&saProcess, sizeof(SECURITY_ATTRIBUTES));
ZeroMemory(&saThread, sizeof(SECURITY_ATTRIBUTES));
saProcess.nLength = sizeof (SECURITY_ATTRIBUTES);
saProcess.lpSecurityDescriptor = pSD;
saProcess.bInheritHandle = FALSE;
saThread.nLength = sizeof (SECURITY_ATTRIBUTES);
saThread.lpSecurityDescriptor = pSD;
saThread.bInheritHandle = FALSE;
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = (LPWSTR)L"winsta0\default";
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
BOOL bResult = CreateProcessAsUser(
hWinlogonTokenDup, // client's access token
executableWithSendInput, // file using SendInput
NULL, // command line
&saProcess, // pointer to process SECURITY_ATTRIBUTES
&saThread, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
creationFlags, // creation flags
pEnv, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
}
SendInput
,如 SendMessage 和 PostMessage 仅限于在与目标进程相同的登录会话和同一桌面中的进程之间工作。UAC 提示显示在 Winlogon 的安全桌面 ( winsta0Winlogon
( 中,因此您需要定期轮询当前桌面OpenInputDesktop()
然后使用 SetThreadDesktop()
使当前线程能够将消息发送到用户的桌面/安全桌面,以活动状态为准。
如果是 UAC,您需要在系统帐户下运行流程,以符合 UIPI 完整性级别检查,就像您已经做的那样。
另请参阅:如何在默认桌面和 Winlogon 桌面之间切换进程?
可以授权应用程序能够执行这些 UIAutomation/屏幕阅读器任务。
在程序集清单中创建一个条目,其中包括:
uiAccess="true"
然后,您必须使用有效的数字证书进行数字签名。
而且您必须安装在Program Files
能够自动化 UAC 对话是一项严肃的事情;而且您不会随意搞砸。
奖金阅读
https://techcommunity.microsoft.com/t5/windows-blog-archive/using-the-uiaccess-attribute-of-requestedexecutionlevel-to/ba-p/228641