You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 08:54:01