Как создать обратную трассировку, глядя на значения стека? - PullRequest
1 голос
/ 28 мая 2011

Тест: как сгенерировать обратную трассировку, посмотрев на значения стека?

0xf3e2de34 f3e2de70 c0135351 401ef021 00000000   p.bsQS...p......
0xf3e2de44 f3e2de81 00000021 f3e2c000 f7950924   ..bs......bs...w
0xf3e2de54 00000000 401ef000 00000246 00000246   .....p..F...F...
0xf3e2de64 00000001 00000001 f7950000 f3e2df18   ...........w..bs
0xf3e2de74 c02898b5 322d7875 23203235 00007820   5...ux.252...x..
0xf3e2de84 f3e2de98 00000000 f7950bd0 bffff0ec   ..bs....P..wlp..
0xf3e2de94 c70cf660 00000000 00000000 bffff0ec   .v.G........lp..
0xf3e2dea4 f3e2c000 f7950930 7fffffff 00000000   ..bs0..w........
0xf3e2deb4 00000000 00000001 00000000 bffff07b   .............p..
0xf3e2dec4 f5cfd880 bffff07b 00000000 f5f24740   .XOu.p.......Gru
0xf3e2ded4 c0124f87 00000000 00000000 00200200   .O..............
0xf3e2dee4 f3e2defc 067b3067 00000000 f5f24740   ..bsg0.......Gru
0xf3e2def4 c0124f87 f7950934 f7950934 c028331b   .O..4..w4..w.3..
0xf3e2df04 00000000 c01b0fe8 f5cfd880 f7950000   ....h....XOu...w
0xf3e2df14 fffffffb f3e2df50 c0283642 00000001   ....P.bsB6......
0xf3e2df24 00000001 00000001 f3e2c000 f6fe30d0   ..........bsP0.v

Подсказка - текущую функцию всегда можно определить по EIP

Я нашел этот вопрос в kernelnewbies / ABI документация.
Я действительно не понимаю подсказку, данную там? (Возможно, потому что я понятия не имею об этой вещи).

Может ли кто-нибудь объяснить мне, как решить подобные вопросы.

Ответы [ 2 ]

4 голосов
/ 28 мая 2011

В этом случае вы можете сделать это достаточно надежно, так как этот код был скомпилирован с включенными указателями кадров.

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

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

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

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

Таким образом, чтобы создать обратную трассировку, вы должны следовать указателям кадра, просматривая соответствующие сохраненные EIPS,Итак:

current function was called from c0135351
follow f3e2de70 → was called from c02898b5
follow f3e2df18 → was called from c0283642

Конечно, это был легкий случай.Если у вас нет указателей фреймов, вам нужно угадать, соответствует ли данное значение в стеке указателю инструкций.

Недостающая часть - как перевести эти числа в имена функций.Наличие незарезанного vmlinux (обратите внимание на x, а не z) файла неоценимо.System.map содержит только некоторые символы, поэтому очень часто вы узнаете, что соответствующая функция была между функцией A и функцией B.

Edit:

Вызов функции на 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-art)

Таким образом, если вы будете следовать сохраненным указателям EBP, вы можете получить сохраненные EIP указатели (ret выше), которыеуказывать на инструкции в цепочке вызовов (если быть точным, в цепочке возврата).

0 голосов
/ 28 мая 2011

EIP - это указатель инструкций, я думаю, он содержит адрес выполняемой в данный момент инструкции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...