The exception handlers are organized in a singly-linked list associated with each thread. As a rule, the nodes of that list are allocated on the stack.
The head of the list is pointed to by a pointer located at the beginning of the TEB (Thread Environment Block), so when the code wants to add a new exception handler, a new node is added to the head of the list and the pointer in the TEB is changed to point to the new node.
Each node is of type _EXCEPTION_REGISTRATION_RECORD and stores the address of the handler and a pointer to the next node of the list. Oddly enough, the “next pointer” of the last node of the list is not null but equal to 0xffffffff. Here’s the exact definition:

0:000> dt _EXCEPTION_REGISTRATION_RECORD
ntdll!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : Ptr32     _EXCEPTION_DISPOSITION

The TEB can also be accessed through the selector fs, starting from fs:[0], so it’s common to see code like the following:

Compilers usually register a single global handler that knows which area of the program is being executed (relying on a global variable) and behaves accordingly when it’s called.
Since each thread has a different TEB, the operating system makes sure that the segment selected by fs refers always to the right TEB (i.e. the one of the current thread). To get the address of the TEB, read fs:[18h] which corresponds to the field Self of the TEB.

Let’s display the TEB:

0:000> !teb
TEB at 7efdd000
    ExceptionList:        003ef804          <-----------------------
    StackBase:            003f0000
    StackLimit:           003ed000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7efdd000
    EnvironmentPointer:   00000000
    ClientId:             00001644 . 00000914
    RpcHandle:            00000000
    Tls Storage:          7efdd02c
    PEB Address:          7efde000
    LastErrorValue:       2
    LastStatusValue:      c0000034
    Count Owned Locks:    0
    HardErrorMode:        0

Now let’s verify that fs refers to the TEB:

0:000> dg fs
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0053 7efdd000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3

As we said above, fs:18h contains the address of the TEB:

0:000> ? poi(fs:[18])
Evaluate expression: 2130563072 = 7efdd000

Remember that poi dereferences a pointer and ‘?‘ is used to evaluate an expression.

Let’s see what’s the name of the structure pointed to by ExceptionList above:

0:000> dt nt!_NT_TIB ExceptionList
ntdll!_NT_TIB
   +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD

This means that each node is an instance of _EXCEPTION_REGISTRATION_RECORD, as we already said.
To display the entire list, use !slist:

0:000> !slist $teb _EXCEPTION_REGISTRATION_RECORD
SLIST HEADER:
   +0x000 Alignment          : 3f0000003ef804
   +0x000 Next               : 3ef804
   +0x004 Depth              : 0
   +0x006 Sequence           : 3f

SLIST CONTENTS:
003ef804
   +0x000 Next             : 0x003ef850 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x6d5da0d5     _EXCEPTION_DISPOSITION  MSVCR120!_except_handler4+0
003ef850
   +0x000 Next             : 0x003ef89c _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x00271709     _EXCEPTION_DISPOSITION  +0
003ef89c
   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x77e21985     _EXCEPTION_DISPOSITION  ntdll!_except_handler4+0
ffffffff
   +0x000 Next             : ???? 
   +0x004 Handler          : ???? 
Can't read memory at ffffffff, error 0

Remember that $teb is the address of the TEB.

A simpler way to display the exception handler chain is to use

0:000> !exchain
003ef804: MSVCR120!_except_handler4+0 (6d5da0d5)
  CRT scope  0, func:   MSVCR120!doexit+116 (6d613b3b)
003ef850: exploitme3+1709 (00271709)
003ef89c: ntdll!_except_handler4+0 (77e21985)
  CRT scope  0, filter: ntdll!__RtlUserThreadStart+2e (77e21c78)
                func:   ntdll!__RtlUserThreadStart+63 (77e238cb)

We can also examine the exception handler chain manually:

0:000> dt 003ef804 _EXCEPTION_REGISTRATION_RECORD
MSVCR120!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0x003ef850 _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x6d5da0d5     _EXCEPTION_DISPOSITION  MSVCR120!_except_handler4+0
0:000> dt 0x003ef850 _EXCEPTION_REGISTRATION_RECORD
MSVCR120!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0x003ef89c _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x00271709     _EXCEPTION_DISPOSITION  +0
0:000> dt 0x003ef89c _EXCEPTION_REGISTRATION_RECORD
MSVCR120!_EXCEPTION_REGISTRATION_RECORD
   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
   +0x004 Handler          : 0x77e21985     _EXCEPTION_DISPOSITION  ntdll!_except_handler4+0
The following two tabs change content below.

Massimiliano Tomassoli

Computer scientist, software developer, reverse engineer and student of computer security (+ piano player & music composer)

Latest posts by Massimiliano Tomassoli (see all)

Leave a Reply

Be the First to Comment!

Notify of

wpDiscuz