Ищем main без отладочных символов

Table of Contents

Ищем main без отладочных символов

Итак, у нас есть программа, из которой удалены отладочные символы, которые позволяют нам войти в gdb и посмотреть, как все работает. По факту gdb вообще отказывается показывать нам функцию main:

(gdb) disassemble main
Таблица символов не загружена. Используйте меню файл

Что делать в таком случае, если программа слинкована статически с библиотекой libc и не вызывает никаких динамических библиотек. Как найти функцию main?

Будем опираться на точку входа entry point, указанную в заголовке исполняемого файла. Чтобы ее узнать вводим:

readelf -h aaaa
Заголовок ELF:
  Magic:   7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00
  Класс:                             ELF32
  Данные:                            дополнение до 2, little endian
  Версия:                            1 (current)
  OS/ABI:                            UNIX - GNU
  Версия ABI:                        0
  Тип:                               EXEC (Исполняемый файл)
  Машина:                            Intel 80386
  Версия:                            0x1
  Адрес точки входа:               0x804884f
  Начало заголовков программы:          52 (байт в файле)
  Начало заголовков программы:          667872 (байт в файле)
  Флаги:                             0x0
  Размер этого заголовка:            52 (байт)
  Размер заголовков программы:       32 (байт)
  Число заголовков программы:        6
  Размер заголовков раздела:         40 (байт)
  Число заголовков раздела:          27
  Индекс табл. строк загол. раздела: 26

Теперь у нас есть точка входа: 0x804884f. Заходим в GDB и ставим туда breackpoint, а потом запускаем програму. Она остановится в точке входа:

gdb -q aaaa
Reading symbols from aaaa...(no debugging symbols found)...done.
(gdb) break *0x804884f
Breakpoint 1 at 0x804884f
(gdb) r
Starting program: .../aaaa
Breakpoint 1, 0x0804884f in ?? ()

Посмотрим что там:

Breakpoint 1, 0x0804884f in ?? ()
(gdb) x/30i $pc
=> 0x804884f:   xor    %ebp,%ebp
   0x8048851:   pop    %esi
   0x8048852:   mov    %esp,%ecx
   0x8048854:   and    $0xfffffff0,%esp
   0x8048857:   push   %eax
   0x8048858:   push   %esp
   0x8048859:   push   %edx
   0x804885a:   push   $0x80493b0
   0x804885f:   push   $0x8049310
   0x8048864:   push   %ecx
   0x8048865:   push   %esi
   0x8048866:   push   $0x8048884
   0x804886b:   call   0x8048c80
   0x8048870:   hlt
   0x8048871:   xchg   %ax,%ax
   0x8048873:   xchg   %ax,%ax
   0x8048875:   xchg   %ax,%ax
   0x8048877:   xchg   %ax,%ax
   0x8048879:   xchg   %ax,%ax
   0x804887b:   xchg   %ax,%ax
   0x804887d:   xchg   %ax,%ax
   0x804887f:   nop
   0x8048880:   mov    (%esp),%ebx
   0x8048883:   ret

В начале функции, после пролога идет вызов функции __libc_start_main, которая имеет следующую сигнатуру:

int __libc_start_main(int (*main) (int, char**, char**),
                      int argc,
                      char *__unbounded *__unbounded ubp_av,
                      void (*init) (void),
                      void (*fini) (void),
                      void (*rtld_fini) (void),
                      void (*__unbounded stack_end));

Указатель на функцию main, которую мы ищем, передается в первом параметре. Это означает, что последний адрес в памяти, сохраняемый в стеке перед вызовом call __libc_start_main, является адресом в памяти main, так как компилятором языка Си параметры функции помещаются в стек в обратном по отношению к сигнатуре порядке.

Таким образом, мы видим наш искомый адрес здесь, в предпоследней строчке:

0x8048864:   push   %ecx
0x8048865:   push   %esi
0x8048866:   push   $0x8048884
0x804886b:   call   0x8048c80

Установим туда breakpoint, продолжим выполнение, и мы окажемся в функции main:

(gdb) break *0x8048884
Breakpoint 2 at 0x8048884
(gdb) c
Continuing.

Breakpoint 2, 0x08048884 in ?? ()
(gdb) x/30i $pc
=> 0x8048884:   lea    0x4(%esp),%ecx
   0x8048888:   and    $0xfffffff0,%esp
   0x804888b:   pushl  -0x4(%ecx)
   0x804888e:   push   %ebp
   0x804888f:   mov    %esp,%ebp
   0x8048891:   push   %edi
   0x8048892:   push   %esi
   0x8048893:   push   %ebx
   0x8048894:   push   %ecx

Так можно найти функцию main в программе, из которой удалены отладочные символы.

Яндекс.Метрика
Home