从模拟用户下启动的某些系统默认 .lnk 文件的问题
Problems with some system default .lnk-files launching from under an impersonated user
我正在编写 32 位服务应用程序,我希望能够在其中为 已登录用户 启动“开始”菜单项。我确实设法通过模拟用户并使用 CreateProcessAsUser 和命令行启动选定的 .lnk 文件来完成此任务:%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "
。它适用于几乎所有快捷方式,除了 Accessories 文件夹中的一堆系统快捷方式(例如 Sticky Notes.lnk、Snipping Tool.lnk)。在启动截图工具期间,我从 cmd 收到带有此错误的消息框:
Windows cannot find 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk'. Make sure you typed the name correctly, and then try again.
但是 .lnk 文件存在于这个目录中!
总结:
- 服务是 32 位
- Windows 8 专业版 x64
- 通过用户模拟和使用命令行的 CreateProcessAsUser 启动快捷方式
%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "
- 此方法几乎适用于“开始”菜单中的所有快捷方式,但 Start/Accessories 文件夹中的某些快捷方式除外(并非全部,例如 Paint.lnk 可以正常打开)
示例代码:
int launchAppForCurrentLoggedUser()
{
HANDLE userToken = WTSApiHelper::currentLoggedUserToken();
if (userToken == INVALID_HANDLE_VALUE) {
return -1;
}
//Duplicating token with access TOKEN_DUPLICATE | TOKEN_ALL_ACCESS,
//impersonation level SecurityImpersonation and token type TokenPrimary.
//Also closing original userToken
HANDLE dup = WTSApiHelper::duplicateToken(userToken);
if (dup == INVALID_HANDLE_VALUE) {
return -1;
}
int res = -1;
uint8 *env = NULL;
BOOL succeeded = CreateEnvironmentBlock((LPVOID *)&env, dup, FALSE);
if (!succeeded) {
Log("failed to get environment variables for user (error 0x%x).", GetLastError());
}
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
STARTUPINFOW si;
memset(&si, 0, sizeof(STARTUPINFOW));
si.cb = sizeof(STARTUPINFOW);
si.lpDesktop = L"winsta0\Default";
WCHAR params[] = L"/c \" start /b /i \"\" \"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk\" \" ";
WCHAR cmd[] = L"C:\Windows\system32\cmd.exe";
DWORD flags = env ? CREATE_UNICODE_ENVIRONMENT : 0;
succeeded = CreateProcessAsUserW(dup, cmd, params, NULL, NULL, FALSE, flags | CREATE_NO_WINDOW, env, NULL, &si, &pi);
if (!succeeded) {
Log("cannot launch process for user with error 0x%x.", GetLastError());
} else {
nres = 0;
}
DestroyEnvironmentBlock(env);
CloseHandle(dup);
return nres;
}
我在这里想念什么?
CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key. Therefore, to access the information in the HKEY_CURRENT_USER registry key, you must load the user's profile information into HKEY_USERS with the LoadUserProfile function before calling CreateProcessAsUser. Be sure to call UnloadUserProfile after the new process exits.
MSDN 建议使用 CreateProcessWithLogonW 或 CreateProcessWithTokenW,或者手动加载用户的配置文件信息。
还有:
CreateProcessAsUser allows you to access the specified directory and executable image in the security context of the caller or the target user. By default, CreateProcessAsUser accesses the directory and executable image in the security context of the caller. In this case, if the caller does not have access to the directory and executable image, the function fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to the ImpersonateLoggedOnUser function before calling CreateProcessAsUser.
丢失的不是 LNK 文件,而是它的目标。
似乎是 WOW64 问题 -- 对于您的 32 位服务,%WINDIR%\System32
实际上重定向到 SysWOW64
并且这些可执行文件不存在。
嗯,实际上你的32位服务是在寻找SysWOW64
中确实存在的32位cmd.exe
,然后32位cmd.exe出现上述问题,当查找在快捷方式中找到的路径 %windir%\system32\SnippingTool.exe
.
我可以使用 32 位命令提示符重现该问题。尝试使用这些快捷方式的 32 位进程会失败。
尝试使用 %WINDIR%\SysNative\cmd.exe
生成本机版本的 cmd.exe
(在您的系统上为 64 位)
此外,您有引用问题。您试图嵌套引号,但实际发生的是第二个引号与第一个引号匹配并退出引号,而不是嵌套。
将来,当服务出现故障时,运行 来自普通控制台应用程序的相同调用会很有帮助。在这种情况下,您会立即发现问题与模拟完全无关。第二步,如果它在控制台应用程序中工作,运行配置文件中将使用控制台应用程序 "Run As" 来测试模拟逻辑,仍然没有服务环境的额外复杂性。
我正在编写 32 位服务应用程序,我希望能够在其中为 已登录用户 启动“开始”菜单项。我确实设法通过模拟用户并使用 CreateProcessAsUser 和命令行启动选定的 .lnk 文件来完成此任务:%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "
。它适用于几乎所有快捷方式,除了 Accessories 文件夹中的一堆系统快捷方式(例如 Sticky Notes.lnk、Snipping Tool.lnk)。在启动截图工具期间,我从 cmd 收到带有此错误的消息框:
Windows cannot find 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk'. Make sure you typed the name correctly, and then try again.
但是 .lnk 文件存在于这个目录中!
总结:
- 服务是 32 位
- Windows 8 专业版 x64
- 通过用户模拟和使用命令行的 CreateProcessAsUser 启动快捷方式
%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "
- 此方法几乎适用于“开始”菜单中的所有快捷方式,但 Start/Accessories 文件夹中的某些快捷方式除外(并非全部,例如 Paint.lnk 可以正常打开)
示例代码:
int launchAppForCurrentLoggedUser() { HANDLE userToken = WTSApiHelper::currentLoggedUserToken(); if (userToken == INVALID_HANDLE_VALUE) { return -1; } //Duplicating token with access TOKEN_DUPLICATE | TOKEN_ALL_ACCESS, //impersonation level SecurityImpersonation and token type TokenPrimary. //Also closing original userToken HANDLE dup = WTSApiHelper::duplicateToken(userToken); if (dup == INVALID_HANDLE_VALUE) { return -1; } int res = -1; uint8 *env = NULL; BOOL succeeded = CreateEnvironmentBlock((LPVOID *)&env, dup, FALSE); if (!succeeded) { Log("failed to get environment variables for user (error 0x%x).", GetLastError()); } PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); STARTUPINFOW si; memset(&si, 0, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); si.lpDesktop = L"winsta0\Default"; WCHAR params[] = L"/c \" start /b /i \"\" \"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk\" \" "; WCHAR cmd[] = L"C:\Windows\system32\cmd.exe"; DWORD flags = env ? CREATE_UNICODE_ENVIRONMENT : 0; succeeded = CreateProcessAsUserW(dup, cmd, params, NULL, NULL, FALSE, flags | CREATE_NO_WINDOW, env, NULL, &si, &pi); if (!succeeded) { Log("cannot launch process for user with error 0x%x.", GetLastError()); } else { nres = 0; } DestroyEnvironmentBlock(env); CloseHandle(dup); return nres; }
我在这里想念什么?
CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key. Therefore, to access the information in the HKEY_CURRENT_USER registry key, you must load the user's profile information into HKEY_USERS with the LoadUserProfile function before calling CreateProcessAsUser. Be sure to call UnloadUserProfile after the new process exits.
MSDN 建议使用 CreateProcessWithLogonW 或 CreateProcessWithTokenW,或者手动加载用户的配置文件信息。
还有:
CreateProcessAsUser allows you to access the specified directory and executable image in the security context of the caller or the target user. By default, CreateProcessAsUser accesses the directory and executable image in the security context of the caller. In this case, if the caller does not have access to the directory and executable image, the function fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to the ImpersonateLoggedOnUser function before calling CreateProcessAsUser.
丢失的不是 LNK 文件,而是它的目标。
似乎是 WOW64 问题 -- 对于您的 32 位服务,%WINDIR%\System32
实际上重定向到 SysWOW64
并且这些可执行文件不存在。
嗯,实际上你的32位服务是在寻找SysWOW64
中确实存在的32位cmd.exe
,然后32位cmd.exe出现上述问题,当查找在快捷方式中找到的路径 %windir%\system32\SnippingTool.exe
.
我可以使用 32 位命令提示符重现该问题。尝试使用这些快捷方式的 32 位进程会失败。
尝试使用 %WINDIR%\SysNative\cmd.exe
cmd.exe
(在您的系统上为 64 位)
此外,您有引用问题。您试图嵌套引号,但实际发生的是第二个引号与第一个引号匹配并退出引号,而不是嵌套。
将来,当服务出现故障时,运行 来自普通控制台应用程序的相同调用会很有帮助。在这种情况下,您会立即发现问题与模拟完全无关。第二步,如果它在控制台应用程序中工作,运行配置文件中将使用控制台应用程序 "Run As" 来测试模拟逻辑,仍然没有服务环境的额外复杂性。