读取UNICODE_STRING的缓冲区时发生访问冲突

时间:2018-09-07 08:25:08

标签: c++ winapi credential-providers

我已经编写了一个使用KERB_CERTIFICATE_LOGON结构的自定义凭据提供程序。 现在一切正常,我尝试编写一些单元测试(我知道测试应该在编码之前编写,但是在这种情况下,我必须先弄清楚一切如何工作;-))。

当我尝试通过wcsncmp使用this SO-question的解决方案来声明KERB_CERTIFICATE_LOGON结构的内容时,如下所示:

KERB_CERTIFICATE_LOGON* kerbCertificateLogon = reinterpret_cast<KERB_CERTIFICATE_LOGON*>(serializedCredentials->rgbSerialization);
wcsncmp(domainName, kerbCertificateLogon->DomainName.Buffer, kerbCertificateLogon->DomainName.Length / sizeof(wchar_t));

此时,我在wcsncmp中遇到访问冲突:

    extern "C" int __cdecl wcsncmp(
    wchar_t const* a,
    wchar_t const* b,
    size_t         count
    )
{
    if (count == 0)
        return 0;

    while (--count != 0 && *a && *a == *b) // <== Here comes "read access violation b was 0x48"
    {
        ++a;
        ++b;
    }

    return static_cast<int>(*a - *b);
}

此外,在调试填充缓冲区的函数时,我可以在用以下代码填充缓冲区后直接在Visual Studio的“ Locals”视图中看到:

kerbCertificateLogon->DomainName.Buffer = reinterpret_cast<PWSTR>(domainBuffer - authInfo);

此结果:

  

0x0000000000000048 <读取字符串字符时出错。>

WTF ??? LSA使用相同的代码可以正常工作,所以我认为一切都很好,但是为什么我不能在简单的单元测试中读取该值?

1 个答案:

答案 0 :(得分:0)

好的,像往常一样,我在询问后不久找到了解决方案。 与上面的评论相反,错误必须与证书结构有关!因此,仅使用两个UNICODE_STRING就无法重现该问题。

在这些结构中,相对指针用于存储信息,就像从旧问题的链接中看到的那样。

我只是没有看到树木的木头。

因此解决方案非常简单:我不得不重新计算绝对指针,而不是直接使用指向UNICODE_STRING中缓冲区的指针。我将其提取为一种方法,因为在测试中我经常需要这种比较:

static void AssertRelativeUnicodeStringEquals(const wchar_t* expected, UNICODE_STRING actual, LPBYTE basePointer)
{
    const int result = wcscmp(expected, reinterpret_cast<PWSTR>(basePointer + reinterpret_cast<int>(actual.Buffer)));
    EXPECT_EQ(0, result);
}

现在我可以打电话给

AssertRelativeUnicodeStringEquals(domainName, kerbCertificateLogon->DomainName, (LPBYTE)kerbCertificateLogon);