Как заменить адрес возврата в стеке с помощью атаки переполнения буфера

Для домашнего задания я выполняю серию атак на переполнение буфера. Мне дали программу для дизассемблирования, исходный код на C для функции, которая неправильно вызывает gets(), и исходный код для нескольких других функций, которые я должен заставить программу вызывать. Для одной из задач мне нужно:

  • Введите код, который изменяет значение, затем
  • Вернитесь к одному из вышеупомянутых методов.

Главное, что я не понимаю, куда программа смотрит в стеке при определении, куда возвращаться. Где находится адрес возврата для метода, хранящегося в стеке?

Программа скомпилирована для x86.


person Kevin    schedule 01.11.2012    source источник
comment
Сначала вам нужно понять, что происходит при вызове функции в машинном коде x86. Обратите внимание на инструкции call и ret. Если у вас есть это, вы можете попытаться узнать, что такое стековый фрейм.   -  person David J    schedule 01.11.2012


Ответы (1)


Что тебе нужно знать:

  • EIP - это регистр, указывающий на следующую инструкцию для выполнения.
  • При вызове функции аргументы, а затем EIP (чтобы вызываемая функция знала, куда вернуться) сохраняются в стеке.

  • Когда компилятору было сказано (явно или неявно) использовать указатели кадра, он затем сохраняет указатель кадра (в регистре EBP) в стеке (чтобы позже он мог восстановить указатель кадра до значения, которое он имел в вызывающей функции) , а затем устанавливает указатель фрейма так, чтобы он указывал на текущую вершину стека. Это позволяет легко получить доступ к аргументам и локальным переменным из известной точки отсчета (указателя кадра) и значительно упрощает отладку.

  • Затем пространство зарезервировано для локальных переменных, и функция выполняется.
  • При возврате из функции восстанавливаются указатель предыдущего кадра и указатель инструкции.

Вызов функции на x86 выглядит примерно так:

                                        ...
int main()                              add  $-0x8,%esp ; alignment
{                                       push $0x2       ; arg 2
        ...                             push $0x1       ; arg 1
        func(1, 2);                     call func       ; function call
        ...                             add  $0x10,%esp ; pop args from stack
}                                       ...

И вызываемая функция выглядит примерно так:

void func(int arg1, int arg2)           push %ebp       ;\
{                                       mov  %esp,%ebp  ;/ create stack frame
        int local1;                     sub  $0x18,%esp ; reserves space
        ...                             ...
}                                       mov  %ebp,%esp  ;\
                                        pop  %ebp       ;/ destroys frame
                                        ret             ; returns

Итак, стек будет выглядеть примерно так:

          :           :
          +-----------+
          : alignment :
          +-----------+
12(%ebp)  |   arg2    |
          +-----------+
 8(%ebp)  |   arg1    |
          +-----------+
 4(%ebp)  |    ret    | -----> return address
          +-----------+
  (%ebp)  |    ebp    | -----> previous ebp
          +-----------+
-4(%ebp)  |  local1   | -----> local vars
          +-----------+
          : alignment :
          +-----------+
          :           :

(Нижние адреса ниже в ASCII-арте)

person ninjalj    schedule 01.11.2012