Click here to Skip to main content
6,306,412 members and growing! (23,548 online)
Email Password   helpLost your password?
General Reading » Hardware & System » General     Advanced License: The Code Project Open License (CPOL)

Vectored Exception Handling in Windows XP SP2

By zhzhtst

This article updates Matt Pietrek's Vectored Exception Handling article in MSDN Magazine.
C, VC7.1WinXPVS.NET2003, Dev
Posted:1 Sep 2007
Views:9,173
Bookmarked:6 times
Unedited contribution
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
2 votes for this article.
Popularity: 0.30 Rating: 1.00 out of 5
2 votes, 100.0%
1

2

3

4

5

Introduction

In September 2001 Under The Hood column in MSDN Magazine, Matt Pietrek covered a new feature introduced in Windows XP - Vectored Exception Handling (VEH). Matt explained in detail the VEH and gave us a useful example. When I examine this issue in Windows XP SP2, the most popular OS currently, I found some problems.

First, the demo program crashed when I run it. As following:

Screenshot - crash.jpg

According to the "Application Error" dialog, we know the error is a single step exception. I examined the source carefully, but couldn't find any problems. When I attach Visual Studio .NET 2003 debugger to the crashed program, I found the error address is the second instruction of LoadLibraryExW function. Why is the single step flag still here? Didn't we have it removed? Finally, I have found the reason. In previous Windows Operation System, almost all system functions have standard stack frame. The first instruction of these function is "PUSH EBP" and its opcode is 55h, that is 1 byte. But in Windows XP SP2, the standard prolog code for SEH stack frame of the system function have been replaced with _SEH_prolog function. I have found that the first instruction of these function push the count of memory that local variables of these function take into stack. For LoadLibraryExW, it's "PUSH 34h" and its opcode is 6Ah 34h, that is 2 bytes. In the demo program, if the single step flag want to be removed, it must satisfies two conditions: first, the exception code must be STATUS_SINGLE_STEP; second, the exception address must be the next address of LoadLibraryExW's address. But it's impossible in Windows XP SP2, because the first instruction of LoadLibraryExW is 2 bytes. If we replace 1 in souce with 2, we can solve this problem.

Second, in that article, Matt said that Vectored Exception Hanlding linked list is "Circular Linked List", but I have found it is "Doubly Linked List". Moreover, the RtlpCalloutEntryList global variable is the head of this linked list. This global variable is a LIST_ENTRY structure (8 bytes), not a VECTORED_EXCEPTION_NODE pointer. How did I find this? When I use SoftICE to see its value, I found the following:

Screenshot - gv.jpg

Obviously, the variable takes 8 bytes. When you think of the style that Windows processes the linked list, you will get it.

As is well known, Windows XP SP2 enhanced the security of the system. Many global available pointers are encoded so that it is difficult to use these pointers to exploit. Exception handling is the first to be affected. Windows XP SP2 supplies a common way to do this. It is EncodePointer API. In fact, this API is forwarded to RtlEncodePointer in NTDLL.DLL. Of course, there is DecodePointer and it's forwarded to RtlDecodePointer in NTDLL.DLL.

According to Matt's pseudocode, I have written the pseudocode for these API.

VEH.H file:

typedef struct _VECTORED_EXCEPTION_NODE {
    LIST_ENTRY ListEntry;
    PVECTORED_EXCEPTION_HANDLER    pfnHandler;    // for security, this pointer has been encoded

} VECTORED_EXCEPTION_NODE, *PVECTORED_EXCEPTION_NODE;

// The following two global variables are initialized by Windows loader

// (In fact, it's LdrpInitializeProcess routine)


// this variable is response to protect insert and delete operation from

// linked list, Windows loader call RtlInitializeCriticalSection to init it

RTL_CRITICAL_SECTION RtlpCalloutEntryLock;

// this variable is the head of the Vectored Exception Handling linked list

// Windows loader call InitializeListHead to init it

// please refer to the section "Singly- and Doubly-Linked Lists" in DDK documents

LIST_ENTRY RtlpCalloutEntryList;

VEH.C file:

#include <ntddk.h>

#include "veh.h"


// the prototype comes from winbase.h in Windows Server 2003 R2 SDK

PVOID WINAPI RtlAddVectoredExceptionHandler(
            ULONG First,
            PVECTORED_EXCEPTION_HANDLER Handler)
{
    PVECTORED_EXCEPTION_NODE pCurrentNode = (PVECTORED_EXCEPTION_NODE)
        RtlAllocateHeap( GetProcessHeap(), 0, sizeof(VECTORED_EXCEPTION_NODE) );

    if (!pCurrentNode)
    {
        return 0;
    }

    pCurrentNode->pfnHandler = RtlEncodePointer(Handler);    // encode for security


    RtlEnterCriticalSection(&RtlpCalloutEntryLock);

    if (First)
    {
        InsertHeadList(&RtlpCalloutEntryList, &pCurrentNode->ListEntry);
    }
    else
    {
        InsertTailList(&RtlpCalloutEntryList, &pCurrentNode->ListEntry);
    }

    RtlLeaveCriticalSection(&RtlpCalloutEntryLock);

    return pCurrentNode;
}


// SDK document says Handler is PVOID, but according to the return value of

// AddVectoredExceptionHandler API, it is PVECTORED_EXCEPTION_NODE actually.

ULONG WINAPI RemoveVectoredExceptionHandler(PVOID Handler)
{
    PVECTORED_EXCEPTION_NODE pCurrentNode, pRemovedNode;
    BOOL bHandlerExist = FALSE;

    RtlEnterCriticalSection(&RtlpCalloutEntryLock);

    for ((PLIST_ENTRY)pCurrentNode  = RtlpCalloutEntryList.Flink;
         (PLIST_ENTRY)pCurrentNode != &RtlpCalloutEntryList;
         (PLIST_ENTRY)pCurrentNode  = pCurrentNode->ListEntry.Flink)
    {
        if (pCurrentNode == (PVECTORED_EXCEPTION_NODE)Handler)
        {
            pRemovedNode = pCurrentNode;
            RemoveEntryList(&pCurrentNode->ListEntry);

            bHandlerExist = TRUE;
            break;
        }
    }

    RtlLeaveCriticalSection(&RtlpCalloutEntryLock);

    if (bHandlerExist)
    {
        RtlFreeHeap(GetProcessHeap(), 0, (LPVOID)pRemovedNode);

        return 1;
    }

    return 0;
}


int WINAPI RtlCallVectoredExceptionHanlers(
                PEXCEPTION_RECORD pExcptRec,
                PCONTEXT pContext)
{
    EXCEPTION_POINTERS ExceptionPointers;

    // Is the list empty ?

    if (RtlpCalloutEntryList.Flink == &RtlpCalloutEntryList)
    {
        return 0;
    }
    else
    {
        PVECTORED_EXCEPTION_NODE pCurrentNode;
        BYTE retValue = 0;

        ExceptionPointers.ExceptionRecord = pExcptRec;
        ExceptionPointers.ContextRecord   = pContext;

        RtlEnterCriticalSection(&RtlpCalloutEntryLock);

        for ((PLIST_ENTRY)pCurrentNode  = RtlpCalloutEntryList.Flink;
             (PLIST_ENTRY)pCurrentNode != &RtlpCalloutEntryList;
             (PLIST_ENTRY)pCurrentNode  = pCurrentNode->ListEntry.Flink)
        {
            LONG disposition = ((PVECTORED_EXCEPTION_HANDLER)(RtlDecodePointer(pCurrentNode->pfnHandler)))(&ExceptionPointers);
            if (disposition == EXCEPTION_CONTINUE_EXECUTION)
            {
                retValue = 1;
                break;
            }
        }

        RtlLeaveCriticalSection(&RtlpCalloutEntryLock);

        return retValue;
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

zhzhtst


Member
zhzhtst is a college student in China. He is interested in reverse engineering and virus analysis.
Occupation: Researcher
Location: China China

Other popular Hardware & System articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 1 of 1 (Total in Forum: 1) (Refresh)FirstPrevNext
Generalthat's good PinmemberBUGHOHO8:57 1 Sep '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 1 Sep 2007
Editor:
Copyright 2007 by zhzhtst
Everything else Copyright © CodeProject, 1999-2009
Web12 | Advertise on the Code Project