读取 UNICODE_STRING 的缓冲区时发生访问冲突
Access violation when reading buffer of UNICODE_STRING
我编写了一个使用 KERB_CERTIFICATE_LOGON 结构的自定义凭证提供程序。
现在一切正常,我尝试编写一些单元测试(我知道应该在编码之前编写测试,但在这种情况下,我必须先弄清楚一切是如何工作的 ;-))。
当我尝试使用 wcsncmp 的 解决方案断言 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 <Error reading characters of string.>
卧槽???相同的代码在 LSA 使用时工作正常,所以我认为一切都很好,但为什么我不能在简单的单元测试中读取值?
好的,像往常一样,我问了不久就找到了解决办法。
与上面的评论之一相反,错误必须与证书结构有关!因此,仅使用两个 UNICODE_STRING 将无法重现该问题。
在这些结构中,相对 指针用于存储信息,正如从 link 到较旧的问题中可以看到的那样。
只见树木不见森林
所以解决方案非常简单:我不得不重新计算绝对指针,而不是直接使用指向 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);
我编写了一个使用 KERB_CERTIFICATE_LOGON 结构的自定义凭证提供程序。 现在一切正常,我尝试编写一些单元测试(我知道应该在编码之前编写测试,但在这种情况下,我必须先弄清楚一切是如何工作的 ;-))。
当我尝试使用 wcsncmp 的
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 <Error reading characters of string.>
卧槽???相同的代码在 LSA 使用时工作正常,所以我认为一切都很好,但为什么我不能在简单的单元测试中读取值?
好的,像往常一样,我问了不久就找到了解决办法。 与上面的评论之一相反,错误必须与证书结构有关!因此,仅使用两个 UNICODE_STRING 将无法重现该问题。
在这些结构中,相对 指针用于存储信息,正如从 link 到较旧的问题中可以看到的那样。
只见树木不见森林
所以解决方案非常简单:我不得不重新计算绝对指针,而不是直接使用指向 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);