【问题标题】:Problems with some system default .lnk-files launching from under an impersonated user从模拟用户下启动的某些系统默认 .lnk 文件的问题
【发布时间】:2015-10-25 14:07:00
【问题描述】:

我正在编写 32 位服务应用程序,希望能够为 登录的用户 启动开始菜单项。我确实设法通过模拟用户并使用 CreateProcessAsUser 和命令行启动选定的 .lnk 文件来完成此任务:%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "。它几乎适用于所有快捷方式,除了 Accessories 文件夹中的一堆系统快捷方式(例如 Sticky Notes.lnk、Snipping Tool.lnk)。在启动截图工具期间,我从 cmd 收到带有此错误的消息框:

Windows 找不到“C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Snipping Tool.lnk”。请确保您输入的名称正确,然后重试。

但是 .lnk 文件就存在于这个目录中!

总结:

  • 服务是 32 位的
  • Windows 8 Pro x64
  • 通过用户模拟和 CreateProcessAsUser 使用命令行启动快捷方式%windir%\system32\cmd /c " start /b /i "" "<path-to-lnk-file>" "
  • 该方法几乎适用于“开始”菜单中的所有快捷方式,但“开始/附件”文件夹中的一些快捷方式除外(并非所有快捷方式,例如 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: "lpCommandLine: 这个函数的Unicode版本,CreateProcessAsUserW,可以修改这个字符串的内容,所以这个参数不能是指针到只读内存(例如const变量或文字字符串)。如果此参数是常量字符串,则该函数可能会导致访问冲突。”
  • @IInspectable,我知道,指定的代码有点简化。
  • 简化和引入错误是有区别的。简化版本将使用WCHAR params[] = L"/c [...] ";。同样简单,但正确。
  • @IInspectable 是的,你是对的,我的错。我会马上解决这个问题。

标签: c++ windows winapi impersonation lnk


【解决方案1】:

CreateProcessAsUser 不会将指定用户的配置文件加载到 HKEY_USERS 注册表项中。因此,要访问 HKEY_CURRENT_USER 注册表项中的信息,您必须在调用 CreateProcessAsUser 之前使用 LoadUserProfile 函数将用户的配置文件信息加载到 HKEY_USERS 中。请务必在新进程退出后调用 UnloadUserProfile。

According to the msdn page

MSDN 建议使用 CreateProcessWithLogonW 或 CreateProcessWithTokenW,或者手动加载用户的 profile 信息。

还有:

CreateProcessAsUser 允许您在调用者或目标用户的安全上下文中访问指定的目录和可执行映像。默认情况下,CreateProcessAsUser 访问调用者安全上下文中的目录和可执行映像。在这种情况下,如果调用者无权访问目录和可执行映像,则函数将失败。要使用目标用户的安全上下文访问目录和可执行映像,请在调用 CreateProcessAsUser 之前在对 ImpersonateLoggedOnUser 函数的调用中指定 hToken。

【讨论】:

  • 根据问题,用户已登录(因此,他们的个人资料已加载)。
【解决方案2】:

丢失的不是 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 位)

此外,您还有报价问题。您正在尝试嵌套引号,但实际发生的是第二个引号与第一个引号匹配并退出引用,而不是嵌套。

将来,当服务出现故障时,从普通控制台应用程序运行相同的调用会很有帮助。在这种情况下,您会立即发现该问题与冒充完全无关。第二步,如果它在配置文件中运行的控制台应用程序中运行,则将使用控制台应用程序的“运行方式”来测试模拟逻辑,但仍然不会增加服务环境的复杂性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-05
    • 2020-07-09
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 2017-10-18
    • 2013-07-18
    • 1970-01-01
    相关资源
    最近更新 更多