首页 > 解决方案 > LookupAccountSid() 损坏内存堆

问题描述

我花了几天时间追踪一个表现为结构化异常0xC0000374(堆损坏)的崩溃......当然,只能在客户环境中重现。

将其缩小到这个(非常简化的)代码:

    DWORD cchName = 0, cchDomain = 0;
    SID_NAME_USE type;
    if (!LookupAccountSidW(NULL, pSid, NULL, &cchName, NULL, &cchDomain, &type))
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            <bail via exception or return>;
    }

    cout << cchName << ":" << cchDomain << " -> ";

    DWORD cchName1 = (cchName + 1), cchDomain1 = (cchDomain + 1);

    LPWSTR pName   = ... allocate cchName1   WCHARs ...;
    LPWSTR pDomain = ... allocate cchDomain1 WCHARs ...;

    if (!LookupAccountSidW(NULL, pSid, pName, &cchName1, pDomain, &cchDomain1, &type))
        <bail via exception or return>;

    cout << cchName1 << ":" << cchDomain1 << endl;

    ... deallocate pDomain; // <- here Application Verifier detects corrupted block
    ... deallocate pName;

请忽略内存泄漏的可能性(代码已简化)。另外,请注意,根据MSDN,不需要过度分配 1 个符号。但是让我描述一下我在调试器中看到的......

对于遇到的所有(除了一个)SID,它会打印出诸如16:7 -> 15:6or之类的东西,6:7 -> 5:6而且一切都很花哨。基本上,第一个调用返回所需的缓冲区大小(包括 terminating NUL),第二个调用返回写入(不包括 )到提供的缓冲区中的符号数(NUL顺便说一句,这些缓冲区被过度分配)。

现在,一个特定的 SID 会产生6:3 -> 5:2输出。但是当我查看pDomain缓冲区(长度为 4 个符号)时,我看到了截断的域名ABCD(实际域名为 6 个符号),然后是NUL(这会破坏堆控制结构)。所以LookupAccountSidW声称它只写入了 2(+1) 个符号,而实际上它已经将 4(+1) 个符号写入了一个 4 个符号长的缓冲区。

从我的角度来看,这是一个明显的错误LookupAccountSidW,但我真的很想弄清楚该 SID 与其他 SID 有何不同。也许它是从另一个(较短的)域迁移的?

PS 它是 Windows 10 (10.0.14393.2969)

PPS SID 是S-1-5-21-<3-part domain id>-<user id>

标签: windowswinapisid

解决方案


我遇到了这个问题,所以我正在为不幸落入这个陷阱的人记录我的发现。

似乎存在 LookupAccountSidA 在某些环境中会导致堆溢出的情况。

可以将用户从一个域迁移到另一个域。由于历史原因,SID 可以保留为域的一部分。LookupAccountSidA 应该支持查找这些 SID,它会这样做,只是当旧域的名称比新域的名称长时,它会在内部超出堆。

在后台,LookupAccountSidA 调用 LsaLookupSids2,它获取一个 PLSA_TRANSLATED_NAME(名称数组)和一个 PLSA_REFERENCED_DOMAIN_LIST。这里的问题是 LookupAccountSidA 使用了错误的数组位置来设置域数据所需的大小。如果有记忆,它会使用位置零,它应该是其他的东西。因此,如果位置 0 的域的名称比与您正在查找的 SID 关联的名称短,LookupAccountSidA 将自行覆盖堆。

唯一的解决方法是传递两个 256 个字符的缓冲区,并将它们填充初始化为 '\0'。将这些传入您的名称和域数组,不要相信为域返回的大小。将这些从您返回的缓冲区中复制出来,并注意不要在读取时超出缓冲区。

当然,更好的选择是使用 LsaLookupSids2 并在必要时进行 Unicode 到多字节的转换。

PS:微软的一位代表告诉我,这是在 Windows 7 和 8 之间引入的错误。我不知道这是否会影响 LookupAccountSidW,但肯定有可能。


推荐阅读