2

我已经使用mhook library. 在特殊情况下,当 a定义为NtOpenFile()时失败。在代码上定义它是.std::wstringstack varheapworking

代码可以正常工作,除非某个win32 application(我们称之为 nuisance.exe)尝试打开现有的测试文件(如 c:\temp\anyfile.log)access fails。大多数情况下返回 STATUS_INVALID_ACL (0xC0000077)。

reduced my code一行一行地发现错误发生在一个被调用的函数中定义了一个 std::wstring (下面这个例子)。每次在不同的操作系统上都会发生错误

NTSTATUS NtOpenFileApiHook::NtOpenFileHook(PHANDLE              FileHandle,
                                  ACCESS_MASK           DesiredAccess,
                                  POBJECT_ATTRIBUTES    ObjectAttributes,
                                  PIO_STATUS_BLOCK      IoStatusBlock,
                                  ULONG                 ShareAccess,
                                  ULONG                 OpenOptions 
                                  )
{
    NTSTATUS Status = STATUS_SUCCESS;

    // using this function the call will fail
    AfterThis_NtOpenFile_WillFail();

    // using this function INSTEAD the call will work
    AfterThis_NtOpenFile_WillWork();

    // calling the real NtOpenFile using a pointer
    // nothing was changed hier, the original parameters are passed
    Status = RealNtOpenFile(FileHandle, ...);

    return Status;
}

int AfterThis_NtOpenFile_WillFail()
{
    std::wstring String = L"";

    return 0;
}

int AfterThis_NtOpenFile_WillWork()
{
    std::wstring * pString = new std::wstring();
    pString->assign(L"");
    delete pString;

    return 0;
}

我已经为这个电话修复了这种方式。但我担心其他情况下的其他功能可能会失败,所以我正在寻找原因并(可能)寻找解决方案。

Nuisance.exe 是一个 C# 应用程序,默认堆栈大小调用一个我一无所知的 win32 dll。

4

1 回答 1

2

如果 Nuisance.exe 是一个 C++ 应用程序,我会想象它以与此类似的方式调用 NtOpenFile,在覆盖的堆栈上分配一个指针参数:

   POBJECT_ATTRIBUTES    MakeObjectAttributes()
   {
      POBJECT_ATTRIBUTES oa = {...};
      return &oa; // Pointer to stack variable - UB
   }
   ...
   NtOpenFile(..., MakeObjectAttributes(), ...)

STATUS_INVALID_ACL (0xC0000077)错误可能表明以这种方式分配 inside SecurityDescriptorOBJECT_ATTRIBUTES

然后重要的是 使用了多少堆栈AfterThis_NtOpenFile_WillFail,并且超过AfterThis_NtOpenFile_WillWork,因为std::wstring由于小字符串优化,它会比几个指针大。

如果调用链始终相同,则损坏可能是确定性的。

我不知道在 C# 中是否可以使用等效于临时返回地址的代码。但 DLL 可能是 C/C++ 或允许摇晃指针的类似语言。

std::wstring要证明/反驳堆栈的作用,请尝试在具有大小的堆栈上分配其他数据。更精确的证明可以是检查传递的指针以查看它们是否指向即将被覆盖的堆栈区域。

于 2021-06-15T11:14:23.490 回答