【问题标题】:How can I get the active user name in a SYSTEM process using C++?如何使用 C++ 在 SYSTEM 进程中获取活动用户名?
【发布时间】:2013-09-25 06:17:37
【问题描述】:

我使用了 GetUserName() METHOD ,但它返回的用户名在 SYSTEM 进程中是“SYSTEM”。如何在 SYSTEM 进程中获取活动用户名?这是我的代码:

void getComputerUsername(char * username,char * domainname)
{
 HANDLE hp , htoken;
 char buff[1024];
 unsigned long size = 1024;

 TOKEN_USER *tuser;
 PSID sid;
 TCHAR * user = new TCHAR[256];
 TCHAR * domain=new TCHAR[256];
 SID_NAME_USE snu;

 hp = htoken = INVALID_HANDLE_VALUE;
 hp = GetCurrentProcess();
 if(OpenProcessToken(hp, TOKEN_QUERY, &htoken))
 {
     if(GetTokenInformation(htoken, TokenUser, (void*)buff, size, &size))
 {
     tuser = (TOKEN_USER*)buff;
     sid = tuser->User.Sid;
     size = 256;
     if(LookupAccountSid(NULL, sid, user, &size, domain, &size, &snu))
     {
    int iLength = WideCharToMultiByte(CP_ACP, 0, user, -1, NULL, 0, NULL, NULL);  
    WideCharToMultiByte(CP_ACP, 0, user, -1, username, iLength, NULL, NULL);   

    iLength = WideCharToMultiByte(CP_ACP, 0, domain, -1, NULL, 0, NULL, NULL);  
    WideCharToMultiByte(CP_ACP, 0, domain, -1, domainname, iLength, NULL, NULL);  
           //strcpy( user,username);
     }
 }
 }

}

【问题讨论】:

  • 哪个操作系统?我猜是Windows?据我所知,在 Windows 上,有一个 SYSTEM 用户,您的应用程序可能确实以该用户身份运行 - 那么您想获得谁的用户名?
  • 如果您的进程在 SYSTEM 帐户下运行,这就是您得到的结果:GetUserName 返回拥有当前令牌的帐户的名称。您可能想知道其他信息,例如“当前登录的用户”(可能不止一个!)或“启动此过程的用户”。
  • 该应用程序在 WINDOWS 上运行。此外,我只想知道“当前登录的用户”。使用该应用程序的每个人都在域中,并且有一个我想获得的唯一登录帐户。
  • 哪个登录用户?可能有许多登录用户(在工作站上),并且可能有活动用户(在服务器机器上)。检查任务管理器中的Users 选项卡以了解我要说的内容。
  • 活跃用户。假设只有一个活跃用户。

标签: c++ windows security acl user-accounts


【解决方案1】:

如果您想知道谁登录了物理控制台,您可以致电WTSGetActiveConsoleSessionId 以获取当前处于活动状态的终端服务(又名“快速用户切换”又名“远程桌面”)会话 ID。

然后您可以使用WTSUserName 调用WTSQuerySessionInformation 以获取用户名。

(如果您感兴趣的用户可能通过远程桌面登录,则此方法将不起作用。)

【讨论】:

  • 太棒了....谢谢sssssssssss就是这样...... +1来自我......再次感谢......
【解决方案2】:

以下方法适用于物理控制台和虚拟(远程桌面)控制台会话。

枚举所有进程是一种方法,不管用户是在物理控制台上还是通过远程会话登录,但它有一些问题:

1) 您不能使用已记录的 Windows API 在同一服务进程中枚举 x86 和 x64 进程。 x86 服务只能枚举 x86 进程,而 x64 服务只能枚举 x64 进程。一种规避方法是让 x86 服务启动 x64 辅助进程(反之亦然)来完成其余的枚举任务。

2) 在不同 Windows 版本(例如 Vista 到 Windows 10)上,登录用户始终存在的唯一进程是 explorer.exe,但该进程在 x64 操作系统平台上是 x64,在 x32 操作系统平台上是 x32 及其存在并不表示用户已主动登录。

更好的方法是枚举会话,找到活动的交互式会话或也连接的会话,然后获取该会话的用户名。

下面的代码远不止这些,包括模拟该用户并以该用户身份运行一个进程,所有这些都来自 Windows 服务,但如果您只对用户名感兴趣,请查找第二个实例 WTSQuerySessionInformation()函数被调用。

