последовательность вызова функций при обработке исключения
В Windows 2000 функция NTDLL.DLL!RtlUnwind
оставляет немного "мусора" в регистрах, в результате чего в EBX попадет адрес текущего SEH-фрейма. А это значит, что для достижения задуманной цели мы должны поверх handler'а поместить указатель на команду JMP EBX (FFh E3h) или CALL EBX (FFh D3h), которую можно найти как в самой атакуемой программы, так и в памяти операционной системы (естественно, адрес будет "плавать" от версии к версии, что есть неизбежное зло, но с этим надо смириться). Тогда при возникновении исключения управление будет передано на двойное слово, содержащее указатель prev. Да-да! Не по указателю prev, а именно на сам указатель, который следует заменить на JMP SHORT sell?code. Поскольку, команды перехода в x86-процессорах относительные, знать точное расположение shell-кода в памяти уже необязательно.
В Windows XP эта лазейка была прикрыта, но! Осталась функция-фильтр __except_handler3, входящая в состав RTL компилятора, а потому никак не зависящая от операционной системы. Рассмотрим окрестности дизассемблерного кода, передающего управление на зарегистрированный программистом обработчик.
.text:004012D1 mov esi, [ebx+0Ch] ; указатель на текущий SEH-фрейм
.text:004012D4 mov edi, [ebx+8]
.text:004012D7
.text:004012D7 unknwn_libname_2: ; CODE XREF: unknwn_libname_1+90vj
.text:004012D cmp esi, 0FFFFFFFFh ; обработчиков больше нет?
.text:004012DA jz short unknwn_libname_5 ; если да, завершаем программу
.text:004012DC lea ecx, [esi+esi*2]
.text:004012DF cmp dword ptr [edi+ecx*4+4], 0
.text:004012E4 jz short unknwn_libname_3 ; Microsoft VisualC 2-7/net
.text:004012E6 push esi ; сохраняем указатель на фрейм
.text:004012E7 push ebp ; сохраняем указатель на кадр
.text:004012E8 lea ebp, [ebx+10h]
.text:004012EB call dword ptr [edi+ecx*4+4]; вызываем обработчик исключения
.text:004012EF pop ebp ; восстанавливаем кадр
.text:004012F0 pop esi ; восстанавливаем фрейм