2013-05-13 7 views
1

У меня есть расширение ядра области видимости файла, которое сообщает о демонах при запуске приложения. Демон должен приостанавливать запущенное приложение в начале его первой команды в main().Поиск начала основной функции с помощью ptrace

При вызове ptrace с помощью PT_ATTACH демон появляется слишком рано и находится в динамическом компоновке (dyld).

Вот пример стека вызовов резьбы 0 при прикреплении: -

Thread 0: 
0 dyld       0x00007fff6e4cd35e mach_reply_port + 10 
1 dyld       0x00007fff6e4cd4d4 _mig_init + 13 
2 dyld       0x00007fff6e4cd17f mach_init + 46 
3 dyld       0x00007fff6e4aa239 dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 411 
4 dyld       0x00007fff6e4aa05e _dyld_start + 54 

Поэтому, есть ли способ, чтобы либо обеспечить демон может привязывать к началу основной функции после загрузки библиотек закончили , или многократно на один шаг к этой точке, и в этом случае, как мне удастся найти адрес main, учитывая, что для запущенного приложения не может быть символов?

Спасибо.

ответ

-1

Главное не является точкой входа, а скорее именем, которое отображается на символ _start исполняемого элемента сборки. В зависимости от вашего исполняемого типа (elf-32 или что-то еще), он запускается с разных адресов (это может быть рандомизировано). Вы можете использовать GDB, чтобы найти адрес точки входа (или первую выполненную команду), выполнив одну из своих программ один раз (используя gdb, then si), а затем распечатайте значение регистра ПК (используя регистрационные регистры или что-то еще).

Вы также можете переключиться на макет сборки в gdb и увидеть всю трассировку стека и посмотреть, где она начинается. Исполняемый код обычно начинается как 0x0800xxxx

+1

Спасибо, но я думаю, что вам не хватает моей точки. Это демон, который я пишу, который должен остановить любое запущенное приложение. Я не могу использовать GDB, а main - возможная точка входа, но мне просто нужно убедиться, что загрузка всех библиотек завершена, и никаких других инструкций не выполняется. Я полностью понимаю, что точка входа будет отличаться по своему адресу, кроме ASLR, каждое приложение будет иметь различный объем памяти. – TheDarkKnight

+0

Если вы ptracing, просто остановите ptrace при каждом системном вызове. Либо это, либо ваша трассированная программа вызовет ptrace_signal, чтобы остановить выполнение там, и пусть ваш демон знает его там. это будет после основной точки входа, и оптимизация может привести к возникновению других вещей между основным() и сигналом. – Magn3s1um

+0

Как выполнить трассировку программы для вызова функции ptrace_signal, чтобы остановить выполнение? Трассируемая программа - любое возможное приложение на компьютере, которое может запускать пользователь, а не тот, который я написал? Извините, я вас не понимаю? – TheDarkKnight

0

только предположение, но так как Libc будет звонить exit после main, вероятно, можно определить вызов main пешком _start, пока не найдете вызов секции .text, за которым следует позвоните в раздел .plt. Вы также знаете, статус выхода main является параметром exit, так что вы ищете mov %eax, %edi, и, вероятно, main приходит после _start и .plt до .text, и вы знаете, как не зайти слишком далеко, так что вы можете сделать это довольно общий.

Учитывая, что runtime/libc/compiler является нормальным (Mac OS X основан на FreeBSD, правильно?), Вы, вероятно, можете уйти с совпадением всего нескольких байтов, с чем-то вроде этого (вы, вероятно, должны добавить некоторую безопасность в минимум):

size_t *find_main_vmoffset(char *text_start, size_t text_size) 
{ 
    char *p = text_start; 

    const char sig[] = { 
     /* 0xe8, ??, ??, */ 0, 0,  /* callq main */ 
     0x89, 0xc7,    /* mov %eax, %edi */ 
     0xe8, /* ??, ??, 0xff, 0xff, */  /* callq exit */ 
    }; 

    while (p = memmem(p, text_size - (p - text_start), sig, sizeof(sig))) { 
     /* Check it's one call followed by another */ 
     if (p[-3] != 0xe8) 
      continue; 
     /* Check the second call is backwards (into .plt) */ 
     if (p[7] != 0xff || p[8] != 0xff) 
      continue; 

     /* Eureka! */ 
     return (p - text_start) + 2 + *(int32_t *)(p - 2); 
    } 
    return 0; 
} 

Вам просто нужно добавить виртуальный адрес .text к этому, и вы в основном делается :).

+0

Я заметил, что некоторые реализации libc используют обертки (например, glibc), поэтому в этом случае это немного сложнее, но тем не менее оно должно быть идентифицировано аналогичным образом. –