SetUnhandledExceptionFilter:继续执行1操作码

Pat*_*kvL 5 delphi exception-handling

我正在使用Delphi中的Xbox1模拟器,因为我在本地CPU上运行游戏,我必须为游戏代码中可能出现的ring0指令创建故障保护.

为了能够捕获这些指令,我了解到SetUnhandledExceptionFilter可以注册一个将在非Delphi异常上调用的函数(前提是我将JITEnable设置为大于0的值).已注册的回调函数的签名如下:

function ExceptionFilter(E: LPEXCEPTION_POINTERS): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)

在该函数内部,我可以测试这样的非法指令:

// STATUS_PRIVILEGED_INSTRUCTION = $C0000096
if E.ExceptionRecord.ExceptionCode = STATUS_PRIVILEGED_INSTRUCTION then
Run Code Online (Sandbox Code Playgroud)

其中一个令人不快的指令是WVINDB($ 0F,$ 09),我可以这样检测:

 // See if the instruction pointer is a WBINVD opcode :
 if  (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[0] = #$0F)
 and (PAnsiChar(E.ExceptionRecord.ExceptionAddress)[1] = #$09) then
Run Code Online (Sandbox Code Playgroud)

这一切都有效(假设我在调试器外部运行)但我无法让代码执行超出失败的指令 - 我尝试了这样:

  begin
    // Skip the WBINVD instruction, and continue execution :
    Inc(DWORD(E.ExceptionRecord.ExceptionAddress), 2);
    Result := EXCEPTION_CONTINUE_EXECUTION;
    Exit;
  end;
Run Code Online (Sandbox Code Playgroud)

唉,这不起作用.实际上,我会使用真正的指令指针(E.ContextRecord.Eip),但不知何故整个ContextRecord似乎没有填充.

我能做些什么使这个并不像预期的那样?

PS:当使用调试器运行时,我希望这段代码最终会出现在我的ExceptionFilter例程中,但事实并非如此 - 它只能在没有调试器的情况下运行; 为什么?

DebugHook := 0; // Act as if there's no debugger
// Trigger a privileged instruction exception via this ring0 instruction :
asm
  WBINVD
end;
// Prove that my exception-filter worked :
ShowMessage('WBINVD succesfully ignored!');
Run Code Online (Sandbox Code Playgroud)

Rem*_*mko 3

SetUnhandledExceptionFilter 似乎是某种 Delphi 包装器,如果直接执行可能会更幸运?

您可以使用AddVectoredExceptionHandler注册您自己的异常处理程序,这将调用一个回调函数,该函数为您提供EXCEPTION_POINTERS结构。该结构的 Context 成员返回您可以修改的 ao EIP。

如果您在回调中返回 EXCEPTION_CONTINUE_EXECUTION,则继续在给定的 EIP 处执行。