【WINAPI】获取系统当前用户名

文章目录
  1. 1. 0x01 API查询结果总结
  2. 2. 0x02 获取用户的API
    1. 2.1. GetUserName
    2. 2.2. 通过环境变量获取
    3. 2.3. WTSQuerySessionInformation 通过会话查询用户名
    4. 2.4. GetUserNameExA
  3. 3. 0x03 如何在服务进程中获取系统当前登录的用户
  4. 4. 0x04 其他方式
    1. 4.1. 测试

概述: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;
}

WTSQuerySessionInformation 通过会话查询用户名

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;
}
//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;
}

测试

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;
}
}
}