//Function to run a process as active user from windows service
void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args)
{
    DWORD session_id = -1;
    DWORD session_count = 0;

    WTS_SESSION_INFOA *pSession = NULL;


    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
    {
        //log success
    }
    else
    {
        //log error
        return;
    }

    for (int i = 0; i < session_count; i++)
    {
        session_id = pSession[i].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,
            session_id,
            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) continue;
        }
        else
        {
            //log error
            continue;
        }

        HANDLE hImpersonationToken;

        if (!WTSQueryUserToken(session_id, &hImpersonationToken))
        {
            //log error
            continue;
        }


        //Get real token from impersonation token
        DWORD neededSize1 = 0;
        HANDLE *realToken = new HANDLE;
        if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
        {
            CloseHandle(hImpersonationToken);
            hImpersonationToken = *realToken;
        }
        else
        {
            //log error
            continue;
        }


        HANDLE hUserToken;

        if (!DuplicateTokenEx(hImpersonationToken,
            //0,
            //MAXIMUM_ALLOWED,
            TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
            NULL,
            SecurityImpersonation,
            TokenPrimary,
            &hUserToken))
        {
            //log error
            continue;
        }

        // Get user name of this process
        //LPTSTR pUserName = NULL;
        WCHAR* pUserName;
        DWORD user_name_len = 0;

        if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
        {
            //log username contained in pUserName WCHAR string
        }

        //Free memory                         
        if (pUserName) WTSFreeMemory(pUserName);

        ImpersonateLoggedOnUser(hUserToken);

        STARTUPINFOW StartupInfo;
        GetStartupInfoW(&StartupInfo);
        StartupInfo.cb = sizeof(STARTUPINFOW);
        //StartupInfo.lpDesktop = "winsta0\\default";

        PROCESS_INFORMATION processInfo;

        SECURITY_ATTRIBUTES Security1;
        Security1.nLength = sizeof SECURITY_ATTRIBUTES;

        SECURITY_ATTRIBUTES Security2;
        Security2.nLength = sizeof SECURITY_ATTRIBUTES;

        void* lpEnvironment = NULL;

        // Get all necessary environment variables of logged in user
        // to pass them to the new process
        BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
        if (!resultEnv)
        {
            //log error
            continue;
        }

        WCHAR PP[1024]; //path and parameters
        ZeroMemory(PP, 1024 * sizeof WCHAR);
        wcscpy(PP, path);
        wcscat(PP, L" ");
        wcscat(PP, args);

        // Start the process on behalf of the current user 
        BOOL result = CreateProcessAsUserW(hUserToken, 
            NULL,
            PP,
            //&Security1,
            //&Security2,
            NULL,
            NULL,
            FALSE, 
            NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
            //lpEnvironment,
            NULL,
            //"C:\\ProgramData\\some_dir",
            NULL,
            &StartupInfo,
            &processInfo);

        if (!result)
        {
            //log error
        }
        else
        {
            //log success
        }

        DestroyEnvironmentBlock(lpEnvironment);

        CloseHandle(hImpersonationToken);
        CloseHandle(hUserToken);
        CloseHandle(realToken);

        RevertToSelf();
    }

    WTSFreeMemory(pSession);
}

【讨论】:

    【解决方案3】:

    您需要使用EnumProcesses枚举所有正在运行的进程

    然后查看此答案以从进程中获取用户名:

    https://stackoverflow.com/a/2686150/203244

    【讨论】:

      【解决方案4】:

      枚举桌面并找到“默认”桌面。从该桌面获取用户 SID。 也许您必须尝试找到正确的访问权限;我只尝试了交互式进程中的代码。

      BOOL CALLBACK EnumDesktopProc(_In_  LPTSTR lpszDesktop, _In_  LPARAM lParam)
      {
          // todo: check if desktop is "Default"
          char info[1000];
          auto hd = OpenDesktop(lpszDesktop, NULL, FALSE, DESKTOP_READOBJECTS);
          GetUserObjectInformation(hd, UOI_USER_SID, info, 1000, NULL);
          return TRUE;
      }
      
      BOOL CALLBACK EnumWindowStationProc(_In_  LPTSTR lpszWindowStation, _In_  LPARAM lParam)
      {
          auto hs = OpenWindowStation(lpszWindowStation, FALSE, WINSTA_ENUMDESKTOPS);
          EnumDesktops(hs, &EnumDesktopProc, NULL);
          return TRUE;
      }
      
      int _tmain(int argc, _TCHAR* argv[])
      {
          EnumWindowStations(&EnumWindowStationProc, NULL);
          return 0;
      }
      

      【讨论】:

      • 可能在 XP 上工作,但之后就不行了,因为你会搜索服务会话。
      • 它有效。刚刚在 Window 7 上测试。从作为本地系统运行的服务打开命令提示符,并得到以下输出:Station: WinSta0;桌面:默认;桌面:断开连接;桌面:Winlogon;以及更多用于各种服务。
      • 是的,您将能够看到所有服务桌面,但不能看到交互式用户的桌面,这是您在此方案中想要的桌面。 (搜索服务桌面有时很有用,但在这种情况下就不行了。)
      【解决方案5】:

      如果您只想获取 avtive 控制台用户名,请调用 windows api WTSGetActiveConsoleSessionId() 和 WTSQuerySessionInformation():

      DWORD SessionIdWanted = WTSGetActiveConsoleSessionId();
      
      if(0xFFFFFFFF != SessionIdWanted)
      {
          WCHAR* pUserName;
          DWORD dwNameLen = 0;
      
          if(WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, SessionIdWanted, 
          &pUserName, &dwNameLen))
          {
              wstring UserName(pUserName);
              wcout << L"Current active console user: " << UserName << endl;
          }
          else
              //...
      }
      else
          //Now no active console user here.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-15
        • 2020-06-08
        • 1970-01-01
        • 2011-02-10
        • 1970-01-01
        • 2011-08-07
        • 2017-10-15
        相关资源
        最近更新 更多