After some reading here and on MSDN, i put the following code together:
;*************************************************************************************
;assemble 64 ;UASM
;*************************************************************************************
option casemap : none
option win64: 15
OPTION STACKBASE : RBP
include <windows.inc>
includelib kernel32.lib
includelib user32.lib
;*************************************************************************************
;*************************************************************************************
.code
ExceptionFilter PROTO
TestEx PROC FRAME:ExceptionFilter
;*************************************************************************************
; create gpf and try to handle it
;*************************************************************************************
Try = $ ;start address
xor rax, rax
mov [rax], rax ;gpf
End_Try = $ ;end address
Resume:
invoke MessageBoxA, 0, CSTR("works"), CSTR("test"), 0
invoke ExitProcess, 0
ret
Catch::
lea rax, Resume
mov [r8].CONTEXT.Rip_, rax ;change the context so execution resumes at label "Exit"
mov rax, ExceptionContinueExecution ;should now resume execution at label "Resume"
;int 3 ;debuggger breakpoint
add rsp, 8
db 0c3h ;ret, prevents "leave" to be inserted, which is unwanted here
TestEx ENDP
;*************************************************************************************
ExceptionFilter PROC
;*************************************************************************************
; rcx = Exception_Record, rdx = EstablisherFrame, r8 = CONTEXT, r9 = DispatcherContext
;*************************************************************************************
lea rax, Try
cmp [rcx].EXCEPTION_RECORD.ExceptionAddress,rax ;check start address
jl Do_not_handle
lea rax, End_Try
cmp [rcx].EXCEPTION_RECORD.ExceptionAddress,rax ;check end address
jg Do_not_handle
jmp Catch ;handle code inside the proc
Do_not_handle:
mov rax, ExceptionContinueSearch
ret
ExceptionFilter ENDP
;*************************************************************************************
END TestEx
My ultimate goal is to be able to decide, if an app must be terminated or can continue and act accordingly. I don´t need nested Try blocks. In some cases the app must be terminated, i can make a log, display an error message or the like and exit gracefully- this works (not included in the demo code). In some other cases it makes sense just to continue at a different location. This is what the code tries to do - and it seems to work too. The code runs into "Catch", RIP is overwritten in the CONTEXT record with the address of "Resume", so the code resumes execution here after the "RET".
Is this a correct approach or are there bugs or traps i didn´t notice so far?
JK