有没有办法让DisableUserModeCallbackFilter在Windows 10中工作?
Is there a way to get DisableUserModeCallbackFilter to work in Windows 10?
有没有办法让DisableUserModeCallbackFilter
(或类似)在Windows 10上运行?
它应该允许从用户模式代码中抛出的异常跨用户/内核边界传播,并且在早期的 Windows 版本到 Windows 7 上有一个修补程序,但我似乎无法让它在更新的版本上运行。
这是一个测试程序,似乎在Windows 10 x64上出错,但在Windows XP x86上没有错误:
#include <tchar.h>
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib, "user32")
WNDPROC oldproc = NULL;
LRESULT CALLBACK newproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_ftprintf(stderr, _T("OMGn"));
fflush(stderr);
throw 0;
return oldproc(hwnd, uMsg, wParam, lParam);
}
int _tmain(int argc, TCHAR *argv[])
{
HWND hWnd = CreateWindowEx(0, TEXT("STATIC"), TEXT("Name"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL, NULL);
oldproc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)newproc);
try {
UpdateWindow(hWnd);
} catch (int ex) {
_ftprintf(stderr, _T("Error: %dn"), ex);
fflush(stderr);
}
}
当窗口过程调用时 - 内核在内核堆栈和用户模式下推送额外的堆栈帧,称为特殊"函数"(甚至比普通函数更快标签)KiUserCallbackDispatcher
,它调用窗口过程,最后通过特殊的 API 调用返回到内核ZwCallbackReturn
弹出内核堆栈帧。 请注意,在调用ZwCallbackReturn
之后,我们返回不返回它之后的下一条指令, 但是从我们进入内核的位置,从那里调用用户模式回调(通常来自GetMessage
或PeekMessage
)。
无论如何,我们必须弹出内核堆栈帧 - 所以调用ZwCallbackReturn
. 因此,跨KiUserCallbackDispatcher
展开异常的情况 - 设计错误,不得工作。 在这种情况下,谁称呼ZwCallbackReturn
? 如果它将从KiUserCallbackDispatcher
中的处理程序调用__finally
- 此中断展开过程(ZwCallbackReturn
我怎么说永不回来, 但就像跳远一样 - 用另一个堆栈指针和所有寄存器将我们移动到另一个地方)。即使您从catch
手动呼叫ZwCallbackReturn
- 此呼叫后您将在哪里?
所以在SEH处理程序之前需要处理异常KiUserCallbackDispatcher
或者如果需要取消分配一些资源,__finally
块的最小值。
KiUserCallbackDispatcher
SEH
处理程序用于调用ZwCallbackReturn
,即使回调中将出现异常。 但是,此SEH处理程序的行为可能会受到RTL_USER_PROCESS_PARAMETERS.Flags
中未记录的标志的影响:
伪代码:
void KiUserCallbackDispatcher(...)
{
__try {
//...
} __except(KiUserCallbackExceptionFilter(GetExceptionInformation())) {
KiUserCallbackDispatcherContinue:
ZwCallbackReturn(0, 0, 0);
}
}
void LdrpLogFatalUserCallbackException(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord);
int KiUserCallbackExceptionFilter(PEXCEPTION_POINTERS pep)
{
if ( NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Flags & 0x80000)
{
return EXCEPTION_EXECUTE_HANDLER;
}
LdrpLogFatalUserCallbackException(pep->ExceptionRecord, pep->ContextRecord);
return EXCEPTION_CONTINUE_EXECUTION;
}
如果未设置此标志 (0x80000
) -LdrpLogFatalUserCallbackException
调用。 它在内部调用UnhandledExceptionFilter
,如果它不返回EXCEPTION_CONTINUE_EXECUTION
- 使用STATUS_FATAL_USER_CALLBACK_EXCEPTION
和FirstChance = FALSE
调用ZwRaiseException
(这意味着此异常不会传递给应用程序 - 仅用于调试器作为最后机会异常)
如果我们设置这个标志 -EXCEPTION_EXECUTE_HANDLER
将从过滤器返回 -RtlUnwindEx
将被调用(带有TargetIp = KiUserCallbackDispatcherContinue
) - 结果将调用__finally
处理程序
ZwCallbackReturn(0, 0, 0);
在任何情况下,异常都不会传递给堆栈中高于KiUserCallbackDispatcher
的函数中的 SEH(因为此处将处理异常)
因此,我们需要在下面的堆栈中处理异常KiUserCallbackDispatcher
或将标志设置为0x80000
- 在这种情况下,如果我们在KiUserCallbackDispatcher
之前不处理异常 - 我们的__finally
块(如果存在)将在完成回调ZwCallbackReturn
之前执行。
SetProcessUserModeExceptionPolicy
在最近的Windows版本中没有导出(从win8开始),但是接下来是此API的年度代码(确切代码):
#define PROCESS_CALLBACK_FILTER_ENABLED 0x1
BOOL WINAPI SetProcessUserModeExceptionPolicy(DWORD dwFlags)
{
PLONG pFlags = (PLONG)&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Flags;
if (dwFlags & PROCESS_CALLBACK_FILTER_ENABLED)
{
_bittestandset(pFlags, 19); // |= 0x80000
}
else
{
_bittestandreset(pFlags, 19); // &= ~0x80000
}
return TRUE;
}
测试:
WNDPROC oldproc;
LRESULT CALLBACK newproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)oldproc);
__try {
*(int*)0=0;
//RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, 0);
} __finally {
DbgPrint("in finallyn");
CallWindowProc(oldproc, hwnd, uMsg, wParam, lParam);
}
return 0;
}
void test()
{
RtlGetCurrentPeb()->ProcessParameters->Flags |= 0x80000;
if (HWND hwnd = CreateWindowExW(0, WC_EDIT, L"***", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL, NULL))
{
oldproc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)newproc);
__try {
ShowWindow(hwnd, SW_SHOW);
}__except(EXCEPTION_EXECUTE_HANDLER){
DbgPrint("no sense. never will be calledn");
}
MSG msg;
while (0 < GetMessage(&msg, hwnd, 0, 0))
{
DispatchMessage(&msg);
}
}
}
尝试注释或取消注释RtlGetCurrentPeb()->ProcessParameters->Flags |= 0x80000;
行(或相同NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Flags & 0x80000
行)并比较效果。
无论如何,顶级SEH过滤器(在调用wndproc之前)永远不会被调用
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 声明C++具有动态大小的数组类型在 Linux 中工作正常,但不能在 Windows 中工作
- 自 Windows 10 20H1 以来,具有单独线程的多个窗口停止工作
- LoadImage 在 Windows 更新后停止工作
- C++程序工作,但 Windows 显示"程序.exe已停止工作"
- 名为DLL的C++windows服务程序工作不正常
- Windows 函数 "NetUserChangePassword" 在 Windows 10 下不再工作(在 Windows 7 下工作)
- ImpersonateLoggedOnUser在windows服务中不工作
- Makefile在Linux中工作,但在Windows下不起作用,在子目录中找不到文件
- C++代码在 Linux 上按预期工作,但在 Windows 上则不然
- Windows API "CreateWindowEx" 在 Python (3.6.8) 64 位使用的 DLL 中工作吗?
- Windows 上的 SDL 2 在音频设备上无法正常工作
- 有没有办法让DisableUserModeCallbackFilter在Windows 10中工作?
- opengl32.lib如何在Windows(仅1.1版本)上工作?它是否真正实现了OpenGL函数
- C++程序使用 mingw 在 Linux 上交叉编译在 MSy2 中工作,但不能直接在 Windows 中工作
- 将Linux打开,读,写,关闭功能以在Windows上工作
- 从2011年开始,必须在2019年开始工作以使此Windows Textbox做出哪些更改
- Git-Bash for Windows 'rm' 是如何工作的?
- 从Windows上的系统工作的服务中获取用户文档文件夹.C++
- ConsoleApplication4.exe已停止工作.Windows将关闭该程序并通知是否有可用的解决方案