flat assembler
Message board for the users of flat assembler.

Index > Windows > win64 exception handling using PE32+ exception directory

Author
Thread Post new topic Reply to topic
Feryno



Joined: 23 Mar 2005
Posts: 449
Location: Czech republic, Slovak republic
Feryno
my first working sample of win64 exception handling using exception directory
you may extend and improve it, then please post your experiments and successes
Code:
; howto debug this using fdbg:
; if you intercept the EXCEPTION_INT_DIVIDE_BY_ZERO exception by debugger, place a breakpoint at expt_handler (that is at instruction sub rsp,28h) and pass exception back to application by Action -> Run unhandled Ctrl-F12

format PE64 GUI at (1 shl 32)
entry start

include     '%fasminc%\win64a.inc'
include    'exception.inc'
IMAGE_DIRECTORY_ENTRY_EXCEPTION            =  3    ; Exception Directory


section '.code' code readable executable

ex_handl_start:

start:
    push    rbx
 sub     rsp,8*(4+0)

     xor     ebx,ebx
buggy_instruction:
   div     ebx
sizeog_buggy_instruction =       $ - buggy_instruction

; I'm king if I go here:
  xor     r9,r9
       lea     r8,[msg_empty]
      lea     rdx,[msg_recovered]
 xor     ecx,ecx
     call    [MessageBoxA]


exit:      ;xor    eax,eax
     ;add    rsp,8*(4+0)
 ;pop    rbx
 ;ret
        xor     ecx,ecx
     call    [ExitProcess]


ex_handl_end:

align 10h
expt_handler:
; RCX = ?
; RDX = ?
;  R8 = CONTEXT64
;  R9 = ?
        sub     rsp,8*(4+1)

virtual at r8
context     CONTEXT64
end virtual

; Necessary to skip instruction causing exception. NTDLL.RtlRestoreContext will restore context after return from the exception handler.
; Opcode size is hardcoded here, but we can use routines from fdbg disasm engine to determine opcode size.
      add     [context.Rip],sizeog_buggy_instruction

  xor     r9,r9
       xor     r8,r8
       lea     rdx,[msg]
   xor     ecx,ecx
     call    [MessageBoxA]

if EXCEPTION_CONTINUE_SEARCH = 0
       xor     eax,eax
else
     mov     eax,EXCEPTION_CONTINUE_SEARCH
end if

 add     rsp,8*(4+1)
 ret


msg              db      'An exception occured in the main application, trying to continue over it thanks to Exception Directory Entry.',0
msg_recovered    db      'The main application recovered from the exception successfully by skipping the instruction causing the exception.'
msg_empty      db      0


section '.pdata' readable writeable

