LINUX.ORG.RU

Поиск ELF сигнатур через ptrace в памяти форка

 , ,


0

3

Есть такой код:

#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <signal.h>

#define ELF_MAGIC_LE		0x464C457F	/* "\x7FELF" in little endian */

void parent(pid_t);
void child();

int main( int argc, char *argv[])
{
  pid_t pid = fork();
  if (pid)
  {
    parent(pid);
  }
  else
    child();

  return 0;
}

void child()
{
  struct timespec tim = {5,0};
  for(;;) nanosleep(&tim, NULL); //sleep 5 sec
}

void parent(pid_t pid)
{
  size_t i;
  long ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  for (i = 0x0; i+1 < 0xfffff000ULL; i+= 0x1000)
  {
    ret = ptrace(PTRACE_PEEKDATA, pid, (void *)i, NULL);
    if ( ((unsigned long)ret & 0xFFFFFFFF) == ELF_MAGIC_LE) printf ("elf header at 0x%zx\n", i);
  }
  ptrace(PTRACE_DETACH, pid, NULL, NULL);
  kill(pid, SIGKILL);
}
если его собрать для 32-х бит с опцией -m32, он иногда находит, иногда не находит elf header по следующим адресам
elf header at 0x8048000
elf header at 0x8049000
при этом оно всегда находит 3 elf заголовка по примерно таким адресам
elf header at 0xf7602000
elf header at 0xf77d7000
elf header at 0xf77d8000
но в любом случае оно сигфолтится. Вопросы: почему оно не всегда находит первые 2 elf заголовка? Почему сигфолтится? Доступ к какому диапазону адресов через ptrace(PTRACE_PEEKDATA, ... вызывает сигфолт? Что тут можно улучшить?

★★★★★

Последнее исправление: SZT (всего исправлений: 2)

Что тут можно улучшить?

Добавить проверку результата ptrace(), что это не -1.

А почему находит много — наверное, находит ELF_MAGIC_LE, может он у вас в стек попадает. Если у вас каждый раз при запуске программы стек по случайному адресу, то ваша константа, то будет попадать на начало блока 0x1000, то не будет.

mky ★★★★★
()
Ответ на: комментарий от tailgunner

А отчего им там не взяться, если в память процесса эти самые ELF файлы отображаются?

SZT ★★★★★
() автор топика
Ответ на: комментарий от mky

Добавить проверку результата ptrace(), что это не -1.

Если речь идет о проверке результата ptrace(PTRACE_PEEKDATA, ... то в этом нет смысла, учитывая что я сравниваю с 0x464C457F который не равен -1.

SZT ★★★★★
() автор топика

Вот кстати такой код:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <inttypes.h>
#include <fcntl.h>

#define ELF_MAGIC_LE		0x464C457F	/* "\x7FELF" in little endian */

int main( int argc, char *argv[])
{
  int devnull = open("/dev/random", O_WRONLY);
  size_t i;

  for (i = 0x0; i+1 < 0xfffff000ULL; i+= 0x1000)
  {
    if (write(devnull, (void *)i, 4) == 4)
    {
      if( *(uint32_t *)i == ELF_MAGIC_LE )
      {
        printf ("elf header at 0x%zx\n", i);
      }
    }
  }
  return 0;
}
сигфолта почему-то не вызывает. И работает надежнее

SZT ★★★★★
() автор топика
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Ну, первая сигнатура это собственно сам исполняемый файл (кусок исполняемого файла с кодом и ELF заголовком, ибо разрешено на исполнение)

elf header at 0x8048000 -> 08048000-08049000 r-xp 00000000 08:03 34998302 /home/user/a.out

Вторая это ro data segment

elf header at 0x8049000 -> 08049000-0804a000 r--p 00000000 08:03 34998302 /home/user/a.out

А остальные это либы и еще какой-то vdso

elf header at 0xf75ab000 -> f75ab000-f7753000 r-xp 00000000 08:02 558361                             /lib/i386-linux-gnu/libc-2.19.so
elf header at 0xf7780000 -> f7780000-f7781000 r-xp 00000000 00:00 0                                  [vdso]
elf header at 0xf7781000 -> f7781000-f77a1000 r-xp 00000000 08:02 558363                             /lib/i386-linux-gnu/ld-2.19.so
Это я сопоставил адреса найденных ELF сигнатур с /proc/self/maps

SZT ★★★★★
() автор топика
Последнее исправление: SZT (всего исправлений: 2)
Ответ на: комментарий от mky

Ну сначала там действительно /dev/null был, но он почему-то не работал(кстати, почему?). А с /dev/random работает. Переменную переименовать забыл только.

p.s. у меня сегфолт не воспроизводится.

У меня он стабильно воспроизводится, если компилировать под 32 бита опцией -m32 и запускать в 64-битном окружении. ОС Ubuntu 14.04.3 LTS. Речь идет о коде из топика, если что

SZT ★★★★★
() автор топика
Ответ на: комментарий от SZT

dev/null был, но он почему-то не работал(кстати, почему?

Видимо, в ядре обработка записи в /dev/null не смотрит откуда данные, всегда возвращается указанный размер буфера, ошибок не бывает.

У меня под CentOS 5 на x64 с опцией -m32 нет сегфолта кода из топика.

mky ★★★★★
()
Ответ на: комментарий от SZT

Куски файлов с ELF заголовком там точно есть, можешь проверить

Заголовки ELF наверняка есть, потому что динамический загрузчик читает их по мере отображения содержимого ELF-файла в память. Но сигнатуры (ELF_MAGIC), если и есть, лежат в сегментах данных.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Но по-факту такие сигнатуры лежат в начале исполняемых сегментов. Можешь даже дампнуть те области памяти и убедиться, что там лежит кусок ELF файла с исполняемым кодом

SZT ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.