在堆栈上定义std :: wstring时,Hooked NtOpenFile失败

时间:2014-06-25 13:17:56

标签: c++ winapi stack heap api-hook

我使用mhook library编写了一个挂钩dll。在特殊情况下,NtOpenFile()std::wstring定义为stack var时失败。在代理heap上定义代码为working

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

我逐行reduced my code,最后发现在调用函数中发生了错误,定义了std :: wstring(下面这个例子)。每次在不同的OS上发生错误

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#应用程序,使用默认的stacksize来调用win32 dll,我对此一无所知。

1 个答案:

答案 0 :(得分:2)

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

library(tidyverse)
f_varname <- sym("cyl")
ggplot(mpg, aes(displ, cty)) +
  geom_point() +
  facet_grid(cols = vars(!!f_varname))

POBJECT_ATTRIBUTES MakeObjectAttributes() { POBJECT_ATTRIBUTES oa = {...}; return &oa; // Pointer to stack variable - UB } ... NtOpenFile(..., MakeObjectAttributes(), ...) 错误可能表明 STATUS_INVALID_ACL (0xC0000077) 中的 SecurityDescriptor 是以这种方式分配的。

那么重要的是 OBJECT_ATTRIBUTES 使用了多少堆栈,它比 AfterThis_NtOpenFile_WillFail 多,因为由于小字符串优化,AfterThis_NtOpenFile_WillWork 会比几个指针大。

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

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

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