I have used GetUserName() METHOD , but the username it returned is 'SYSTEM' in a SYSTEM process.How can I get the active username in a SYSTEM process? THIS IS MY CODE:
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);
}
}
}
}
If you want to know who is logged onto the physical console, you can call WTSGetActiveConsoleSessionId
to get the terminal services (aka "fast user switching" aka "remote desktop") session ID that is currently active.
You can then call WTSQuerySessionInformation
with WTSUserName
to get the username.
(If the user you're interested in might be logged on via Remote Desktop, this approach will not work.)
The approach below will work for both physical console and virtual (remote desktop) console sessions.
Enumerating all processes is a way to do it, regardless of whether user is on the physical console or logged in via remote session, but it has certain issues:
1) You can't enumerate both x86 and x64 processes in the same service process using documented Windows APIs. An x86 service can only enumerate x86 processes and an x64 service can only enumerate x64 processes. A way to circumvent that is to have an x86 service launch an x64 helper process (and vice versa) to do the rest of the enumeration task.
2) The only process that is always present for a logged on user across different Windows versions (e.g. Vista to Windows 10) is explorer.exe however that process is x64 on x64 OS platforms and x32 on x32 OS platforms and its presence does not mean that the user is actively logged in.
A better way is to enumerate sessions, find the active interactive session or sessions that is also connected and then get the user name of that session.
The code below does much more than that, including impersonation of that user and running a process as that user all from a windows service, but if you are just interested in the user name please look for the second instance the WTSQuerySessionInformation() function is called.
//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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With