Hello!
.formal_descriptor:; ---------------------------------------------------------------- ;
; This is: Win64 SEH (Structured Exception Handling) NASM, GOLINK.
; Author: J.K. Encryptor256.
; Date: November 09, 2013.
; ---------------------------------------------------------------- ;
; Description:
;
; Program call's two buggy procedures, in each of them, there is
; a code, that is invalid and will generate an exception. When
; exception happens, handler will catch it and recover from it,
; updates registers rip and rsp.
; ---------------------------------------------------------------- ;
; Information:
;
; About SEH i found on web, learned, and builded
; my own working example.
;
; 1. User, Feryno, posted at, 08 Mar 2010,
; good information to study from,
; helped me to clarify my thinking.
; Web:(
http://board.flatassembler.net/topic.php?t=11266)
;
; 2. MSDN.
;
; ---------------------------------------------------------------- ;
; Using:
;
; 1. Compiler:
; 1.1. NASM (The Netwide Assembler)
; 1.2. Web:(
http://nasm.us/)
;
; 2. Linker:
; 2.1. GoLink (Jeremy Gordon's Go Tools for Win32 and Win64)
; 2.2. Web:(
http://www.godevtool.com/)
;
; 3. Editor:
; 3.1. PSPad (Freeware Editor)
; 3.2. Web:(
http://www.pspad.com/en/)
;
; ---------------------------------------------------------------- ;
; How to compile and link,
;
; Easy, in the way, i did:
;
; 1. NASM: "nasm.exe -f win64 main.asm -o main.obj"
; Produces output file of 1.80 KB (1,850 bytes)
;
; 2. GoLink: "golink.exe /entry main /console main.obj MSVCRT.dll"
; Produces output file of 3.50 KB (3,584 bytes)
;
; ---------------------------------------------------------------- ;
.data_descriptor:; ---------------------------------------------------------------- ;
; Code of "main.asm" begins here:
; ---------------------------------------------------------------- ;
%ifndef _main_
%define _main_
; Tell compiler to generate 64 bit code
bits 64
; ---------------------------------------------------------------- ;
; Data segment ;
; ---------------------------------------------------------------- ;
section .data use64
; Info messages
txt_code_begin: db 10,10,"[Code Begin]",10,0
txt_code_end: db 10,10,"[Code End]",10,0
; Const - exception codes
EXCEPTION_ACCESS_VIOLATION equ (0xC0000005)
EXCEPTION_INT_DIVIDE_BY_ZERO equ (0xC0000094)
; Const - exception messages
txt_exception_access_violation:
db 10,"~Exception: !!! EXCEPTION_ACCESS_VIOLATION !!!",0
txt_exception_int_divide_by_zero:
db 10,"~Exception: !!! EXCEPTION_INT_DIVIDE_BY_ZERO !!!",0
txt_exception_undefined:
db 10,"~Exception: !!! Undefined !!!",0
; Const - unwind flags
UNW_FLAG_EHANDLER equ 0x08
UNW_FLAG_UHANDLER equ 0x10
UNW_FLAG_CHAININFO equ 0x20
UNW_VERSION_1 equ 0x01
UNW_FLAG_VEU equ (UNW_VERSION_1+UNW_FLAG_EHANDLER+UNW_FLAG_UHANDLER)
; ---------------------------------------------------------------- ;
; pData segment - put here runtime function structures ;
; ---------------------------------------------------------------- ;
section .pdata use64
; RUNTIME_FUNCTION
dd exception_code_begin
dd exception_code_end
dd unwind_info
; ---------------------------------------------------------------- ;
; xData segment - put here unwind info's ;
; ---------------------------------------------------------------- ;
section .xdata use64
; UNWIND_INFO
; 1. Version : 3, Flags : 5
; 2. SizeOfProlog
; 3. CountOfCodes
; 4. FrameRegister : 4, FrameOffset : 4
; 5. ExceptionHandler
; 6. ExceptionData
unwind_info:
db UNW_FLAG_VEU ;1
db 0 ;2
db 0 ;3
db 0 ;4
dd exception_handler ;5
dd 0 ;6
.code_descriptor:; ---------------------------------------------------------------- ;
; Code segment ;
; ---------------------------------------------------------------- ;
section .code use64
global main
extern printf
; ---------------------------------------------------------------- ;
; Main - entry point ;
; ---------------------------------------------------------------- ;
main:
push rbx
sub rsp,qword 8*4
; 1. Print info: "[Code Begin]
mov rcx,qword txt_code_begin
call printf
; 2. Call two buggyProcedure's;
; Generates exception.
; Recovers and continues.
call buggyProcedure1 ; Fire's EXCEPTION_ACCESS_VIOLATION
call buggyProcedure2 ; Fire's EXCEPTION_INT_DIVIDE_BY_ZERO
; 3. Print info: "[Code End]
mov rcx,qword txt_code_end
call printf
add rsp,qword 8*4
pop rbx
ret
; ----------------------------------------------------
; buggyProcedure - these' will produce exceptions
; ----------------------------------------------------
exception_code_begin:
buggyProcedure1:
mov [rsp+8*1],rcx; (unused)
mov [rsp+8*2],rdx; (unused)
mov [rsp+8*3],r8; (unused)
mov [rsp+8*4],r9; (unused)
push rbp ; !!! RBP is used to recover !!!
mov rbp,rsp
sub rsp,qword 8*5
xor rax,rax
mov qword [rax],qword 0xBEEF
add rsp,8*5
mov rsp,rbp
pop rbp
ret
buggyProcedure2:
mov [rsp+8*1],rcx; (unused)
mov [rsp+8*2],rdx; (unused)
mov [rsp+8*3],r8; (unused)
mov [rsp+8*4],r9; (unused)
push rbp ; !!! RBP is used to recover !!!
mov rbp,rsp
sub rsp,qword 8*5
xor rax,rax
div rax
add rsp,8*5
mov rsp,rbp
pop rbp
ret
exception_code_end:
; ---------------------------------------------------------------- ;
; exception_handler ;
; ---------------------------------------------------------------- ;
align 0x10 ; aling code on 16 byte boundary
exception_handler:
mov [rsp+8*1],rcx; (save) IN PEXCEPTION_RECORD ExceptionRecord
mov [rsp+8*2],rdx; (save) IN ULONG64 EstablisherFrame,
mov [rsp+8*3],r8; (save) IN OUT PCONTEXT ContextRecord
mov [rsp+8*4],r9; (save) IN OUT PDISPATCHER_CONTEXT DispatcherContext
; ------------------------------------------------- ;
sub rsp,qword 8*5
; Recover RIP, to where execution continues --- ;
mov rax,qword [r8+160]; Get PCONTEXT.RBP
mov rax,qword [rax+8]; Get return value
mov qword [r8+248],rax; Update PCONTEXT.RIP
; Recover RSP, to place before exception --- ;
mov rax,qword [r8+160]; Get PCONTEXT.RBP
add rax,byte 16;
mov qword [r8+152],rax ; Restore RSP
; Print exception message -----------------------
; What kind'a exception happened?
mov rax,qword [rsp+8*5+8*1]
mov eax,dword [rax+0]
.printe0:
cmp eax,dword EXCEPTION_ACCESS_VIOLATION
jne .printe1
mov rcx,qword txt_exception_access_violation
jmp .printe
.printe1:
cmp eax,dword EXCEPTION_INT_DIVIDE_BY_ZERO
jne .printe2
mov rcx,qword txt_exception_int_divide_by_zero
jmp .printe
.printe2:
mov rcx,qword txt_exception_undefined
jmp .printe
.printe:
call printf
; Continue execution!
xor rax,rax
add rsp,qword 8*5
ret
%endif
; ---
; END ---
; ---
I was thinking, it will be hard, to implement seh, but,
actually, it's pretty darn easy!
.output_descriptor:[Code Begin]
~Exception: !!! EXCEPTION_ACCESS_VIOLATION !!!
~Exception: !!! EXCEPTION_INT_DIVIDE_BY_ZERO !!!
[Code End]
.video_descriptor:Watch source code and runtime demo on youtube, named: "Win64 SEH Structured Exception Handling NASM GOLINK"
Link:
http://youtu.be/NUTndzrVSqQ.attachment_descriptor:Added attachment of source code, named "main.zip", name speaks for it self.
And that's it!
Encryptor256!!!