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
Playing with the code i realize that i don´t actally need an extra procedure (ExceptionFilter), i can code this:
TestEx PROC FRAME:Catch
;*************************************************************************************
; 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"
db 0c3h ;ret, prevents "leave" to be inserted, which is unwanted here
TestEx ENDP
"Frame" points to a label inside the procedure, where all handling is possible. Could it be that easy?
Your code is ok.
Instead of using "db", it's more readable to use RETN:
mov rax, ExceptionContinueExecution ;should now resume execution at label "Resume"
; db 0c3h ;ret, prevents "leave" to be inserted, which is unwanted here
retn
Thanks for the confirmation!
Cool, "RETN" doesn´t cause "LEAVE" to be added under the hood - thanks again. I have read some nightmare stories about 64 bit SEH, but to me the basics seem pretty staightforeward. It´s except for how to set the handler address essentially the same as in 32 bit.
JK
Quote from: JK on July 05, 2020, 06:28:57 PMCool, "RETN" doesn´t cause "LEAVE" to be added under the hood
In fact, ret is an internal MASM macro that takes info from the PROLOGUE macro to insert leave and pop
used regs. In contrast, RETN and RETN nn are pure instructions.
It's useful to keep that mind also if you have multiple RET in a procedure. Often, at least in 32-bit land, you get shorter code when keeping one of them and let the others jmp to it.
Perhaps this one had no soluce,in 64 bits
;LINK : fatal error LNK1246: '/SAFESEH' incompatible avec l'ordinateur cible 'x64' ; link without '/SAFESEH'
This option is needed to use hook in 64 bits using a particular SEGMENT
Quote
PARTAGE SEGMENT DWORD COMMON SHARED 'DATA'
hHook dq 0
hWnd dq 0 ;limité en taille
PARTAGE ENDS
On msdn,I find a sample(c++) using menu to Hook,but he fall on a syntax abyss with SIZE_T
Any help on that ?
According to MSDN (https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers?view=vs-2019) "/safeseh" is valid only for 32 bit, it´s not supported in 64 bit.
:thumbsup:
Good information,need to be read