Переопределить библиотечную функцию libc open()

У меня есть тот же переопределенный open(), который предоставляется в моей библиотеке glibc, и я сначала установил LD_PRELOAD в свою библиотеку, поэтому, когда процесс вызывает open(), open, который определенная в моей библиотеке.

ПРОБЛЕМА: - В glibc есть несколько других функций, которые вызывают open(), когда такой пример getpt(), когда getpt() вызывает open(), open(), который определен в вызове glibc, как бы я сделал getpt() для вызова open(), который определен в моей библиотеке().

Ограничения: - У меня нет возможности компилировать glibc.

+3
источник поделиться
3 ответа

Как правильно указано tmcguire, вызов от posix_openpt до __open является вызовом внутреннего символа и не может быть вставлен.

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

Я рассматриваю решение времени компиляции

У вас его не может быть.

чем решение времени выполнения, потому что решение времени выполнения будет иметь влияние на производительность.

Решение времени выполнения не должно иметь никакого влияния на производительность (помимо накладных расходов на вызов open вместо glibc s).

Я знаю только один способ для библиотеки вставлять glibc внутренние вызовы: исправление во время выполнения. Идея состоит в том, чтобы

  • найдите адрес libc.so.6 open (который является псевдонимом для __open),
  • найдите границы раздела glibc .text во время выполнения
  • сканировать его для инструкций CALL __open
  • для любой такой инструкции
    • mprotect страница, на которой он будет доступен для записи.
    • вычислить новую команду CALL my_open и исправить ее "сверху" исходной инструкции
    • mprotect страница назад для чтения и выполнения

Это некрасиво, но отлично работает для я * 86 (32-разрядной) Linux, где CALL может "достигать" любую другую команду в адресном пространстве 4 ГБ. Это не работает для x86_64, где CALL по-прежнему ограничено +/- 2 ГБ, но расстояние от вашей библиотеки до glibc может быть больше.

В этом случае вам нужно найти подходящий батут в пределах libc.so.6, к которому вы можете перенаправить исходный CALL, и в который вы можете поместить опознавательный регистр JMP в ваш конечный пункт назначения. К счастью, libc.so.6 обычно имеет несколько незанятых областей NOP подходящего размера из-за выравнивания функций.

+2
источник

Мне удалось решить его во время компиляции, просто определив функцию getpt() в моей библиотеке.

Это решение является неполным, поскольку в glibc (кроме getpt()] могут быть другие функции, которые могли бы вызвать open, тогда будет вызван открытый вызов внутри glibc.

Я могу жить с этим решением на данный момент, но мне нужно будет полностью его исправить в будущем.

+1
источник

Я не думаю, что вы можете сделать это с помощью LD_PRELOAD.

Если вы посмотрите на разборку libc (используя, например, objdump --disassemble /lib64/libc.so.6 | grep -A20 "<getpt>:", вы увидите, что getpt() вызывает __open(), который является псевдонимом open().

000000000011e9d0 <posix_openpt>:
  11e9d0:       53                      push   %rbx
  [...]
  11e9ee:       e8 dd d9 fb ff          callq  dc3d0 <__open>

Однако этот вызов __open - это вызов, относящийся к ПК, который не проходит через PLT - это означает, что вы можете не вставлять символ с LD_PRELOAD, так как все вызовы внутри libc не будут использовать PLT. Вероятно, это связано с тем, что libc был связан с -BSymbolic.

Единственный вариант - сделать то, что делает strace, и использовать ptrace для присоединения к процессу. См. этот вопрос о том, как это работает.

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос