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




Идентификация функций - часть 2


А замыкает функцию инструкция RET

(но, внимание: не всякий RET обозначает конец функции! подробнее об этом см. "Идентификация значения, возращенного функцией").

Таким образом, распознать функцию можно двояко: по перекрестным ссылкам, ведущим к машинной инструкции CALL и по ее эпилогу, завершающемуся инструкцией RET. Перекрестные ссылки и эпилог в совокупности позволяют определить адреса начала и конца функции. Немного забегая вперед (см. "Идентификация локальных стековых переменных") заметим, что в начале многих функций присутствует характерная последовательность команд, называемая эпилогом, которая так же пригодна для идентификации функций. А теперь расскажем обо всем этом поподробнее.

::Перекрестные ссылки. Просматривая дизассемблерный код, находим все инструкции CALL – содержимое их операнда и будет искомым адресом начала функции. Адрес не виртуальных функций, вызываемых по имени, вычисляется еще на стадии компиляции и операнд инструкции CALL

в таких случаях представляет собой непосредственное значение. Благодаря этому адрес начала функции выявляется простым синтаксическим анализом: ищем контекстным поиском все подстроки "CALL" и запоминаем (записываемым) непосредственные операнды.

Рассмотрим следующий пример:

func();

main(){

int a;

func();

a=0x666;

func();

}

func(){

int a;

a++;

}

Листинг 6 Пример, демонстрирующий непосредственный вызов функции

Результат его компиляции должен выглядеть приблизительно так:

.text:00401000      push   ebp

.text:00401001      mov    ebp, esp

.text:00401003      push   ecx

.text:00401004      call   401019

.text:00401004 ; Вот мы выловили инструкцию call c

непосредственным операндом,

.text:00401004 ; представляющим собой адрес начала функции. Точнее - ее смещение

.text:00401004 ; в кодовом сегменте (в данном случае в сегменте ".text")

.text:00401004 ; Теперь можно перейти к строке ".text:00401019" и, дав функции




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