我有一个相当复杂但经过严格测试的汇编语言x86-32应用程序,可在各种x86-32和x86-64机器上运行。这是语言编译器的运行时系统,因此它支持执行另一个已编译的二进制程序,即#34;目标代码"。
它使用Windows SEH捕获各种陷阱:除零,非法访问,...并使用Windows提供的上下文信息打印注册转储,显示陷阱时机器的状态。 (它会执行许多与问题无关的其他内容,例如打印函数回溯或根据需要从除法中恢复)。这允许"目标代码的编写者"了解他的计划出了什么问题。
在我认为非法内存访问的两个Windows 7-64系统上,它们或多或少相同,它的行为不同。具体问题是"目标代码" (不是经过良好测试的运行时系统)某处愚蠢地将0x82加载到EIP中;这是地址空间AFAIK中不存在的页面。我希望通过SEH获得Windows陷阱,并期望使用EIP = 00000082等进行注册转储。
在一个系统上,我完全得到了寄存器转储。我可以在这里展示它,但它并没有为我的问题添加任何内容。因此,很明显我的运行时系统中的SEH可以捕获它,并显示情况。这台机器上没有任何MS开发工具。
在另一个(" mystery")系统上,运行系统和目标代码具有相同的二进制文件,我得到的只是命令提示符。没有进一步的输出FWIW,这台机器上有MS Visual Studio 2010。神秘机器被大量用于其他目的,并且在正常使用中没有显示其他有趣的行为。
我认为行为差异是由某个地方的Windows配置引起的,或者是Visual Studio控制的。 DEP配置不是系统菜单;它们都被配置(vanilla)为" DEP用于标准系统进程"。我的运行时系统可执行文件有"否(/ NXCOMPAT:NO)"构造
这两款机器都是i7但不同的芯片,4芯,大量内存,不同的主板。我不认为这是相关的;当然这两个CPU都以相同的方式捕获陷阱。
运行时系统在启动时包含以下行:
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); //在崩溃时停止Windows弹出
这是最近添加的,以防止"神秘"系统显示一个弹出窗口," xxx.exe已停止工作"崩溃发生时。弹出框的行为并不会发生在第一个系统上,所以这一切都是将问题推到了“神秘”的另一个角落。机。
我希望配置/控制它的任何线索?
我在这里提供了我正在使用的SEH代码。它已被编辑 删除大量的健全检查代码 我声称对所见的状态没有影响 在这段代码中。
运行时系统的顶层生成一组worker 线程(使用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>
答案 0 :(得分:0)
&#34; DEP用于标准系统流程&#34;不会帮助你;它是internally known as "OptIn"。您需要的是.exe文件的PE头中设置的IMAGE_DLLCHARACTERISTICS_NX_COMPAT
标志。或者调用kernel32.dll中的SetProcessDEPPolicy
函数SetProcessMitigationPolicy
也不错......但是在Windows 8之前它不可用。
有一些nice explanation on Ed Maurer's blog,它解释了.NET如何使用DEP(你不会关心它)以及系统规则(你做过)。
BIOS设置也会影响硬件NX是否可用。