windows - 结构化异常处理程序在几乎相同的机器上以不同的方式捕获接近零的EIP陷阱?

标签 windows exception-handling crash config seh

我有一个运行在各种x86-32和x86-64机器上的相当复杂但经过了充分测试的汇编语言x86-32应用程序。这是用于语言编译器的运行时系统,因此它支持执行另一个已编译的二进制程序“目标代码”。

它使用Windows SEH捕获各种陷阱:除以零,非法访问...,并使用Windows提供的上下文信息打印寄存器转储,该信息显示陷阱时机器的状态。 (它还有很多与问题无关的其他东西,例如打印函数回溯或根据需要从零除以恢复)。这使“目标代码”的编写者可以了解其程序出了什么问题。

在我认为是非法内存访问的两个Windows 7-64系统上,它们的行为或多或少是相同的。特定的问题是某个地方的“目标代码”(不是经过充分测试的运行时系统)愚蠢地将0x82加载到EIP中。这是地址空间AFAIK中不存在的页面。我希望通过SEH获得Windows陷阱,并希望通过EIP = 00000082等进行寄存器转储。

在一个系统上,我确切地得到了该寄存器转储。我可以在这里显示它,但不会对我的问题有任何影响。因此,很明显,我的运行时系统中的SEH可以捕获此错误并显示情况。该机器上没有任何MS开发工具。

在另一个(“神秘”)系统上,使用与运行时系统和目标代码完全相同的二进制文件,我得到的只是命令提示符。没有进一步的输出。 FWIW,此计算机上装有MS Visual Studio 2010。该神秘机大量用于其他目的,在正常使用中未显示其他有趣行为。

我认为行为差异是由某处的Windows配置或Visual Studio控制的某物引起的。不是系统菜单的DEP配置。它们都被配置为“标准系统过程的DEP”(原始)。而且我的运行时系统可执行文件已配置为“否(/ NXCOMPAT:NO)”。

这两台机器都是i7,但芯片不同,4核,大量内存,不同的主板。我认为这不相关;当然,这两个CPU都以相同的方式捕获陷阱。

运行时系统在启动时包括以下行:

SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); //崩溃时停止Windows弹出窗口

最近添加了此选项是为了防止崩溃发生时“神秘”系统显示弹出窗口“xxx.exe已停止工作”。弹出框的行为在第一个系统上没有发生,因此所有这些操作只是将问题推到了“神秘”机器上的另一个角落。

我在哪里寻找配置/控制的任何线索?

我在这里提供我正在使用的SEH代码。已被编辑
删除大量的健全性检查代码
我声称对所看到的外观状态没有影响
在此代码中。

运行时系统的顶层生成一组工作程序
线程(使用CreateThread)并指向执行ASMGrabGranuleAndGo;
每个线程都设置自己的SEH,并分支到窃取工作的调度程序RunReadyGranule。就我所知,SEH并未更改
之后;至少,运行时系统和“目标代码”可以
不这样做,但是我不知道底层是什么(例如,标准“C”)
库可能会做。

接下来,我提供陷阱处理​​程序TopLevelEHFilter。
是的,套准印刷机本身可能会吹
导致第二个异常。我会尽快尝试进行检查,
但是IIRC我最后一次尝试是在调试器上
机,没有将控制权传递给调试器,只是
让我弹出了窗口。

public ASMGrabGranuleAndGo
ASSUME FS:NOTHING ; cancel any assumptions made for this register
ASMGrabGranuleAndGo:
;Purpose: Entry for threads as workers in PARLANSE runtime system.
;   Each thread initializes as necessary, just once,
;   It then goes and hunts for work in the GranulesQ
;   and start executing a granule whenever one becomes available

; install top level exception handler

; Install handler for hardware exceptions
cmp        gCompilerBreakpointSet, 0
jne        HardwareEHinstall_end ; if set, do not install handler
push       offset TopLevelEHFilter ; push new exception handler on Windows thread stack
mov        eax, [TIB_SEH]    ; expected to be empty
test       eax, eax
BREAKPOINTIF jne
push       eax               ; save link to old exception handler
mov        fs:[TIB_SEH], esp ; tell Windows that our exception handler is active for this thread
HardwareEHinstall_end:

;Initialize FPU to "empty"... all integer grains are configured like this   
finit
fldcw      RTSFPUStandardMode

lock sub   gUnreadyProcessorCount, 1  ; signal that this thread has completed its initialization

