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


Идентификация аргументов функций - часть 11


Попутно отметим один из недостатков стека – как и любой другой гомогенный массив, стек может хранить данные лишь одного типа, например, двойные слова. Если же требуется занести один байт (скажем, аргумент типа char), то приходится расширять его до двойного слова и заносить его целиком. Аналогично, если аргумент занимает четыре слова (double, int64) на его передачу расходуется два стековых элемента!

Помимо передачи аргументов стек используется и для сохранения адреса возврата из функции, что требует в зависимости от типа вызова функции (ближнего или дальнего) от одного до двух элементов. Ближний (near) вызов действует в рамках одного сегмента, - в этом случае достаточно сохранить лишь смещение команды, следующей за инструкций CALL. Если же вызывающая функция находится в одном сегменте, а вызываемая в другом, то помимо смещения приходится запоминать и сам сегмент, чтобы знать в какое место вернуться. Поскольку адрес возврата заносится после аргументов, то относительно вершины стека аргументы оказываются "за" ним и их смещение варьируется в зависимости от того: один элемент занимает адрес возврата или два. К счастью, плоская модель памяти Windows NT\9x позволяет забыть о моделях памяти как о страшном сне и всюду использовать только ближние вызовы.

Не оптимизирующие компиляторы используют для адресации аргументов специальный регистр (как правило, EBP), копируя в него значение регистра-указателя вершины стека в самом начале функции. Поскольку стек растет снизу вверх, т.е. от старших адресов к младшим, смещение всех аргументов (включая адрес возврата) положительны, а смещение N-ого по счету аргумента вычисляется по следующей формуле:

 

arg_offset = N*size_element+size_return_address

где N

– номер аргумента, считая от вершины стека, начиная с нуля, size_element – размер одного элемента стека, в общем случае равный разрядности сегмента (под Windows NT\9x – четыре байта), size_return_address – размер в байтах, занимаемый адресом возврата (под Windows NT\9x – обычно четыре байта).




- Начало -  - Назад -  - Вперед -