Фундаментальные основы хакерства



         

Идентификация локальных стековых переменных - часть 3


Детали технической реализации. Существует множество вариаций реализации выделения и освобождения памяти под локальные переменные. Казалось бы, чем плохо очевидное SUB ESP,xxx на входе и ADD ESP, xxx

на выходе? А вот Borland C++ (и некоторые другие компиляторы) в стремлении отличиться ото всех остальных резервируют память не уменьшением, а увеличением ESP… да, на отрицательное число (которое по умолчанию большинством дизассемблеров отображается как очень большое положительное). Оптимизирующие компиляторы при отводе небольшого количества памяти заменяют SUB

на PUSH reg, что на несколько байт короче. Последнее создает очевидные проблемы идентификации – попробуй, разберись, то ли перед нами сохранение регистров в стеке, то ли передача аргументов, то ли резервирование памяти для локальных переменных (подробнее см. "идентификация механизма выделения памяти").

Алгоритм освобождения памяти так же неоднозначен. Помимо увеличения регистра указателя вершины стека инструкцией ADD ESP, xxx

(или в особо извращенных компиляторах его увеличения на отрицательное число), часто встречается конструкция "MOV ESP, EBP". (Мы ведь помним, что при открытии кадра стека ESP копировался в EBP, а сам EBP в процессе исполнения функции не изменялся). Наконец, память может быть освобождена инструкцией POP, выталкивающей локальные переменные одну за другой в какой ни будь ненужный регистр (понятное дело, такой способ оправдывает себя лишь на небольшом количестве локальных переменных).

Действие

Варианты реализации

Резервирование памяти

SUB ESP, xxx

ADD ESP,–xxx

PUSH reg

Освобождение памяти

ADD ESP, xxx

SUB ESP,–xxx

POP reg

MOV ESP, EBP

Таблица 14 Наиболее распространенные варианты реализации резервирования памяти под локальные переменные и ее освобождение

Идентификация механизма выделения памяти. Выделение памяти инструкциями SUB и ADD

непротиворечиво и всегда интерпретируется однозначно. Если же выделение памяти осуществляется командой PUSH, а освобождение – POP, эта конструкция становится неотличима от простого освобождения/сохранения регистров в стеке.


Содержание  Назад  Вперед