2015-07-11 3 views
2

Я пишу небольшую программу, которая отслеживает все системные вызовы и вызовы двоичного файла (эльфа), используя ptrace (singlelestep, getregs, pick_text, сравнение опкодов и т. Д.).Printf Разрешение символа

До сих пор мне удалось отслеживать системные вызовы и простые вызовы, такие как пользовательские функции.

Но мне не удалось получить имя символа printf из адреса, который я выбираю, благодаря ptrace.

Мой вопрос: Для динамической связанной функции как printf, strlen и т. Д., Как я могу получить в файле эльфа имя символа с адреса?

С простыми вызовами это легко, я прохожу через раздел .strtab и когда адрес совпадает, я возвращаю соответствующую строку.

Но для printf символ известен в .strtab, но имеет адрес «0».

objdump -d каким-то образом удалось связать вызов printf с его адресом.

У вас есть идея?

+0

Включена ли динамическая связь? – fuz

+1

В glibc символ 'printf' на самом деле называется' __printf_chk' из-за фортификационного патча. Запустите 'nm' в объектном файле, который вызывает' printf', и вы увидите. Как правило, посмотрите на libelf как на то, как разбирать файлы эльфа. Я рекомендую вам не разбирать их вручную. – fuz

+0

Я уже использую libelf. И на самом деле, если я использую nm, я могу видеть символ «printf», но не его адрес, а символ помечен буквой «U» для «Undefined». Это моя проблема, я использую адрес функции для извлечения ее имени. Но если адрес не заполнен эльфом, я не могу получить имя. И да, libc динамически связан. Думаю, –

ответ

2

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

Ваша проблема (я думаю), что вы хотите взять адрес символа и перевести его обратно в адрес. Вы пытаетесь это сделать, анализируя ELF-файл программы, которую вы отлаживаете. Это работает с символами, которые находятся в вашей программе, но не с динамически связанными символами, такими как strlen. И вы хотите знать, как это решить.

Причина в том, что адрес символов, таких как strlen, не содержится в вашей программе ELF. Вместо этого они являются нерешенными ссылками, которые динамически разрешаются , когда программа загружает. Действительно, современный Linux (я полагаю) загружает динамические библиотеки (которые содержат перемещаемый или независимый от позиции код) в рандомизированном порядке и рандомизированных адресах, поэтому расположение этих символов будет неизвестно до загрузки программы.

Для библиотек, которые вы открыли с помощью dlopen() (т. Е. Где вы загружаете себя в программу), вы можете получить адрес таких символов, используя dlsym(); это не очень хорошо, если они связаны с программой во время компиляции/ссылки.

На gcc, чтобы разрешить положение символов в общем, используйте расширение gcc dladdr(). Со страницы руководства:

The function dladdr() takes a function pointer and tries to 
    resolve name and file where it is located. Information is 
    stored in the Dl_info structure: 

     typedef struct { 
      const char *dli_fname; /* Pathname of shared object that 
             contains address */ 
      void  *dli_fbase; /* Address at which shared object 
             is loaded */ 
      const char *dli_sname; /* Name of nearest symbol with address 
             lower than addr */ 
      void  *dli_saddr; /* Exact address of symbol named 
             in dli_sname */ 
     } Dl_info; 

    If no symbol matching addr could be found, then dli_sname and 
    dli_saddr are set to NULL. 

    dladdr() returns 0 on error, and nonzero on success. 

Я считаю, что это сработает для вас.

Для получения дополнительной информации, я предлагаю вам посмотреть на source к ltrace, который отслеживает библиотечные вызовы, и как backtrace_symbolshere) работ; обратите внимание, что особенно для неглобальных символов это будет ненадежным, и обратите внимание на комментарий, добавляющий -r dynamic к линии ссылок.

Возможно, вы также захотите посмотреть addr2line и его source.

Смежные вопросы