Gdy programy ulegają awarii, system operacyjny udostępnia mechanizm o nazwie Obsługa wyjątków strukturalnych (SEH), aby spróbować odzyskać operacje. Jest to często implementowane w kodzie źródłowym za pomocą bloków try/catch lub try/exception:
System Windows śledzi rekordy SEH, korzystając ze specjalnej struktury:
Struktura EXCEPTION_REGISTRATION ma rozmiar 8 bajtów i zawiera dwa elementy:
- prev Wskaźnik do następnego rekordu SEH
- handler Wskaźnik do rzeczywistego kodu obsługi
Te rekordy (ramki wyjątku) są przechowywane na stosie w czasie wykonywania i tworzą łańcuch. Początek łańcucha jest zawsze umieszczany w pierwszym elemencie bloku informacji o wątku (TIB), który jest przechowywany na maszynach x86 w rejestrze FS:[0]. Jak pokazano na rysunku , końcem łańcucha jest zawsze domyślny systemowy program obsługi wyjątku, a wskaźnik prev tego rekordu EXCEPTION_REGISTRATION jest zawsze równy 0xFFFFFFFF.
Gdy zostanie wyzwolony wyjątek, system operacyjny (ntdll.dll) umieszcza następującą funkcję C++ na stosie i wywołuje ją:
W przeszłości atakujący mógł po prostu nadpisać jeden z programów obsługi wyjątków na stosie i przekierować kontrolę do kodu atakującego (na stosie).
Jednak później pewne rzeczy uległy zmianie:
- Rejestry są zerowane tuż przed wywołaniem programów obsługi wyjątków.
- Wywołania programów obsługi wyjątków, znajdujących się na stosie, są blokowane.
Łańcuch SEH może być interesującym celem, ponieważ często, nawet jeśli nadpisujesz wskaźnik powrotu na stosie, wykonanie nigdy nie osiąga instrukcji powrotu. Jest to zwykle spowodowane naruszeniem dostępu do odczytu lub zapisu, które ma miejsce przed osiągnięciem epilogu funkcji, spowodowane dużą liczbą znaków wysłanych do bufora, które nadpisały krytyczne dane. W takim przypadku dalej w dół stosu za buforem znajduje się lokalizacja łańcucha SEH dla wątku. Naruszenie dostępu do odczytu lub zapisu spowoduje, że FS:[0] zostanie poddane getdereferenced, co zawiera wskaźnik do adresu stosu wątku, gdzie przechowywana jest pierwsza wartość „Next SEH” (NSEH). Rejestr segmentu FS zawsze wskazuje na Thread Information Block (TIB) dla aktualnie aktywnego wątku. TIB to struktura użytkownika na wątek, która przechowuje dane, takie jak wskaźnik do początku łańcucha SEH dla wątku w FS:[0], limity stosu i wskaźnik do Process Environment Block (PEB) w FS:[0x30]. Bezpośrednio pod pozycją NSEH na stosie znajduje się adres pierwszego wywołanego programu obsługi. Nadpisanie tego adresu adresem niestandardowym jest często łatwym sposobem na uzyskanie kontroli, jeśli nie można tego zrobić za pomocą nadpisywania wskaźnika powrotu. SafeSEH ma na celu uniemożliwienie działania tej techniki, ale jak zobaczysz, można ją łatwo ominąć.