@@: push       0                           ; sleep for 0 ticks
call       MySleep                     ; give up CPU (lets other threads run if we don't have enuf CPUs)
lea        esp, [esp+4]                ; pop arguments
mov        eax, gUnreadyProcessorCount ; spin until all other threads have completed initialization
test       eax, eax
jne        @b

mov        gThreadIsAlive[ecx], TRUE ; signal to scheduler that this thread now officially exists
jmp        RunReadyGranule    
ASMGrabGranuleAndGo_end:

;-------------------------------------------------------------------------------

TopLevelEHFilter: ; catch Windows Structured Exception Handling "trap"
; Invocation:
;   call  TopLevelEHFilter(&ReportRecord,&RegistrationRecord,&ContextRecord,&DispatcherRecord)
;         The arguments are passed in the stack at an offset of 8 (<--NUMBER FROM MS DOCUMENT)
;   ESP here "in the stack" being used by the code that caused the exception
;   May be either grain stack or Windows thread stack
extern exit :proc
extern syscall @RTSC_PrintExceptionName@4:near ; FASTCALL

push       ebp                     ; act as if this is a function entry
mov        ebp, esp                ; note: Context block is at offset ContextOffset[ebp]

IF_USING_WINDOWS_THREAD_STACK_GOTO unknown_exception, esp ; don't care what it is, we're dead
    ; *** otherwise, we must be using PARLANSE function grain stack space
    ; Compiler has ensured there's enough room, if the problem is a floating point trap
    ; If the problem is illegal memory reference, etc,
    ; there is no guarantee there is enough room, unless the application is compiled 
    ; with -G ("large stacks to handle exception traps")

; check what kind of exception 
mov        eax, ExceptionRecordOffset[ebp]
mov        eax, ExceptionRecord.ExceptionCode[eax]
cmp        eax, _EXCEPTION_INTEGER_DIVIDE_BY_ZERO
je         div_by_zero_exception
cmp        eax, _EXCEPTION_FLOAT_DIVIDE_BY_ZERO
je         float_div_by_zero_exception
jmp        near ptr unknown_exception  

float_div_by_zero_exception:
mov        ebx, ContextOffset[ebp] ; ebx = context record
mov        Context.FltStatusWord[ebx], CLEAR_FLOAT_EXCEPTIONS    ; clear any floating point exceptions
mov        Context.FltTagWord[ebx], -1 ; Marks all registers as empty
div_by_zero_exception: ; since RTS itself doesn't do division (that traps),
; if we get *here*, then we must be running a granule and EBX for granule points to GCB
mov        ebx, ContextOffset[ebp] ; ebx = context record

mov        ebx, Context.Rebx[ebx] ; grain EBX has to be set for AR Allocation routines
ALLOCATE_2TOK_BYTES 5             ; 5*4=20 bytes needed for the exception structure
mov        ExceptionBufferT.cArgs[eax], 0
mov        ExceptionBufferT.pException[eax], offset RTSDivideByZeroException    ; copy ptr to exception

mov        ebx, ContextOffset[ebp] ; ebx = context record
mov        edx, Context.Reip[ebx]
mov        Context.Redi[ebx], eax  ; load exception into thread's edi

GET_GRANULE_TO ecx

; This is Windows SEH (Structured Exception Handler... see use of Context block below! 

mov        eax, edx
LOOKUP_EH_FROM_TABLE   ; protected by DelayAbort
TRUST_JMP_INDIRECT_OK eax
mov        Context.Reip[ebx], eax

mov        eax, ExceptionContinueExecution ; signal to Windows: "return to caller" (we've revised the PC to go to Exception handler)
leave
ret

TopLevelEHFilter_end:

unknown_exception:
<print registers, etc. here>

最佳答案

“用于标准系统过程的DEP”不会为您提供帮助;这是internally known as "OptIn"。您需要的是在.exe文件的PE header 中设置的IMAGE_DLLCHARACTERISTICS_NX_COMPAT标志。或在kernel32.dll中调用SetProcessDEPPolicy函数。SetProcessMitigationPolicy也可以...但是直到Windows 8才可用。

有一些nice explanation on Ed Maurer's blog,它解释了.NET如何使用DEP(您不会在意)以及系统规则(您会这样做)。

BIOS设置也会影响硬件NX是否可用。

关于windows - 结构化异常处理程序在几乎相同的机器上以不同的方式捕获接近零的EIP陷阱?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25797325/

相关文章:

c# - 自动调整大小的图片框

c++ - 如何以编程方式判断两个变量是否位于同一个堆栈上? (在 Windows 中)

java - Spring MVC Controller 中处理不可恢复异常的最佳实践

ios - CGImageDestinationFinalize 时崩溃

c++ - 程序入口点 __gxx_personality_sj0 无法位于...

c++ - 使用 DialogBox 作为主窗口是否正确/合适?

c# - 调用 MonoTouch.UIKit.UIDevice.CurrentDevice.SystemVersion 时发生崩溃

javascript - 在 <head> 中动态添加链接样式表

c# - 如何优雅地测试 C# 中的溢出情况?

c# - Windows 服务中的异常处理最佳实践?