概述:windows 操作系统获取系统当前登录的用户
0x01 API查询结果总结
以域名为domain
,系统当前登录用户名为 test
为例举例说明,设备名为 WIN-FEKV0FJ89UQ
API |
用户态进程 |
服务进程 |
GetUserName |
test |
SYSTEM |
GetEnvironmentVariable(获取环境变量 %USERNAME%) |
test |
WIN-FEKV0FJ89UQ$ |
WTSQuerySessionInformation(不指定sessionid) |
test |
服务进程中会返回空
|
WTSQuerySessionInformation(指定sessionid为WTSGetActiveConsoleSessionId()) |
test |
test |
GetUserNameExA |
test(返回形式依据传入的参数1) |
domain\WIN-FEKV0FJ89UQ |
总结下来,如果要获取系统当前登录的用户名,那么不管是在用户进程还是服务进程,使用 WTSQuerySessionInformation 指定 Sessionid 的方法比较靠谱。
0x02 获取用户的API
GetUserName
GetUserName
以其运行的exe为主,用户态进程下获取的系统当前登录的用户名,服务进程中获取的为 system
用户。
1 2 3 4 5 6 7
| std::string GetLoginUsernameByApi() { char username[1024]; DWORD usernameLength = sizeof username; GetUserName(username, &usernameLength); return username; }
|
通过环境变量获取
%USERNAME% 和 GetUserName
本质上一致,不同的是,服务进程中,%USERNAME% 字段保存的是主机名+&
,只有用户态进程下才是当前系统登录用户名
1 2 3 4 5 6
| std::string getLoginUsernameByEnv() { char username[1024]; GetEnvironmentVariable("USERNAME", username, sizeof username); return username; }
|
1 2 3 4 5 6 7 8 9 10
| std::string getLoginUsernameBySession() { LPWSTR usernameBuffer = NULL; DWORD infoSize = 0; WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTS_INFO_CLASS::WTSUserName, &usernameBuffer, &infoSize); string username(usernameBuffer); return username; }
|
GetUserNameExA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| BOOL GetNameEx() { PCHAR cpuName = new CHAR[256]; PCHAR domainName = new CHAR[256]; DWORD domainNameSize = 0;
ZeroMemory(domainName, 256);
GetComputerObjectNameA(NameSamCompatible, NULL, &domainNameSize); if (GetComputerObjectNameA(NameSamCompatible, cpuName, &domainNameSize)) { std::wcout << "当前登录的域机器: " << cpuName << std::endl; } else { std::cerr << "无法获取域信息" << std::endl; }
domainNameSize = 0; GetUserNameExA(NameDisplay, NULL, &domainNameSize); if (GetUserNameExA(NameDisplay, domainName, &domainNameSize)) { std::wcout << "当前登录的域用户: " << domainName << std::endl; } else { std::cerr << "无法获取域信息" << std::endl; } }
|
0x03 如何在服务进程中获取系统当前登录的用户
获取当前控制台会话ID,然后再调用 WTSQuerySessionInformationW
查询用户名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| BOOL GetLocalCurUserName(std::wstring& strUserName) { BOOL bRet = FALSE; DWORD sessionId = WTSGetActiveConsoleSessionId(); LPWSTR ppBuffer[100]; DWORD bufferSize; bRet = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, ppBuffer, &bufferSize);
printf(" GetLocal1CurUserName --> %s", *ppBuffer);
if (bRet == TRUE) { strUserName = *ppBuffer; WTSFreeMemory(ppBuffer); }
return bRet; }
|
0x04 其他方式
上述指定 Sessionid 的方法也可以通过 ProcessIdToSessionId 来获取 Sessionid。思路就是获取进程 Explorer.exe
的进程id,然后通过 PID 获取 Sessionid,最后通过 WTSQuerySessionInformationW 获取到对应的用户名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| DWORD GetPorceeIdByName(const std::string& procName) { const char* FindExe = procName.c_str(); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (INVALID_HANDLE_VALUE == hSnapshot) { return NULL; } PROCESSENTRY32 pe = { sizeof(pe) }; for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe)) { if (strcmp(pe.szExeFile, FindExe) == 0) { CloseHandle(hSnapshot); return pe.th32ProcessID; } } CloseHandle(hSnapshot); }
bool GetUserNameByPid(DWORD pid, std::wstring& username) { DWORD SessionId; ProcessIdToSessionId(pid, &SessionId);
LPWSTR usernameBuffer = NULL; DWORD infoSize = 0; if (FALSE == WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, SessionId, WTS_INFO_CLASS::WTSUserName, &usernameBuffer, &infoSize)) { return false; } username = usernameBuffer;
return true; }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12
| void test() { DWORD dwPid; wstring wsUserName; if (dwPid = GetPorceeIdByName("explorer.exe")) { if (GetUserNameByPid(dwPid, wsUserName)) { std::wcout << "explorer.exe:" << wsUserName << endl; } } }
|