Nytro Posted November 23, 2011 Report Posted November 23, 2011 Exception handling routines (ntdll)/* * exception handling routines (xp 32-bit, partial/incomplete) * * ntdll 5.1.2600.5755 * v2 (updated jan 2011) * * - hawkes <hawkes@sota.gen.nz> * * useful link: http://www.eeye.com/html/resources/newsletters/vice/VI20060830.html * */#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* prev; 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 */VOID KiUserExceptionDispatcher(__in PCONTEXT ContextRecord, __in PEXCEPTION_RECORD ExceptionRecord) { NTSTATUS Status; if (RtlDispatchException(ContextRecord, ExceptionRecord)) { /* 7C90E48E modify the execution context of the current thread to whatever the chosen exception handler gives us */ Status = ZwContinue(ContextRecord, 0); } else { /* 7C90E49A no exception handler found so re-raise the exception for a debugger or the NT exception handler */ Status = ZwRaiseException(ExceptionRecord, ContextRecord, 0); } /* 7C90E4A5 build an exception record with 20 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);}/* 7C92A970 returns true if exception handler was found and used */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; if (RtlCallVectoredExceptionHandlers(ExceptionRecord, ContextRecord)) { /* 7C95010A */ ret = 1; } else { /* 7C92A991 */ RtlpGetStackLimits(&StackLimit, &StackBase); /* 7C92A99F */ head = RtlpGetRegistrationHead(); highest = 0; while (head != (PEXCEPTION_REGISTRATION) -1) { /* 7C92A9B4 */ if (head < StackLimit || head + sizeof(EXCEPTION_REGISTRATION) > StackBase || head & 3) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } if (head->handler >= StackLimit && head->handler < StackBase) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } /* 7C92A9E3 */ if (!RtlIsValidHandler(head->handler)) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } else if (LogExceptions) { /* 7C950113 */ RtlpLogExceptionHandler(ContextRecord, ExceptionRecord, 0, head, 0x10); } /* 7C92A9FE */ 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 */ RtlpLogLastExceptionDisposition(highest, hret); } /* 7C92AA1E */ if (head == NULL) { ExceptionRecord->ExceptionFlags &= ~EH_NESTED_CALL; } /* 7C92AA27 */ if (hret == DISPOSITION_DISMISS) { if (ExceptionRecord->ExceptionFlags & EH_NONCONTINUABLE) { /* 7C950181 */ exRec.ExceptionCode = 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; } } else if (hret == DISPOSITION_CONTINUE_SEARCH) { /* 7C92A31C a little fudging with 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.ExceptionRecord = ExceptionRecord; exRec.NumberParameters = 0; RtlRaiseException(&exRec); } /* 7C92A326 */ head = head->prev; } }exit: /* 7C92AA43 */ return ret;}/* 7C92A934 */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; RtlEnterCriticalSection(&RtlpCalloutEntryLock); for (veh = (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList.Flink); veh != (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList; veh = (PVECTORED_EXCEPTION_NODE) veh->ListEntry.Flink) { handler = RtlDecodePointer(veh->handler); disposition = handler(&Rec); if (disposition == EXCEPTION_CONTINUE_EXECUTION) { ret = 1; break; } } 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_HANDLE_VALUE, 22, &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) { RtlInvalidHandlerDetected(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, safeseh_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 = MemoryBasicVlmInformation */ if (NtQueryVirtualMemory((HANDLE) -1, handler, 3, &mbi, sizeof(MEMORY_BASIC_INFORMATION), NULL) < 0) { return 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->Ldr != 0 && node != NULL) { while (node != &_PEB->Ldr->InLoadOrderModuleList) { /* 7C92AB00 */ if (handler < node->BaseAddr) { node = node->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 (header > base && header < base + ((PIMAGE_NT_HEADER) base)->OptionalHeaders.SizeOfImage) { /* 7C950D7D */ RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz); } } break; } } } /* 7C92AB2C */ if (LdrpInLdrInit) { RtlLeaveCriticalSection(&LdrpLoaderLock); } } *base_addr = base; return safeseh_table;}Vectored exception handling:typedef struct _LdrpVectorHandlerList { struct _LdrpVectorHandlerList *Prev; struct _LdrpVectorHandlerList *Next; DWORD Depth; PVECTORED_EXCEPTION_HANDLER VectoredHandler;} VECTORED_HANDLER_LIST, *PVECTORED_HANDLER_LIST;VECTORED_HANDLER_LIST LdrpVectorHandlerList[2];BOOLEAN RtlpCallVectoredHandlers(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord, BOOL flag) { BOOLEAN ret; DWORD hret; PVECTORED_HANDLER_LIST freeList, head, next; PTEB teb = _TEB; // fs:18h PPEB peb = teb->ProcessEnvironmentBlock; // teb:30h ret = 0; head = &LdrpVectorHandlerList[flag]; /* there are two possible bit flags with CrossProcessFlags that it checks here flag = 0 corresponds to ProcessUsingVEH flag = 1 corresponds to ProcessUsingVCH */ if (peb->CrossProcessFlags & (1 << (flag + 2)) { freeList = NULL; /* get a slim reader/writer lock on the vectorhandlerlist */ RtlAcquireSRWLockExclusive(head); next = head->Next; while (next != head) { next->Depth++; RtlReleaseSRWLockExclusive(head); handler = RtlDecodePointer(next->VectoredHandler); hret = handler(ExceptionRecord); RtlAcquireSRWLockExclusive(head); next->Depth--; if (next->Depth == 0) { next->Next->Prev = next->Prev; next->Prev->Next = next->Next; if (next->Prev == next->Next) { /* this is actuall an atomic bit reset (lock btr) instruction * basically they are clearing either the ProcessUsingVEH or ProcessUsingVCH flags * when the list becomes empty */ peb->CrossProcessFlags &= ~(1 << (flag + 2)); } next->Prev = freeList; freeList = next; } next = next->Prev; if (hret == EXCEPTION_CONTINUE_EXECUTION) { ret = 1; break; } } RtlReleaseSRWLockExclusive(head); while (freeList) { LPVOID p = freeList; freeList = freeList->Prev; RtlFreeHeap(peb->ProcessHeap, 0, p); } } return ret;}Probabil reverse engineering (pe XP) la aceste functii, in cel mai rau caz o implementare particulara. Quote