文章目录
提示:以下是本篇文章正文内容,下面整理可供参考
PC端程序以管理员权限运行,想要做到在任意系统中开机自启动,经研究发现好像无法实现。
方案一:设置到启动项里。administrator账号登录系统的可以开机自启动,其他账号登录系统开启自启动全部失败。
方案二:做一个windows服务,服务启动PC端程序。服务可以开机自启动,但是服务启动的程序要么是system权限,要么是账户权限,无法保证以管理员权限运行。
以下是我在研究过程中总结的windows权限相关知识。
一、windows系统账户权限
Windows中权限指的是不同账户文件、文件夹、注册表等的访问能力。一般我们常用的权限分为普通账户权限、管理员账户权限和system账户权限。
二、权限优缺点
1. 普通账户权限
优点:
1.权限最小化原则,确保用户资源得到最大保障;
2.普通权限程序支持任意账户登录的开机自启动;
缺点:
1. 启动以管理员权限启动的程序时,会弹出用户账户控制(UAC)弹窗;
2. 无法访问服务列表,判断服务程序有没有启动;
3. 无法修改或删除Program Files等管理员权限路径下的文件,仅能查看;
4. 程序无法删掉以管理员权限运行的进程;
2、管理员权限
优点:
1. 可以访问服务列表,运行服务程序;
2. 可正常修改或删除访问Program Files等管理员权限路径下所有文件;
3. 可以启动普通权限运行的程序并赋予管理员权限;
缺点:
1. 普通账户登录的系统,无法开机自启动;
2. 程序无法杀掉system权限运行的进程;
3、system权限
优点:
1. 程序以windows服务托管运行,支持开机自启动;
2. 可以以用户登录账户权限或system权限启动动外部程序;
缺点:
1. system权限获取桌面路径、appdata路径时,默认访问的是system相关路径,不是当前桌面路径;
2. 程序不是在主线程中运行(很难理解)
3. 弹出选择路径弹窗时,会报错或者无法选择桌面路径;
4. 无法打开系统默认浏览器、文本编辑器等,因为程序运行权限超过系统登录账户范畴;
三、跨权限相关调用
1. 启动外部程序
需要注意普通权限调用以管理员权限运行的程序时,会弹出UAC弹窗
QString filePath = QString("D:123.exe");
//SW_SHOW:以正常窗口大小启动外部程序;SW_HIDE:以隐藏窗口启动外部程序
int ret = (int)ShellExecute(NULL, NULL, (LPCSTR)filePath.toLocal8Bit(), NULL, NULL, SW_SHOW);
2. system权限获取当前用户桌面路径
//首先获取当前用户登录token
static HANDLE GetCurrentLogonUserToken()
{
//The following api call fails to get a valid session id if remote desktop /team viewer is running at startup
UINT dwSessionId = WTSGetActiveConsoleSessionId();
//LOG_DEBUG("Session id from WTSGetActiveConsoleSessionId:%d", dwSessionId);
HANDLE hImpersonationToken = NULL;
if (!WTSQueryUserToken(dwSessionId, &hImpersonationToken))
{
//LOG_ERROR("Exception in WTSQueryUserToken:%d Proceeding to enumerate sessions!", GetLastError());
}
else
{
//LOG_DEBUG("Returning WTSGetActiveConsoleSessionId Token:%d", hImpersonationToken);
WCHAR* pUserName;
DWORD user_name_len = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSUserName, &pUserName, &user_name_len))
{
//LOG_INFO("UserName from sessionId is %s:", pUserName);
if (pUserName) {
WTSFreeMemory(pUserName);
}
return hImpersonationToken;
}
else
{
//LOG_ERROR("Exception in WTSQuerySessionInformation:%d! Returning Null Impersonation Token", GetLastError());
return NULL;
}
}
DWORD sessionCount = 0;
WTS_SESSION_INFOA* pSession = NULL;
try {
if (!WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &sessionCount))
{
//LOG_ERROR("WTSEnumerateSessionsA failed. errcode=%d", GetLastError());
return NULL;
}
}
catch (...) {}
//LOG_INFO("Begin Enumerating Sesions : %d", sessionCount);
DWORD sessionId = -1;
for (DWORD i = 0; i < sessionCount; i++)
{
sessionId = pSession[i].SessionId;
//LOG_DEBUG("SessionId:%d", sessionId);
WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
DWORD bytes_returned = 0;
if (::WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE,
sessionId,
WTSConnectState,
reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
&bytes_returned))
{
wts_connect_state = *ptr_wts_connect_state;
::WTSFreeMemory(ptr_wts_connect_state);
if (wts_connect_state != WTSActive)
{
//LOG_WARNING("wts_connect_state != WTSActive! Continuing ###");
continue;
}
}
else
{
//LOG_WARNING("Error in WTSQuerySessionInformation:%d: Continuing ###", GetLastError());
continue;
}
}
//LOG_INFO("session_id from enumerating sessions: %d, from WTSGetActiveConsoleSessionId:%d", sessionId, dwSessionId);
if (sessionId == -1) {
//LOG_ERROR("Fatal Error: Failed to get session_id by both methods");
return NULL;
}
if (!WTSQueryUserToken(sessionId, &hImpersonationToken))
{
DWORD err = GetLastError();
//LOG_ERROR("Fatal Error: Failed WTSQueryUserToken on enumerated sessionid: %d", err);
return NULL;
}
// Get user name of this process
//LPTSTR pUserName = NULL;
WCHAR* pUserName;
DWORD user_name_len = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pUserName, &user_name_len))
{
//log username contained in pUserName WCHAR string
// char * lpszUserName = WideCharToChar(pUserName);
//LOG_INFO("UserName from session_id [after enumeration] is %s:", pUserName);
if (pUserName) {
WTSFreeMemory(pUserName);
}
return hImpersonationToken;
}
else
{
//LOG_ERROR("Exception in WTSQuerySessionInformation:%d! Returning Null Impersonation Token", GetLastError());
return NULL;
}
}
#include <ShlObj_core.h>
//然后根据token可以获取当前系统登录账户下桌面路径、appdata路径等
BROWSEINFOW bi;
wchar_t initPath[MAX_PATH];
initPath[0] = 0;
std::wstring wsValue = L"";
//CSIDL_DESKTOPDIRECTORY:桌面路径
//CSIDL_APPDATA:Application Data路径
//CSIDL_STARTMENU:Start Menu路径
if (SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_DESKTOPDIRECTORY, hToken, SHGFP_TYPE_DEFAULT, initPath))) {
qDebug() << QString("get deskop success");
wsValue = initPath;
}
QString path = QString::fromStdWString(wsValue);
3. system权限下启动外部程序
a. 以system权限启动外部程序
bool createProcessWithAdmin(DWORD& pid, const QString& strProcessName, const QString& pCmdLine /*= NULL*/)
{
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
LPVOID pEnv = NULL;
pid = 0;
if (strProcessName.isEmpty()) {
return false;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) {
qDebug()<< QString("OpenProcessToken failed, errcode=%1").arg(GetLastError());
return false;
}
do {
//if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityIdentification, TokenPrimary, &hTokenDup))
//{
// qDebug() << QString("DuplicateTokenEx failed, errcode=%1").arg(GetLastError());
// break;
//}
if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &hTokenDup))
{
CloseHandle(hToken);
return false;
}
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD)))
{
qDebug()<<QString("SetTokenInformation failed");
break;
}
if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE)) {
qDebug()<<QString("CreateEnvironmentBlock failed");
break;
}
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
if (!CreateProcessAsUser(hTokenDup,getTransCodeByteArray(strProcessName).data(), getTransCodeByteArray(pCmdLine).data(), NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi))
{
qDebug() << QString("CreateProcessAsUser failed, errcode=%1").arg(GetLastError());
break;
}
//if (!CreateProcessAsUserW(hTokenDup, strProcessName.c_str(), pCmdLine, NULL, NULL, FALSE,dwCreationFlag,pEnv, NULL, &si, &pi))
//{
// qDebug() << QString("CreateProcessAsUserW failed, errcode=%1").arg(GetLastError());
// break;
//}
CloseHandleSafe(pi.hProcess);
CloseHandleSafe(pi.hThread);
if (pEnv) {
DestroyEnvironmentBlock(pEnv);
}
CloseHandleSafe(hToken);
CloseHandleSafe(hTokenDup);
pid = pi.dwProcessId;
return true;
} while (0);
if (pEnv != NULL) {
DestroyEnvironmentBlock(pEnv);
}
CloseHandleSafe(hTokenDup);
CloseHandleSafe(hToken);
return false;
}
b. 以当前用户登录权限启动外部程序
//首先获取当前用户令牌
static HANDLE GetCurrentLogonUserToken()
{
//The following api call fails to get a valid session id if remote desktop /team viewer is running at startup
UINT dwSessionId = WTSGetActiveConsoleSessionId();
//LOG_DEBUG("Session id from WTSGetActiveConsoleSessionId:%d", dwSessionId);
HANDLE hImpersonationToken = NULL;
if (!WTSQueryUserToken(dwSessionId, &hImpersonationToken))
{
//LOG_ERROR("Exception in WTSQueryUserToken:%d Proceeding to enumerate sessions!", GetLastError());
}
else
{
//LOG_DEBUG("Returning WTSGetActiveConsoleSessionId Token:%d", hImpersonationToken);
WCHAR* pUserName;
DWORD user_name_len = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, dwSessionId, WTSUserName, &pUserName, &user_name_len))
{
//LOG_INFO("UserName from sessionId is %s:", pUserName);
if (pUserName) {
WTSFreeMemory(pUserName);
}
return hImpersonationToken;
}
else
{
//LOG_ERROR("Exception in WTSQuerySessionInformation:%d! Returning Null Impersonation Token", GetLastError());
return NULL;
}
}
DWORD sessionCount = 0;
WTS_SESSION_INFOA* pSession = NULL;
try {
if (!WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &sessionCount))
{
//LOG_ERROR("WTSEnumerateSessionsA failed. errcode=%d", GetLastError());
return NULL;
}
}
catch (...) {}
//LOG_INFO("Begin Enumerating Sesions : %d", sessionCount);
DWORD sessionId = -1;
for (DWORD i = 0; i < sessionCount; i++)
{
sessionId = pSession[i].SessionId;
//LOG_DEBUG("SessionId:%d", sessionId);
WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
DWORD bytes_returned = 0;
if (::WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE,
sessionId,
WTSConnectState,
reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
&bytes_returned))
{
wts_connect_state = *ptr_wts_connect_state;
::WTSFreeMemory(ptr_wts_connect_state);
if (wts_connect_state != WTSActive)
{
//LOG_WARNING("wts_connect_state != WTSActive! Continuing ###");
continue;
}
}
else
{
//LOG_WARNING("Error in WTSQuerySessionInformation:%d: Continuing ###", GetLastError());
continue;
}
}
//LOG_INFO("session_id from enumerating sessions: %d, from WTSGetActiveConsoleSessionId:%d", sessionId, dwSessionId);
if (sessionId == -1) {
//LOG_ERROR("Fatal Error: Failed to get session_id by both methods");
return NULL;
}
if (!WTSQueryUserToken(sessionId, &hImpersonationToken))
{
DWORD err = GetLastError();
//LOG_ERROR("Fatal Error: Failed WTSQueryUserToken on enumerated sessionid: %d", err);
return NULL;
}
// Get user name of this process
//LPTSTR pUserName = NULL;
WCHAR* pUserName;
DWORD user_name_len = 0;
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pUserName, &user_name_len))
{
//log username contained in pUserName WCHAR string
// char * lpszUserName = WideCharToChar(pUserName);
//LOG_INFO("UserName from session_id [after enumeration] is %s:", pUserName);
if (pUserName) {
WTSFreeMemory(pUserName);
}
return hImpersonationToken;
}
else
{
//LOG_ERROR("Exception in WTSQuerySessionInformation:%d! Returning Null Impersonation Token", GetLastError());
return NULL;
}
}
//以当前用户登录权限启动外部程序
bool createProcessWithUser(OUT DWORD& pid, const QString& strProcessName, const QString& pCmdLine /*= NULL*/)
{
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
LPVOID pEnv = NULL;
pid = 0;
hToken = GetCurrentLogonUserToken();
if (hToken == NULL) {
qDebug() << QString("GetCurrentLogonUserToken failed, errcode=%1").arg(GetLastError());
return false;
}
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup))
{
qDebug() << QString("DuplicateTokenEx failed, errcode=%1").arg(GetLastError());
return false;
}
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionID, sizeof(DWORD)))
{
qDebug() << QString("SetTokenInformation failed");
return false;
}
if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE))
{
qDebug() << QString("CreateEnvironmentBlock failed");
return false;
}
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
if (!CreateProcessAsUser(hTokenDup, getTransCodeByteArray(strProcessName).data(), getTransCodeByteArray(pCmdLine).data(), NULL, NULL, FALSE,
dwCreationFlags, pEnv, NULL, &si, &pi))
{
qDebug() << QString("CreateProcessAsUserW failed, errcode=%1").arg(GetLastError());
return false;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (pEnv != NULL) {
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(hTokenDup);
CloseHandle(hToken);
pid = pi.dwProcessId;
return true;
if (pEnv != NULL) {
DestroyEnvironmentBlock(pEnv);
}
CloseHandleSafe(hTokenDup);
CloseHandleSafe(hToken);
return false;
}