0

使用 ANCI C 和 Windows API:

我从 Windows 7 服务应用程序(在会话 0 中运行)调用函数CreateProcessAsUser(,,,)以在用户登录到会话 1 时启动应用程序。

这很好用。服务以这种方式启动后应用程序表现出的所有行为都是正常的,除非用户通常可以访问的网络位置(即,好像应用程序是从会话 1 启动的)不再可用

所以我的问题是:

  1. 如果我为正确登录会话 1 的用户复制了令牌,为什么在使用此令牌启动应用程序时,它无法访问该用户通常可以访问的网络位置中的数据?

  2. 除了使用 CreateProcessAsUser 函数之外,我是否还缺少其他步骤来恢复网络可访问性?

注意: 我特别选择了 CreateProcessAsUser(与 CreateProcessWithLogonW 等其他选择相反)以避免在源代码中维护和传递用户凭据。

有什么建议么?

以下是我以会话 1 用户身份从 Windows 服务启动应用程序的源代码:

BOOL LaunchAppIntoDifferentSession(char *AtsAppPathName) 
{
  PROCESS_INFORMATION pi;
  STARTUPINFO si;
  BOOL bResult = FALSE;
  DWORD dwSessionId;
  DWORD winlogonPid = 0;
  HANDLE hUserToken,hUserTokenDup,hPToken,hProcess;
  DWORD dwCreationFlags;

  // Log the client on to the local computer.
  dwSessionId = WTSGetActiveConsoleSessionId();

  // Find the winlogon process
  PROCESSENTRY32 procEntry;

  HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (hSnap == INVALID_HANDLE_VALUE)
  {
    return 1 ;
  }

  procEntry.dwSize = sizeof(PROCESSENTRY32);

  if (!Process32First(hSnap, &procEntry))
  {
    CloseHandle(hSnap);
    return 1 ;
  }

  do
  {
      if (stricmp(procEntry.szExeFile, "winlogon.exe") == 0)
      {
        // found a winlogon process...make sure it's running in the console session
        DWORD winlogonSessId = 0;
          if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)
          {
            winlogonPid = procEntry.th32ProcessID;
            break;
          }
      }

  } while (Process32Next(hSnap, &procEntry));

  WTSQueryUserToken(dwSessionId,&hUserToken);
  dwCreationFlags = NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb= sizeof(STARTUPINFO);
  si.lpDesktop = "winsta0\\default";
  ZeroMemory(&pi, sizeof(pi));
  TOKEN_PRIVILEGES tp;
  LUID luid;
  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,&hPToken))
  {
    sprintf(gTempBuf, "Process token open Error: %u",GetLastError()); 
    if(LOG_ERR==1) WriteToLog("gTempBuf");

  }

  if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
  {
    sprintf(gTempBuf, "Lookup Privilege value Error: %u",GetLastError()); 
    if(LOG_ERR==1) WriteToLog("gTempBuf");
  }
  tp.PrivilegeCount =1;
  tp.Privileges[0].Luid =luid;
  tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
  if(!DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityImpersonation,TokenPrimary,&hUserTokenDup))
  {
    sprintf(gTempBuf, "DuplicateTokenEx return Error: %u",GetLastError()); 
    if(LOG_ERR==1) WriteToLog("gTempBuf");
  }

  //Adjust Token privilege
  SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));

  if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL))
  {
    sprintf(gTempBuf, "Adjust Privilege value Error: %u",GetLastError()); 
    if(LOG_ERR==1) WriteToLog("gTempBuf");
  }

  if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)
  {
    sprintf(gTempBuf, "Token does not have the privilege"); 
    if(LOG_ERR==1) WriteToLog("gTempBuf");
  }

  LPVOID pEnv =NULL;

  if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
  {
   dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
  }
  else
  pEnv=NULL;

  // Launch the process in the client's logon session.
  bResult = CreateProcessAsUser(
      hUserTokenDup,    // client's access token
      AtsAppPathName,   // file to execute
      NULL,             // command line
      NULL,             // pointer to process SECURITY_ATTRIBUTES
      NULL,             // pointer to thread SECURITY_ATTRIBUTES
      FALSE,            // handles are not inheritable
      dwCreationFlags,  // creation flags
      pEnv,             // pointer to new environment block 
      NULL,             // name of current directory 
      &si,              // pointer to STARTUPINFO structure
      &pi               // receives information about new process
   );
  // End impersonation of client.

  //Perform All the Close Handles task
  CloseHandle(hProcess);
  CloseHandle(hUserToken);
  CloseHandle(hUserTokenDup);
  CloseHandle(hPToken);
  CloseHandle(hSnap);

  //return iResultOfCreateProcessAsUser;
  return 0;
}  
4

2 回答 2

0

您是否使用映射驱动器访问这些网络位置?

映射的驱动器与登录会话一起存储。由于未加载用户的配置文件,他们将无法访问他们的“映射驱动器”

您可以改用完整的 UNC 路径。

于 2014-01-01T19:04:21.880 回答
0

问题是您获得了管理(提升)令牌的副本。这可能是故意的,因为您启用了调试权限。不幸的是,用户的提升令牌与过滤的令牌不在同一个登录会话中,因此没有任何用户的映射驱动器。

更多信息,包括各种解决方法,可以在 MSDN 文章“如果启用 UAC,将文件从映射驱动器复制到本地目录失败并出现错误“位置不可用””中找到。通常最简单的解决方案是使用 UNC 路径或根据需要重新映射驱动器。

于 2014-05-14T20:29:36.967 回答