Author Topic: Win64 SEH Structured Exception Handling NASM GOLINK (Example code)  (Read 17750 times)

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
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: [Select]
; ---------------------------------------------------------------- ;
; 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: [Select]
; ---------------------------------------------------------------- ;
; 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: [Select]
[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!!!
Encryptor256's Investigation \ Research Department.

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 SEH Structured Exception Handling NASM GOLINK (Example code)
« Reply #1 on: November 09, 2013, 05:09:34 PM »
If exception happens, set carry flag:

Code: [Select]
; ---------------------------------------------------------------- ;
; 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

      ; Set carry flag, alter PCONTEXT.EFlags, offset 68
      or dword [r8+68],dword 0x00000001

      ; 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

So, now, main code:

Code: [Select]
; ---------------------------------------------------------------- ;
; 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
      jc .quit
      call buggyProcedure2 ; Fire's EXCEPTION_INT_DIVIDE_BY_ZERO
      jc .quit


      ; 3. Print info: "[Code End]"
      mov rcx,qword txt_code_end
      call printf

.quit:
      add rsp,qword 8*4
      pop rbx
      ret

Output:

Code: [Select]
[Code Begin]

~Exception: !!! EXCEPTION_ACCESS_VIOLATION !!!

Cool!

Encryptor256!
Encryptor256's Investigation \ Research Department.

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: Win64 SEH Structured Exception Handling NASM GOLINK (Example code)
« Reply #2 on: November 09, 2013, 05:15:42 PM »
To calculate offsets when accessing registers in Contex structure i used PELLES C,

Code: [Select]
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{

char buff[321];
CONTEXTs zip;

unsigned long offset = (unsigned long)&zip.EFlags-(unsigned long)&zip;

//68 EFlags
//160 RBP
//152 RSP
//248 RIP

wsprintf(buff,"%d",offset);

MessageBox(0,buff,0,0);
return 0;
}

Encryptor256!!!
Encryptor256's Investigation \ Research Department.