我正在使用Delphi中的Xbox1模拟器,因为我在本地CPU上运行游戏,我必须为游戏代码中可能出现的ring0指令创建故障保护。
为了能够捕获这些指令,我了解到SetUnhandledExceptionFilter可以注册一个将在非Delphi异常上调用的函数(前提是我将JITEnable设置为大于0的值)。已注册的回调函数的签名为:
function ExceptionFilter(E: LPEXCEPTION_POINTERS): Integer; stdcall;
在该功能中,我可以测试这样的非法指令:
// STATUS_PRIVILEGED_INSTRUCTION = $C0000096
if E.ExceptionRecord.ExceptionCode = STATUS_PRIVILEGED_INSTRUCTION then
其中一个违规指令是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
这一切都有效(假设我在调试器外面运行 ),但我无法让代码在失败的指令之外执行 - 我试过这样:
begin
// Skip the WBINVD instruction, and continue execution :
Inc(DWORD(E.ExceptionRecord.ExceptionAddress), 2);
Result := EXCEPTION_CONTINUE_EXECUTION;
Exit;
end;
唉,这不起作用。实际上,我会使用真正的指令指针(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!');
答案 0 :(得分:3)
SetUnhandledExceptionFilter似乎是某种Delphi封装器,如果你直接这样做,也许你有更多的运气?
您可以使用AddVectoredExceptionHandler注册自己的异常处理程序,这将调用callback函数,该函数为您提供EXCEPTION_POINTERS结构。该结构的Context成员返回ao EIP,您可以修改它。
如果在回调执行中返回EXCEPTION_CONTINUE_EXECUTION,则继续执行给定的EIP。