;------------------------------------------------ ; Invalid Disposition exception trick ; or making noncontinuable exception continuable ;) ; Copyleft (c) Omega Red 2007, 2008 ; fasm source ;------------------------------------------------ ; 32-bit executable format PE GUI entry start include '%fasminc%\win32a.inc' include '%fasminc%\macro\proc32.inc' ;------------------------------------------------ struct EXCEPTION_POINTERS ExceptionRecord dd ? ; ptr ContextRecord dd ? ; ptr ends struct EXCEPTION_RECORD ExceptionCode dd ? ExceptionFlags dd ? NestedExceptionRecord dd ? ExceptionAddress dd ? NumberParameters dd ? ExceptionInformation dd 15 dup (?) ends SIZE_OF_80387_REGISTERS = 80 MAXIMUM_SUPPORTED_EXTENSION = 512 struct FLOATING_SAVE_AREA ControlWord dd ? StatusWord dd ? TagWord dd ? ErrorOffset dd ? ErrorSelector dd ? DataOffset dd ? DataSelector dd ? RegisterArea db SIZE_OF_80387_REGISTERS dup (?) Cr0NpxState dd ? ends struct CONTEXT ContextFlags dd ? Dr0 dd ? Dr1 dd ? Dr2 dd ? Dr3 dd ? Dr6 dd ? Dr7 dd ? FloatSave FLOATING_SAVE_AREA SegGs dd ? SegFs dd ? SegEs dd ? SegDs dd ? Edi dd ? Esi dd ? Ebx dd ? Edx dd ? Ecx dd ? Eax dd ? Ebp dd ? Eip dd ? SegCs dd ? EFlags dd ? Esp dd ? SegSs dd ? ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup (?) ends ;------------------------------------------------ section 'code' code readable executable start: ; int3 ; install UEF invoke SetUnhandledExceptionFilter, UnhandledExceptionFilter ; install SEH push dword seh_handler push dword [fs:0] mov dword [fs:0], esp invoke GetModuleHandle, _ntdll invoke GetProcAddress, eax, _rre ; cause #UD exception which will set up hardware BPX on RtlRaiseException ud2 nop ; cause divide error -> invalid disposition exception (normally noncontinuable ) xor eax,eax div eax _end: ; delete SEH pop dword [fs:0] add esp, 4 invoke msgbox, 0, t9, t9, 0 invoke exit, 0 ;------------------------------------------------ proc seh_handler ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext push ebx esi edi ; save win32 callback registers mov ebx, [ExceptionRecord] mov esi, [ContextRecord] mov eax, [ebx+EXCEPTION_RECORD.ExceptionCode] cmp eax, STATUS_ILLEGAL_INSTRUCTION ; c000001d jne seh_ss invoke msgbox, 0, t2, t1, 0 ; #UD: let's install BPX on RtlRaiseException push [esi+CONTEXT.Eax] ; address here pop [esi+CONTEXT.Dr0] mov [esi+CONTEXT.Dr7], 0x00000101 ; enable local BPX on DR0 add [esi+CONTEXT.Eip], 2 ; skip UD2 jmp seh_end seh_ss: cmp eax, STATUS_SINGLE_STEP ; 80000004 - BPM or single step jne seh_dz invoke msgbox, 0, t3, t1, 0 ; RtlRaiseException hook bpx ;] ; check if exception is noncontinuable - if it is, make it continuable mov eax, [esi+CONTEXT.Esp] ; get esp on RtlRaiseException entry mov eax, [eax+4] ; get parameter - ptr to EXCEPTION_RECORD test [eax+EXCEPTION_RECORD.ExceptionFlags], EXCEPTION_NONCONTINUABLE jz seh_ss2 ; continuable exception, ignore ; clear noncontinuable flag and [eax+EXCEPTION_RECORD.ExceptionFlags], not EXCEPTION_NONCONTINUABLE seh_ss2: mov [esi+CONTEXT.Dr7], 0 ; disable bpx so we don't loop forever jmp seh_end seh_dz: cmp eax, STATUS_INTEGER_DIVIDE_BY_ZERO jne seh_id invoke msgbox, 0, t4, t1, 0 ; divide error, let's trigger noncontinuable condition mov eax, 0xdeadc0de ; invalid disposition jmp seh_end2 seh_id: ; invalid disposition handler (which should be made continuable by our hook ;) cmp eax, STATUS_INVALID_DISPOSITION ; c0000026 jz @f ; unknown exception, commit suicide ;] invoke msgbox, 0, t8, t1, 0 mov eax, 1 ; continue search (= effectively kill process) jmp seh_end2 @@: ; fix the condition that leaded to noncontinuable exception - divide error in this case invoke msgbox, 0, t5, t1, 0 mov eax, [ebx+EXCEPTION_RECORD.NestedExceptionRecord] mov eax, [eax-0x0c] ; context pointer - ONLY IF EXCEPTION PARAMETERS ARE DIRECTLY BEFORE SEH FRAME! mov [eax+CONTEXT.Eax], 0xdeadbeef ; correct div ;) ; this exception is now continuable so we can go ahead seh_end: xor eax, eax ; status: continue execution seh_end2: pop edi esi ebx ret ; proc macro takes care of stack balance endp ;------------------------------------------------ UnhandledExceptionFilter: push esi edi ebx ExceptionPointers equ esp+0x10 ; EXCEPTION_POINTERS mov eax, [ExceptionPointers] mov ebx, [eax+EXCEPTION_POINTERS.ExceptionRecord] ; exception info mov esi, [eax+EXCEPTION_POINTERS.ContextRecord] ; CPU state when exception occured mov eax, [ebx+EXCEPTION_RECORD.ExceptionCode] ; code cmp eax, STATUS_INTEGER_DIVIDE_BY_ZERO jne @f ; nothing for now - seh fixes context 2 frames back *o* ; well, we NEED to handle it here - I still don't know exactly why ZwRaiseException ignores SEH after nested exception and throws us here ; seems like some unwind is going on, since DRs are reverted to the state at previous (first) DIV error ; (that's actually good, because we don't need to reenable bpx manually) invoke msgbox, 0, t7, t6, 0 jmp uef_end ;------------ @@: ; unknown exception invoke msgbox, 0, t8, t6, 0 ;------------ uef_end: mov eax, -1 ; continue pop ebx edi esi ret 4 ;------------------------------------------------ section 'data' data readable writable _ntdll db 'ntdll.dll',0 _rre db 'RtlRaiseException',0 t1 db 'SEH',0 t2 db 'STATUS_ILLEGAL_INSTRUCTION',10,'Installing RtlRaiseException hook',0 t3 db 'STATUS_SINGLE_STEP',10,'RtlRaiseException called',0 t4 db 'STATUS_INTEGER_DIVIDE_BY_ZERO',10,'Returning invalid disposition',0 t5 db 'STATUS_INVALID_DISPOSITION',10,'Fixing div and continuing',0 t6 db 'UEF',0 t7 db 'STATUS_INTEGER_DIVIDE_BY_ZERO',0 t8 db 'Unknown exception',0 t9 db 'Exiting properly, all is ok',0 ;------------------------------------------------ data import library user, 'user32.dll',\ kernel, 'kernel32.dll' import user,\ msgbox, 'MessageBoxA' import kernel,\ GetProcAddress, 'GetProcAddress',\ GetModuleHandle, 'GetModuleHandleA',\ SetUnhandledExceptionFilter, 'SetUnhandledExceptionFilter',\ exit, 'ExitProcess' end data ;------------------------------------------------
There are 31,320 total registered users.
[+] expand