如何在使用C++的SYSTEM进程中获取活动用户名?
我已经使用了GetUserName()方法,但是它返回的用户名是SYSTEM中的'SYSTEM'。如何在SYSTEM进程中获得活动的用户名?这是我的代码:如何在使用C++的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);
}
}
}
}
枚举桌面并找到“默认”桌面。从该桌面获取用户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; 和更多的各种服务。 – cdoubleplusgood
是的,您可以看到所有的服务桌面,但不能看到交互式用户的桌面,这是您在这种情况下需要的桌面。 (搜索服务桌面有时很有用,但在这种情况下不适用。) –
如果你想知道谁是登录到物理控制台,你可以调用WTSGetActiveConsoleSessionId
获得终端服务(又名“快速用户切换”又名“远程桌面”)当前处于活动状态的会话ID。
然后,您可以拨WTSQuerySessionInformation
与WTSUserName
获取用户名。
(如果你有兴趣通过远程桌面可能会被登录的用户,这种做法是行不通的)
枚举所有进程是一个办法做到这一点,但它有一定的问题:
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);
}
哪个操作系统?我猜Windows?在Windows上,据我所知,有一个SYSTEM用户,你的应用程序确实是以该用户的身份运行的 - 所以你想得到谁的用户名? – codeling
如果您的进程在SYSTEM帐户下运行,那就是您所得到的:GetUserName返回拥有当前令牌的帐户的名称。您可能想知道其他内容,例如“当前登录的用户”(可能有多个!)或“启动此过程的用户”。 –
该应用程序正在WINDOWS上工作。此外,我只想知道'当前登录的用户'。使用该应用的每个人都在域中,并且拥有我想要获得的唯一登录帐户。 –