/*++ Copyright (c) 1989 Microsoft Corporation Module Name: support.c Abstract: This module implements internal support for the verification code. Author: Silviu Calinoiu (SilviuC) 1-Mar-2001 Revision History: --*/ #include "pch.h" #include "verifier.h" #include "support.h" // // Security checks // VOID CheckObjectAttributes ( POBJECT_ATTRIBUTES Object ) { if (Object /* && Object->ObjectName */) { if (Object->ObjectName == NULL) { DbgPrint ("Object attributes @ %p with null name \n", Object); DbgBreakPoint (); } if (Object->SecurityDescriptor == NULL) { DbgPrint ("Object attributes @ %p with null security descriptor \n", Object); DbgBreakPoint (); } } } // // Handle management // LIST_ENTRY HandleList; RTL_CRITICAL_SECTION HandleLock; ULONG HandleBreakOnDelayed = 1; VOID HandleInitialize ( ) { InitializeListHead (&HandleList); RtlInitializeCriticalSection (&HandleLock); } PAVRF_HANDLE HandleFind ( HANDLE Handle ) { PLIST_ENTRY Current; PAVRF_HANDLE Entry; RtlEnterCriticalSection (&HandleLock); Current = HandleList.Flink; while (Current != &HandleList) { Entry = CONTAINING_RECORD (Current, AVRF_HANDLE, Links); Current = Current->Flink; if (Entry->Handle == Handle) { RtlLeaveCriticalSection (&HandleLock); return Entry; } } RtlLeaveCriticalSection (&HandleLock); return NULL; } PWSTR HandleName ( PAVRF_HANDLE Handle ) { if (Handle) { if (Handle->Name) { return Handle->Name; } else { if (Handle->Delayed) { return L""; } else { return L""; } } } return L""; } PAVRF_HANDLE HandleAdd ( HANDLE Handle, ULONG Type, BOOLEAN Delayed, PWSTR Name, PVOID Context ) { PLIST_ENTRY Current; PAVRF_HANDLE Entry; PWSTR NameCopy; ULONG Hash; if (HandleBreakOnDelayed && Delayed) { DbgPrint (" --- dumping ... %p \n", HandleList.Flink); HandleDump (NULL); DbgPrint ("AVRF: undetected handle \n"); DbgBreakPoint (); } Entry = (PAVRF_HANDLE) RtlAllocateHeap (RtlProcessHeap(), 0, sizeof *Entry); if (Entry == NULL) { return NULL; } if (Name) { NameCopy = (PWSTR) RtlAllocateHeap (RtlProcessHeap(), 0, 2 * (wcslen(Name) + 1)); if (NameCopy == NULL) { RtlFreeHeap (RtlProcessHeap(), 0, Entry); return NULL; } wcscpy (NameCopy, Name); } else { NameCopy = NULL; } RtlZeroMemory (Entry, sizeof *Entry); Entry->Handle = Handle; Entry->Type = Type; Entry->Delayed = Delayed ? 1 : 0; Entry->Context = Context; Entry->Name = NameCopy; RtlCaptureStackBackTrace (2, MAX_TRACE_DEPTH, Entry->Trace, &Hash); RtlEnterCriticalSection (&HandleLock); InsertHeadList (&HandleList, &(Entry->Links)); RtlLeaveCriticalSection (&HandleLock); return Entry; } VOID HandleDelete ( HANDLE Handle, PAVRF_HANDLE Entry ) { RtlEnterCriticalSection (&HandleLock); RemoveEntryList (&(Entry->Links)); RtlLeaveCriticalSection (&HandleLock); if (Entry->Name) { RtlFreeHeap (RtlProcessHeap(), 0, Entry->Name); } RtlFreeHeap (RtlProcessHeap(), 0, Entry); } VOID HandleDump ( HANDLE Handle ) { PLIST_ENTRY Current; PAVRF_HANDLE Entry; RtlEnterCriticalSection (&HandleLock); Current = HandleList.Flink; while (Current != &HandleList) { Entry = CONTAINING_RECORD (Current, AVRF_HANDLE, Links); Current = Current->Flink; if (Handle == NULL || Entry->Handle == Handle) { DbgPrint ("HNDL: %08X %04u `%ws' \n", HandleToUlong(Entry->Handle), Entry->Type, HandleName(Entry)); } } RtlLeaveCriticalSection (&HandleLock); } // // Virtual space operations tracking. // typedef struct _VS_CALL { struct { ULONG Type : 4; ULONG Trace : 16; ULONG Thread : 12; }; PVOID Address; SIZE_T Size; ULONG Operation; ULONG Protection; } VS_CALL, *PVS_CALL; #define NO_OF_VS_CALLS 8192 VS_CALL VsCalls [NO_OF_VS_CALLS]; LONG VsCallsIndex; VOID VsLogCall ( VS_CALL_TYPE Type, PVOID Address, SIZE_T Size, ULONG Operation, ULONG Protection ) { ULONG Index; ULONG Hash; Index = (ULONG)InterlockedIncrement (&VsCallsIndex); Index %= NO_OF_VS_CALLS; //RtlZeroMemory (&(VsCalls[Index]), sizeof (VS_CALL)); VsCalls[Index].Address = Address; VsCalls[Index].Type = Type; VsCalls[Index].Trace = RtlLogStackBackTrace(); VsCalls[Index].Thread = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread); VsCalls[Index].Size = Size; VsCalls[Index].Operation = Operation; VsCalls[Index].Protection = Protection; if (AVrfpProvider.VerifierDebug) { DbgPrint ("AVRF:VS: %01u (%04X): %p %p %X %X \n", Type, (ULONG)(VsCalls[Index].Trace), Address, Size, Operation, Protection); } } // // Heap operations tracking // typedef struct _HEAP_CALL { struct { ULONG Reserved : 4; ULONG Trace : 16; ULONG Thread : 12; }; PVOID Address; SIZE_T Size; } HEAP_CALL, *PHEAP_CALL; #define NO_OF_HEAP_CALLS 8192 HEAP_CALL HeapCalls [NO_OF_HEAP_CALLS]; LONG HeapCallsIndex; VOID HeapLogCall ( PVOID Address, SIZE_T Size ) { ULONG Index; ULONG Hash; Index = (ULONG)InterlockedIncrement (&HeapCallsIndex); Index %= NO_OF_HEAP_CALLS; //RtlZeroMemory (&(HeapCalls[Index]), sizeof (HEAP_CALL)); HeapCalls[Index].Address = Address; HeapCalls[Index].Trace = RtlLogStackBackTrace(); HeapCalls[Index].Thread = HandleToUlong(NtCurrentTeb()->ClientId.UniqueThread); HeapCalls[Index].Size = Size; if (AVrfpProvider.VerifierDebug) { DbgPrint ("AVRF:HEAP: %04X (%04X): %p %p \n", (ULONG)(HeapCalls[Index].Thread), (ULONG)(HeapCalls[Index].Trace), Address, Size); } } VOID AVrfpDirtyThreadStack ( ) { PTEB Teb = NtCurrentTeb(); ULONG_PTR StackStart; ULONG_PTR StackEnd; try { StackStart = (ULONG_PTR)(Teb->NtTib.StackLimit); // // ISSUE: SilviuC: we should dirty stacks on all architectures // #if defined(_X86_) _asm mov StackEnd, ESP; #else StackEnd = StackStart; #endif // // Limit stack dirtying to only 8K. // if (StackStart < StackEnd - 0x2000) { StackStart = StackEnd - 0x2000; } if (AVrfpProvider.VerifierDebug) { DbgPrint ("Dirtying stack range %p - %p for thread %p \n", StackStart, StackEnd, Teb->ClientId.UniqueThread); } while (StackStart < StackEnd) { *((PULONG)StackStart) = 0xBAD1BAD1; StackStart += sizeof(ULONG); } } except (EXCEPTION_EXECUTE_HANDLER) { // nothing } } // // Standard function used for hooked CreateThread. // ULONG AVrfpThreadFunctionExceptionFilter ( ULONG ExceptionCode, PVOID ExceptionRecord ) { VERIFIER_STOP (APPLICATION_VERIFIER_UNEXPECTED_EXCEPTION, "unexpected exception raised in thread function", ExceptionCode, "Exception code", ExceptionRecord, "Exception record (.exr on 1st word, .cxr on 2nd word)", 0, "", 0, ""); return EXCEPTION_EXECUTE_HANDLER; } DWORD WINAPI AVrfpStandardThreadFunction ( LPVOID Context ) { PAVRF_THREAD_INFO Info = (PAVRF_THREAD_INFO)Context; DWORD Result; try { // // Call the real thing. // Result = (Info->Function)(Info->Parameter); } except (AVrfpThreadFunctionExceptionFilter (_exception_code(), _exception_info())) { // // Nothing. // } // // Perform all typical checks for a thread that has just finished. // RtlCheckForOrphanedCriticalSections (NtCurrentThread()); AVrfpCheckThreadTermination (); RtlFreeHeap (RtlProcessHeap(), 0, Info); return Result; } VOID AVrfpCheckThreadTermination ( VOID ) { // // Nothing yet. // }