#define DISPOSITION_DISMISS 0#define disposition_continue_search 1#define disposition_nested_exception 2#define Disposition_collided_unwind 3#define eh_noncontinuable 0x01#define eh_unwinding 0x02#define EH_EXIT_UNWIND 0x04# Define Eh_stack_invalid 0x08#define eh_nested_call 0x10#define status_noncontinuable_exception 0xC0000025#define Status_invalid_disposition 0xc0000026#define exception_continue_execution-1#define PAGE_EXEC_MASK (PAGE_EXECUTE| page_execute_read| page_execute_readwrite| page_execute_writecopy) typedef struct _EXCEPTION_RECORD {DWORD exceptioncode; DWORD ExceptionFlags; struct _exception_record *exceptionrecord; VAR_CW PVOID exceptionaddress; DWORD numberparameters; Ulong_ptr exceptioninformation[15];} Exception_record, *pexception_record;typedef struct _exception_registration{struct _exception_registration* pNext; Pexception_handler HANDLER;} Exception_registration, *pexception_registration;typedef struct _vectored_exception_node {LIST_ENTRY ListEntry; Pvectored_exCeption_handler HANDLER;} Vectored_exception_node, *pvectored_exception_node;typedef enum _exception_disposition {ExceptionContinueExecution , Exceptioncontinuesearch, Exceptionnestedexception, exceptioncollidedunwind} exception_disposition;/* 7C97E3FA * * UCHAR logexceptions = 0;/* 7c97e3c0 */list_entry rtlpcalloutentrylist;/* 7c9805e0 */rtl_critical_section Rtlpcalloutentrylock; Rtl_critical_section ldrploaderlock;/* 7c90e47c *//* * User Layer exception Dispatch source */void Kiuserexceptiondispatcher (__in PCONTEXT Contextrecord, __in Pexception_record exceptionrecord) {NTSTATUS Status;//Call the Rtldispatchexception function to distribute the exception. if ( Rtldispatchexception (Contextrecord, ExceptionRecord)) {/* 7c90e48e modify the execution context of the current thread to Whatever the chosen exception handler gives us *//End exception Distribution Status = Zwcontinue (Contextrecord, 0); } else {/* 7c90e49a no exception handler found so re-raise the exception for a debugger or the NT exception handler *// This triggers an exception, and when the last argument is triggered, it passes false, indicating that this is a second triggered exception. Status= Zwraiseexception (ExceptionRecord, Contextrecord, FALSE); }/* 7c90e4a5 build a exception record with bytes on the stack, second chance exception? */Pexception_record exception = (Pexception_record) alloca (0x14); Exception->exceptioncode = Status; Exception->exceptionflags = 1; Exception->exceptionrecord = Contextrecord; Exception->numberparameters = 1; return Rtlraiseexception (exception);} LPVOID Rtlpgetregistrationhead () {_asm mov eax, fs:[0] _asm ret}/* 7c92a970 If the exception is handled returns True */boolean rtldispatchexception ( PCONTEXT Contextrecord, Pexception_record exceptionrecord) {BOOLEAN ret = 0; LPVOID StackBase, Stacklimit; Pexception_registration Head; DWORD Kprocess_flags; DWORD Dispatch, highest; Exception_record Exrec; The exception is first given to veh processing. If able to handle, end exception distribution if (Rtlcallvectoredexceptionhandlers (ExceptionRecord, Contextrecord)) {/* 7c95010a */ret = 1;} else {/* Otherwise hand over to SEH processing */* 7c92a991 */rtlpgetstacklimits (&stacklimit, &stackbase); Get the Seh Link header node/* 7c92a99f */head = (Pexception_registration) Rtlpgetregistrationhead (); highest = 0; while (head! = (pexception_registration)-1) {//determines if the address of the obtained node is correct if (Head < Stacklimit | | head + sizeof (Exception_reg istration) > StackBase | | Head & 3) {exceptionrecord->exceptionflags |= eh_stack_invalid; goto exit;}//Determine if the address of the exception handler is correct if (Head->handl Er >= stacklimit && head->handler < stackbase) {exceptionrecord->exceptionflags |= EH_STACK_INVALID ; Goto exit; }//To determine if the exception handler is a valid handling function if (! Rtlisvalidhandler (Head->handler)) {/* 7c92a336 */exceptionrecord->exceptionflags |= EH_STACK_INVALID; Goto exit ; } else if (logexceptions) {/* 7c950113 */Rtlplogexceptionhandler (Contextrecord, ExceptionRecord, 0, head, 0x10);}//Execute Seh's _except_handler4 () Hret = Rtlpexecutehandlerforexception (Contextrecord, head, ExceptionRecord, &dispatch, Head->handler); if (logexceptions) {/* 7c950129 there is a second parameter to this function that I don ' t understand yet */Rtlploglastex CeptIondisposition (highest, Hret); }/* 7C92AA1E */if (head = = NULL) {exceptionrecord->exceptionflags &= ~eh_nested_call;}/* 7C92AA27 * * if (hret = = Disposition_dismiss) {if (Exceptionrecord->exceptionflags & eh_noncontinuable) {/* 7c950181 */ExRec.Exceptio NCode = status_noncontinuable_exception; Exrec.exceptionflags = eh_noncontinuable; Exrec.exceptionrecord = ExceptionRecord; exrec.numberparameters = 0; Rtlraiseexception (&EXREC); /* 7c92a31c a little fudging with this block */if (Exceptionrecord->exceptionflags & eh_stack_invalid) {goto exit ; }} else {/* 77EDBD64 */ret = 1; break;}} If the SEH filter function returns a search for other filtering functions to process the else if (Hret = = Disposition_continue_search) {/* 7c92a31c a little fudging with the this block */ if (Exceptionrecord->exceptionflags & eh_stack_invalid) {goto exit;}} else if (Hret = = disposition_nested_exception) {/* 7c950169 */exceptionrecord->exceptionflags |= EH_NESTED_CALL; if ( Dispatch > Highest) {highest = dispatch;}} else {/* 7c950147 */exrec.exceptioncode = status_invalid_disposition; exrec.exceptionflags = eh_noncontinuable; ExRec.E Xceptionrecord = ExceptionRecord; exrec.numberparameters = 0; Rtlraiseexception (&EXREC); }/* 7c92a326 */head = head->pnext; }}exit:/* 7c92aa43 */return ret; /* 7c92a934 *///call Veh function Boolean rtlcallvectoredexceptionhandlers (Pexception_record ExceptionRecord, PCONTEXT Contextrecord) {BOOLEAN ret = FALSE; struct {Pexception_record erec; PCONTEXT CRec; } Rec; Pvectored_exception_node Veh; Pvectored_exception_handler HANDLER; DWORD disposition if (Rtlpcalloutentrylist.flink = = &rtlpcalloutentrylist) {return FALSE;} Erec = ExceptionRecord; CRec = ExceptionRecord; Enter the critical Zone rtlentercriticalsection (&rtlpcalloutentrylock); Start traversing Veh's doubly linked list for (Veh = (pvectored_exception_node) rtlpcalloutentrylist.flink); Veh! = (pvectored_exception_node) rtlpcalloutentrylist; Veh = (pvectored_exception_node) veh->listentry.flink) {//decryption handler Address handler = Rtldecodepointer (Veh->handler); Call handler function disposition = handler (&REC); Determines whether the handler handles the exception. If yes, the loop ends. If not, continue to find the next handler function. if (disposition = = exception_continue_execution) {//sets the return value to true. ret = 1; break;}} Leaving the critical section rtlleavecriticalsection (&rtlpcalloutentrylock); return ret;} /* 7C9033DC */void rtlpgetstacklimits (lpvoid **stacklimit, lpvoid **stackbase) {pteb teb = _teb;//fs:18h *StackLimit = teb->nttib->stacklimit; *stackbase = teb->nttib->stackbase; return;} /* 7c92aa50 */boolean Rtlisvalidhandler (Pexception_handler HANDLER) {DWORD TABLE_SZ; LPVOID safeseh_table, base_addr; DWORD ret, Result_len, exec_flags, High, low; Memory_basic_information MBI; safeseh_table = rtllookupfunctiontable (Handler, &BASE_ADDR, &TABLE_SZ); if (safeseh_table = = NULL | | table_sz = = 0) {/* 7c9500d1 processexecuteflags*/if (zwqueryinformationprocess (INVALID_HAND Le_value, &exec_flags, 4, NULL) >= 0) {/* 7c92cf94 0x10 = executedispatchenable */if (! ( Exec_flags & 0x10)) { return 1; }}/* 7c935e8e * * if (ntqueryvirtualmemory (Invalid_handle_value, Handler, NULL, &mbi, sizeof (memory_basic_ Information), &result_len) < 0) {return 1;}/* 7C935EA9 */if (!) ( MBi. Protect & Page_exec_mask) {rtlinvalidhandlerdetected (handler,-1,-1); return 0;} else if (MBI. Type! = sec_image) {return 1;} Rtlcaptureimageexceptionvalues (MBI. Allocationbase, &safeseh_table, &TABLE_SZ); /* 7C935ED0 */if (var_10 = = NULL | | table_sz = = 0) {return 1;} return 0; } else if (safeseh_table = = (LPVOID)-1 && TABLE_SZ = = 1) {return 0;}/* 7C9500A6 */if (TABLE_SZ < 0) {RTL Invalidhandlerdetected (Handler, safeseh_table, TABLE_SZ); return 0; } rel_addr = handler-base_addr; High = TABLE_SZ; Low = 0; /* 7c9500b1 binary search through SafeSEH table */do {idx = (high + low)/2; if (Rel_addr < Safeseh_table[idx]) {if (idx = = 0) {rtlinvalidhandlerdetected (handler, safeseh_table, TABLE_SZ); return 0;} High = idx-1; if (High < low) {RTLINVAlidhandlerdetected (Handler, safeseh_table, TABLE_SZ); return 0; }} else if (Rel_addr > Safeseh_table[idx]) {low = idx + 1; if (High < low) {rtlinvalidhandlerdetected (handler, SA Feseh_table, TABLE_SZ); return 0; }} else {break;}} while (1); return 1;} /* 7C92AAA4 */lpvoid rtllookupfunctiontable (Pexception_handler HANDLER, DWORD *base_addr, DWORD *TABLE_SZ) {MEMORY_ Basic_information MBI; LPVOID Safeseh_table, Base; if (Ldrpinldrinit && rtltryentercriticalsection (&ldrploaderlock) = = 0) {/* 7c92dd29 3 = Memorybasicvlminform ation */if (Ntqueryvirtualmemory ((HANDLE)-1, Handler, 3, &mbi, sizeof (memory_basic_information), NULL) < 0) {RET Urn NULL; } else if (MBI. Type! = sec_image) {return NULL;} base = MBi. baseaddress; /* 7C92DD51 */rtlcaptureimageexceptionvalues (base, &safeseh_table, TABLE_SZ); } else {if (_teb! = NULL) {/* 7c92aad9 * * Pldr_module node = _peb->ldr->inloadordermodulelist.flink if (_peb->l Dr! = 0 && Node! = NULL) {WHIle (Node! = &_peb->ldr->inloadordermodulelist) {/* 7C92AB00 */if (handler < NODE->BASEADDR) {node = no de->inloadordermodulelist.flink; Continue } if (handler >= node->baseaddr + node->sizeofimage) {node = node->inloadordermodulelist.flink; continue;}/ * 7C92AB14 */base = node->baseaddr; Rtlcaptureimageexceptionvalues (base, &safeseh_table, TABLE_SZ); if (safeseh_table = = NULL && ntdllbase! = null && (base = Rtlntimageheader (ntdllbase)) = null) {if (head Er > Base && Header < base + ((Pimage_nt_header) base)->optionalheaders.sizeofimage) {/* 7c950d7d */RTL Captureimageexceptionvalues (base, &safeseh_table, TABLE_SZ); }} break; }}}/* 7C92AB2C */if (ldrpinldrinit) {rtlleavecriticalsection (&ldrploaderlock);}} *base_addr = base; return safeseh_table;}
Reverse analysis of Windows user layer exception distribution source code