如何从ACCESS_ALLOWED_ACE结构体的SidStart成员获取完整SID?
解决方案
你不需要手动读取SidStart之后的连续内存,Win32 API已经为这类场景做了兼容:
- 直接取
ACCESS_ALLOWED_ACE结构体中SidStart成员的地址,就可以作为合法的PSID指针传给所有接受SID参数的系统API,因为SID的完整数据就是从SidStart的内存地址开始连续存储的。 - 要把SID转换为可读的用户名,可以使用
LookupAccountSidWAPI,也可以先通过ConvertSidToStringSidW把SID转成字符串格式(比如S-1-1-0)后再做处理。
补全后的可运行代码
#include <iostream> #include <Windows.h> #include <sddl.h> #include <vector> using namespace std; int main() { LPCWSTR stringSecurityDescriptor = L"D:AI(D;OICI;DCLCDTSD;;;S-1-1-0)"; PSECURITY_DESCRIPTOR pSD = nullptr; // 增加API返回值判断,避免空指针崩溃 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(stringSecurityDescriptor, SDDL_REVISION_1, &pSD, nullptr)) { wcout << L"转换安全描述符失败,错误码:" << GetLastError() << endl; return 1; } PACL pDacl = nullptr; BOOL bDaclPresent = FALSE; BOOL bDaclDefaulted = FALSE; if (!GetSecurityDescriptorDacl(pSD, &bDaclPresent, &pDacl, &bDaclDefaulted)) { wcout << L"获取DACL失败,错误码:" << GetLastError() << endl; LocalFree(pSD); return 1; } vector<ACCESS_ALLOWED_ACE*> pDaclAces; if (bDaclPresent && pDacl != nullptr) { for (DWORD i = 0; i < pDacl->AceCount; i++) { LPVOID pAce = nullptr; if (GetAce(pDacl, i, &pAce)) { // 先判断ACE类型,避免其他类型ACE强制转换出错 ACE_HEADER* pAceHeader = (ACE_HEADER*)pAce; if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) { pDaclAces.push_back((ACCESS_ALLOWED_ACE*)pAce); } } } } // 转换SID为可读格式 for (auto pAce : pDaclAces) { PSID pSid = (PSID)&pAce->SidStart; // 方法1:转换为SID字符串格式 LPWSTR sidStr = nullptr; if (ConvertSidToStringSidW(pSid, &sidStr)) { wcout << L"SID字符串:" << sidStr << endl; LocalFree(sidStr); } // 方法2:转换为对应用户名 WCHAR accountName[256] = {0}; WCHAR domainName[256] = {0}; DWORD accountNameLen = _countof(accountName); DWORD domainNameLen = _countof(domainName); SID_NAME_USE sidType; if (LookupAccountSidW(nullptr, pSid, accountName, &accountNameLen, domainName, &domainNameLen, &sidType)) { if (domainNameLen > 0) { wcout << L"对应用户:" << domainName << L"\\" << accountName << endl; } else { wcout << L"对应用户:" << accountName << endl; } } } // 释放系统分配的内存,避免泄漏 if (pSD != nullptr) { LocalFree(pSD); } return 0; }
补充说明
- 代码增加了API调用结果校验,避免非法内存访问崩溃
- 新增ACE类型判断逻辑,只会处理允许访问类型的ACE,避免类型转换错误
- 所有系统API分配的内存都做了释放处理
- 你的测试用例运行后,会输出
S-1-1-0对应的用户名为Everyone
内容的提问来源于stack exchange,提问作者Baskman
相关产品推荐
相关产品推荐

