概述: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 用户。
std::string GetLoginUsernameByApi()
{
char username[1024];
DWORD usernameLength = sizeof username;
GetUserName(username, &usernameLength);
return username;
}通过环境变量获取
%USERNAME% 和 GetUserName 本质上一致,不同的是,服务进程中,%USERNAME% 字段保存的是主机名+&,只有用户态进程下才是当前系统登录用户名
std::string getLoginUsernameByEnv()
{
char username[1024];
GetEnvironmentVariable("USERNAME", username, sizeof username);
return username;
}WTSQuerySessionInformation 通过会话查询用户名
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
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 查询用户名。
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 获取到对应的用户名。
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;
}
//printf("%-6d %s\n", pe.th32ProcessID, pe.szExeFile);
}
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;
}测试
void test()
{
DWORD dwPid;
wstring wsUserName;
if (dwPid = GetPorceeIdByName("explorer.exe"))
{
if (GetUserNameByPid(dwPid, wsUserName))
{
std::wcout << "explorer.exe:" << wsUserName << endl;
}
}
}