фрагмент RTL-функции
Вот оно! Перед вызовом обработчика исключения, функция временно сохраняет указатель на текущий SEH-фрейм в стеке (команда PUSH ESI), который на момент вызова обработка будет расположен по смещению +8h. Причем, исправить это средствами операционной системы никак невозможно! Необходимо переписать RTL каждого из компиляторов и перекомпилировать все программы!
Для реализации атаки достаточно заменить handler указателем на последовательность pop reg/pop reg/ret или add esp, 8/ret (которая достаточно часто встречаются в эпилогах функций), а поверх prev как и раньше записать jump на shell-код. Первая команда pop сталкивает с вершины стека уже ненужный адрес возврата, оставленный call, вторая — выбрасывает сохраненный регистр EBP, а ret передает управление на текущий SEH-фрейм.
Теперь структура массива offsets
становится более или менее понятна. Мы видим три подложных SEH-фрейма — по одному для каждой операционной системы, расположенных в памяти с таким расчетом, чтобы они совпадали с текущими SEH-фреймами атакуемой программы. Это самая капризная часть exploit'а, поскольку дислокация фреймов зависит как от версии атакуемой программы (добавление или удаление локальных переменных внутри уязвимой функции изменяет расстояние между фреймом и переполняющимся буфером), так и от начального положения стека на момент запуска программы (за это отвечает операционная система). В дополнении к этому необходимо следить за тем, чтобы handler
действительно указывал на pop reg/pop reg/ret (add esp,8/ret), а не на что-то другое. В противном случае, exploit работать не будет, но если все значения подобранны правильно, управление получит bind_shellcode, который мы сейчас попробуем дизассемблировать, но прежде необходимо перевести ASCII-строку в двоичный вид, чтобы его "проглотил" hiew или IDA PRO.
Вместо того, чтобы писать конвертор с нуля, воспользуемся возможностями компилятора языка Си, написав несложную программу, состоящую фактически всего из одной строки (остальные — объявления):
#include <stdio.h>
char shellcode[]="\xXX\xXX\xXX\xXX"; // сюда помещаем массив для преобразования
main(){FILE *f;if(f=fopen("shellcode","wb"))fwrite(shellcode, sizeof(shellcode),1,f);
}