data IMAGE_DIRECTORY_ENTRY_EXCEPTION
; typedef struct _RUNTIME_FUNCTION {
;     DWORD BeginAddress;
;     DWORD EndAddress;
;     DWORD UnwindData;
; } RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
; All three fields are RVAs (otherwise there wouldn't be dwords).
; BeginAddress   Points to the start address of the involved part of code.  
; EndAddress   Points to the end address of the same part of code.  
; UnwindData   Points to an UNWIND_INFO structure.   
     dd      RVA ex_handl_start
  dd      RVA ex_handl_end
    dd      RVA ex_handl_unwind
end data

ex_handl_unwind:
; The UNWIND_INFO structure tells how the portion of code should be handled. Here's the declaration I found on MSDN: 
; typedef union _UNWIND_CODE {
;     struct {
;         UBYTE CodeOffset;
;         UBYTE UnwindOp : 4;
;         UBYTE OpInfo   : 4;
;     };
;     USHORT FrameOffset;
; } UNWIND_CODE, *PUNWIND_CODE;
;
; typedef struct _UNWIND_INFO {
;     UBYTE Version       : 3;
;     UBYTE Flags         : 5;
;     UBYTE SizeOfProlog;
;     UBYTE CountOfCodes;
;     UBYTE FrameRegister : 4;
;     UBYTE FrameOffset   : 4;
;     UNWIND_CODE UnwindCode[1];
; /*  UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
; *   union {
; *       OPTIONAL ULONG ExceptionHandler;
; *       OPTIONAL ULONG FunctionEntry;
; *   };
; *   OPTIONAL ULONG ExceptionData[]; */
; } UNWIND_INFO, *PUNWIND_INFO;
; Here's the description of the UNWIND_INFO structure members taken directly from the MSDN:
; Version   Version number of the unwind data, currently 1.  
; Flags   Three flags are currently defined: 
; UNW_FLAG_EHANDLER The function has an exception handler that should be called when looking for functions that need to examine exceptions. 
; UNW_FLAG_UHANDLER The function has a termination handler that should be called when unwinding an exception. 
; UNW_FLAG_CHAININFO This unwind info structure is not the primary one for the procedure. Instead, the chained unwind info entry is the contents of a previous RUNTIME_FUNCTION entry. See the following text for an explanation of chained unwind info structures. If this flag is set, then the UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER flags must be cleared. Also, the frame register and fixed-stack allocation fields must have the same values as in the primary unwind info. 
; SizeOfProlog   Length of the function prolog in bytes.  
; CountOfCodes   This is the number of slots in the unwind codes array. Note that some unwind codes (for example, UWOP_SAVE_NONVOL) require more than one slot in the array.  
; FrameRegister    If nonzero, then the function uses a frame pointer, and this field is the number of the nonvolatile register used as the frame pointer, using the same encoding for the operation info field of UNWIND_CODE nodes.  
; FrameOffset    If the frame register field is nonzero, then this is the scaled offset from RSP that is applied to the FP reg when it is established. The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240. This permits pointing the FP reg into the middle of the local stack allocation for dynamic stack frames, allowing better code density through shorter instructions (more instructions can use the 8-bit signed offset form).  
; UnwindCode   This is an array of items that explains the effect of the prolog on the nonvolatile registers and RSP. See the section on UNWIND_CODE for the meanings of individual items. For alignment purposes, this array will always have an even number of entries, with the final entry potentially unused (in which case the array will be one longer than indicated by the count of unwind codes field).  
; ExceptionHandler   This is an image-relative pointer to either the function's language-specific exception/termination handler (if flag UNW_FLAG_CHAININFO is clear and one of the flags UNW_FLAG_EHANDLER or UNW_FLAG_UHANDLER is set).  
; Language-specific handler data (ExceptionData)   This is the function's language-specific exception handler data. The format of this data is unspecified and completely determined by the specific exception handler in use.  
; Chained Unwind Info (ExceptionData)   If flag UNW_FLAG_CHAININFO is set then the UNWIND_INFO structure ends with three UWORDs. These UWORDs represent the RUNTIME_FUNCTION information for the function of the chained unwind.
; The possible values of the Flags field are:
; #define UNW_FLAG_EHANDLER  0x01
; #define UNW_FLAG_UHANDLER  0x02
; #define UNW_FLAG_CHAININFO 0x04
      db      19h,0,0,0
   dd      RVA expt_handler
    dd      0


section '.idata' import data readable writeable
library       kernel32,       'KERNEL32.DLL',\
 user32,         'USER32.DLL'
include       '%fasminc%\api\kernel32.inc'
include     '%fasminc%\api\user32.inc'    


exception.inc file:
Code:
EXCEPTION_CONTINUE_EXECUTION                =       -1
EXCEPTION_CONTINUE_SEARCH         =        0
EXCEPTION_NONCONTINUABLE          =        1      ; Noncontinuable exception

EXCEPTION_MAXIMUM_PARAMETERS          =       15      ; maximum number of exception parameters

EXCEPTION_GUARD_PAGE                    =        80000001h
EXCEPTION_DATATYPE_MISALIGNMENT           =        80000002h
EXCEPTION_BREAKPOINT                      =        80000003h
EXCEPTION_SINGLE_STEP                     =        80000004h
EXCEPTION_ACCESS_VIOLATION                =       0C0000005h
EXCEPTION_IN_PAGE_ERROR                   =       0C0000006h
EXCEPTION_INVALID_HANDLE          =       0C0000008h
EXCEPTION_ILLEGAL_INSTRUCTION             =       0C000001Dh
EXCEPTION_NONCONTINUABLE_EXCEPTION        =       0C0000025h
EXCEPTION_INVALID_DISPOSITION             =       0C0000026h
EXCEPTION_ARRAY_BOUNDS_EXCEEDED           =       0C000008Ch
EXCEPTION_FLT_DENORMAL_OPERAND            =       0C000008Dh
EXCEPTION_FLT_DIVIDE_BY_ZERO              =       0C000008Eh
EXCEPTION_FLT_INEXACT_RESULT              =       0C000008Fh
EXCEPTION_FLT_INVALID_OPERATION           =       0C0000090h
EXCEPTION_FLT_OVERFLOW                    =       0C0000091h
EXCEPTION_FLT_STACK_CHECK         =       0C0000092h
EXCEPTION_FLT_UNDERFLOW                   =       0C0000093h
EXCEPTION_INT_DIVIDE_BY_ZERO              =       0C0000094h
EXCEPTION_INT_OVERFLOW                    =       0C0000095h
EXCEPTION_PRIV_INSTRUCTION                =       0C0000096h
EXCEPTION_STACK_OVERFLOW          =       0C00000FDh
CONTROL_C_EXIT                            =       0C000013Ah
EXCEPTION_POSSIBLE_DEADLOCK               =       0C0000194h


struc EXCEPTION_POINTERS
{
.PEXCEPTION_RECORD  rq      1       ; ExceptionRecord
.PCONTEXT          rq      1       ; ContextRecord
}


struc EXCEPTION_RECORD64
{
.ExceptionCode               rd      1
.ExceptionFlags            rd      1
.EXCEPTION_RECORD  rq      1       ; ExceptionRecord
.ExceptionAddress  rq      1
.NumberParameters  rd      1
.unusedAlignment   rd      1       ; padding
.ExceptionInformation      rq      EXCEPTION_MAXIMUM_PARAMETERS
}


struc XMM_SAVE_AREA32
{
.ControlWord               rw      1
.StatusWord                rw      1
.TagWord           rb      1
.Reserved1         rb      1
.ErrorOpcode               rw      1
.ErrorOffset               rd      1
.ErrorSelector             rw      1
.Reserved2         rw      1
.DataOffset                rd      1
.DataSelector              rw      1
.Reserved3         rw      1
.MxCsr                     rd      1
.MxCsr_Mask                rd      1
.FloatRegisters            rb      8*16    ; every 128-bit holds st in low 80-bits or mm in low 64-bits
.XmmRegisters           rb      16*16   ; yeah, AMD64 in long mode (64-bit) has 16 xmm registers
.Reserved4          rb      96
}


struc CONTEXT64
{
; Register parameter home addresses.
; N.B. These fields are for convience - they could be used to extend the context record in the future.
.P1Home                  rq      1
.P2Home                    rq      1
.P3Home                    rq      1
.P4Home                    rq      1
.P5Home                    rq      1
.P6Home                    rq      1
; Control flags.
.ContextFlags          rd      1
.MxCsr                     rd      1
; Segment Registers and processor flags.
.SegCs                 rw      1
.SegDs                     rw      1
.SegEs                     rw      1
.SegFs                     rw      1
.SegGs                     rw      1
.SegSs                     rw      1
.EFlags                    rd      1
; Debug registers
.Dr0                  rq      1
.Dr1                       rq      1
.Dr2                       rq      1
.Dr3                       rq      1
.Dr6                       rq      1
.Dr7                       rq      1
; Integer registers.
.Rax                       rq      1
.Rcx                       rq      1
.Rdx                       rq      1
.Rbx                       rq      1
.Rsp                       rq      1
.Rbp                       rq      1
.Rsi                       rq      1
.Rdi                       rq      1
.R8                        rq      1
.R9                        rq      1
.R10                       rq      1
.R11                       rq      1
.R12                       rq      1
.R13                       rq      1
.R14                       rq      1
.R15                       rq      1
; Program counter.
.Rip                 rq      1
; Floating point state.
.FltSave                XMM_SAVE_AREA32
; Vector registers.
.VectorRegister               rb      16*26
.VectorControl         rq      1
; Special debug control registers.
.DebugControl                rq      1
.LastBranchToRip   rq      1
.LastBranchFromRip rq      1
.LastExceptionToRip        rq      1
.LastExceptionFromRip      rq      1
}    


Description: compiled win64 executable doing exception handling using PE32+ Exception Directory
Download
Filename: win64_exception_directory.zip
Filesize: 640 Bytes
Downloaded: 240 Time(s)

Post 08 Mar 2010, 09:22
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
alorent



Joined: 05 Dec 2005
Posts: 201
alorent
Great work as always Feryno!!! Very Happy

Thanks!!!
Post 08 Mar 2010, 11:33
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7108
Location: Slovakia
vid
Nice!
Post 08 Mar 2010, 12:41
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
Feryno,

Aren't those
Code:
EXCEPTION_CONTINUE_EXECUTION            =       -1
EXCEPTION_CONTINUE_SEARCH               =        0
EXCEPTION_NONCONTINUABLE                =        1    
for __try/__except C/C++ exception handling (UnhandlerExceptionFilter() too)?

Not a long time ago I've tried to use raw SEH (32-bit), got error and traced into NTDLL. To my surprise, that code checks for 0, 1 and 2 return values (STATUS_INVALID_DISPOSITION for anything else). Then I found this:
Code:
ExceptionContinueExecution = 0
ExceptionContinueSearch = 1
ExceptionNestedException = 2
ExceptionCollidedUnwind = 3    
Perhaps x86-64 differs in this matter. Or exception directory approach does.
Post 09 Mar 2010, 10:59
View user's profile Send private message Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 449
Location: Czech republic, Slovak republic
Feryno
I may try other return values and use debugger to watch what happens then.
I extracted the return values from DDK or WDK or something like this and the date of the exception.inc file at my disk / in my zip archives shows that I created it in year 2006.
I didn't identify yet input parameters passed to exception handler, I identified only R8 which points to Context, I didn't identify RCX, RDX, R9, I have a feeling that OS put something into stack also, so I have a feeling that perhaps 5 or more input params are passed to exception handler (I used DebugCtl branch feature in debugger to indentify RIPs backward before OS transfered execution to exception handler).
Post 09 Mar 2010, 13:29
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
MSDN/WDK wrote:
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE) (
    IN PEXCEPTION_RECORD ExceptionRecord,
    IN ULONG64 EstablisherFrame,
    IN OUT PCONTEXT ContextRecord,
    IN OUT PDISPATCHER_CONTEXT DispatcherContext
);
On my 32-bit XP SP2 EstablisherFrame points to EXCEPTION_REGISTRATION for current handler, DISPATCHER_CONTEXT looks different from 64-bit.
Post 09 Mar 2010, 16:23
View user's profile Send private message Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 449
Location: Czech republic, Slovak republic
Feryno
yes, great, that is the exact thing I was looking for!!!
Post 10 Mar 2010, 07:26
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr
Feryno,

Note the following (VC\crt\src\excpt.h):
Code:
typedef enum _EXCEPTION_DISPOSITION {
    ExceptionContinueExecution,
    ExceptionContinueSearch,
    ExceptionNestedException,
    ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;    
Deeper digging unearthed exsup.inc (how do I forgot it? It was mentioned in Matt Pietrek's article from MSJ, Jan 1997).

Funny constant name, sizeog_buggy_instruction. Wink
Post 10 Mar 2010, 07:37
View user's profile Send private message Reply with quote
Feryno



Joined: 23 Mar 2005
Posts: 449
Location: Czech republic, Slovak republic
Feryno
sizeog = typo error, at my type of keyboard the key G is just at the right side of the key F
Post 11 Mar 2010, 10:02
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
asmnewbie4



Joined: 06 Apr 2012
Posts: 1
Location: Somewhere ...
asmnewbie4
Many thanks, it's very usefull Wink

_________________
While(1) = 0EBh, 0FEh ...
Post 06 Apr 2012, 19:47
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2019, Tomasz Grysztar.

Powered by rwasa.