最近在重构一个项目的时候需要用到遍历系统账户信息和每个账户的 SID 信息用来对比数据,所以就涉及到如何获取 Windows 的账户信息,以及每个账户所关联的 SID。学习了一些前辈的代码后自己总结了一下记录在博客里,方便以后使用。
代码效果
相关代码
代码使用 Windows API 遍历了系统账户信息,并实现了一个将 SID 转为字符串的功能函数。将账户名和 SID 分别打印了出来。
代码语言:javascript复制#include "stdafx.h"
#include "Ntsecapi.h"
DWORD GetStrWithPSID(PSID pSid, TCHAR* szBuffer, int nLength);
int _tmain(int argc, _TCHAR* argv[])
{
PLUID pSessions;
NTSTATUS ntStatus;
ULONG ulCount = 0;
// 枚举所有账户信息
ntStatus = LsaEnumerateLogonSessions(&ulCount, &pSessions);
for (ULONG i = 0; i < ulCount; i )
{
// 取出一个账户信息到 pSessionData,该函数在内部分配内存
PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
ntStatus = LsaGetLogonSessionData (&pSessions[i], &pSessionData);
if (0 != ntStatus)
{
if (pSessionData)
{
LsaFreeReturnBuffer(pSessionData);
}
continue;
}
// 验证 SID 是否有效
if (pSessionData && IsValidSid(pSessionData->Sid))
{
TCHAR szUserName[MAX_PATH] = {0};
TCHAR szSID[MAX_PATH] = {0};
// 拷贝并打印用户名信息,该结构体中有很多成员,描述了该账户的属性
if (NULL != pSessionData->UserName.Buffer)
{
ZeroMemory(szUserName, MAX_PATH);
CopyMemory(szUserName, pSessionData->UserName.Buffer, pSessionData->UserName.Length);
wcout << szUserName << _T(" -> ");
GetStrWithPSID(pSessionData->Sid, szSID, MAX_PATH);
wcout << szSID << endl;
}
}
// 释放资源
if (NULL != pSessionData)
{
LsaFreeReturnBuffer(pSessionData);
}
}
getchar();
return 0;
}
DWORD GetStrWithPSID(PSID pSid, TCHAR* szBuffer, int nLength)
{
// convert SID to string
SID_IDENTIFIER_AUTHORITY *psia = ::GetSidIdentifierAuthority(pSid);
DWORD dwTopAuthority = psia->Value[5];
_stprintf_s(szBuffer, nLength, _T("S-1-%lu"), dwTopAuthority);
TCHAR szTemp[32];
int iSubAuthorityCount = *(GetSidSubAuthorityCount(pSid));
for (int i = 0; i < iSubAuthorityCount; i )
{
DWORD dwSubAuthority = *(GetSidSubAuthority(pSid, i));
_stprintf_s(szTemp, 32, _T("%lu"), dwSubAuthority);
_tcscat_s(szBuffer, nLength, _T("-"));
_tcscat_s(szBuffer, nLength, szTemp);
}
return 0;
}
要注意的是,由于使用了 Secur32 中的函数,所以工程中要导入 Secur32.lib 才能正常编译。