我使用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,我对此一无所知。
答案 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
大小的堆栈上分配其他数据。更精确的证明可以是检查传递的指针,看它们是否指向即将被覆盖的堆栈区域。