Почему LD_PRELOAD работает с системными вызовами? ​

Идея LD_PRELOAD состоит в том, чтобы загрузить общую библиотеку перед исходной общей библиотекой, например, я могу скомпилировать mylib.so, чтобы загрузить ее перед libc.so, поэтому, когда процесс хочет использовать printf, он ищет в so, которые загружаются один за другим, и находит их в mylib.so (потому что этот so был загружен первым) вместо libc.so, поэтому он использует printf в mylib.so вместо printf в libc.so.

Я понимаю, почему это работает с функциями, реализованными в so, например printf в libc.so.

Но когда я хочу подключить функцию write или другую функцию syscall, почему это работает? Процесс не ищет функцию в so, он обращается непосредственно к ядру.

  1. Работает ли LD_PRELOAD с двоичным файлом, который скомпилирован статически? Почему? В этом воспроизведении https://stackoverflow.com/a/13866611 упоминается, что LD PRELOAD не работает со статически бинарными

  2. Почему LD_PRELOAD работает с динамически скомпилированным двоичным файлом, чтобы перехватывать системные вызовы?

Архитектура ARM.


person yfr24493AzzrggAcom    schedule 28.02.2020    source источник
comment
Когда вы кодируете вызовы write, это не является прямым вызовом системного вызова. Он вызывает оболочку, которая устанавливает системный вызов, а затем перехватывает ядро. Таким образом, LD_PRELOAD может работать, переопределяя вызов оболочки.   -  person kaylum    schedule 28.02.2020
comment
@kaylum вы уверены, что пишете, что это системный вызов, который не завернут, я вижу это в сборке. Значит, LD_PLELOAD тоже должен работать со статически двоичными файлами ??   -  person yfr24493AzzrggAcom    schedule 28.02.2020
comment
Существует системный вызов, называемый записью, но это не то, что вы вызываете напрямую. в libc есть обертки системных вызовов. Предварительная загрузка работает только с динамически связанными исполняемыми файлами.   -  person kaylum    schedule 28.02.2020
comment
Я скорректировал формулировку вашего вопроса, чтобы сделать его более ясным, дайте мне знать, если это нормально.   -  person Marco Bonelli    schedule 28.02.2020
comment
Краткий ответ: вас обманули. Хорошо, это немного резко, но различие между системными вызовами и библиотечными функциями искусственное и не совсем точное. На самом деле все они являются библиотечными функциями, и то, что называется системными вызовами, больше не соответствует непосредственно реальным системным вызовам — фактические системные вызовы изменились. open(), например, скорее всего, выполняет системный вызов openat().   -  person Andrew Henle    schedule 28.02.2020
comment
Эта функция Q/A on thumb start имеет пользовательскую функцию для определения системных вызовов и т. д. в вашем коде. Вы также можете статически связать некоторые библиотеки и сделать другие динамическими, используя частичное связывание. А также статическая библиотека и кросс-компиляция имеют write() реализацию и соответствующую тему.   -  person artless noise    schedule 28.02.2020


Ответы (1)


Процесс не ищет функцию в so, он обращается непосредственно к ядру.

Неправильно, используемые вами функции системных вызовов (read(), write(), ...) являются обертками libc для реальных системных вызовов, даже для общей функции syscall(). Вот код для например, функция write(). Единственный способ напрямую войти в ядро ​​​​из вашей программы — вручную запустить системный вызов (см. ниже).

Работает ли LD_PRELOAD с двоичным файлом, который скомпилирован статически? Почему?

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

Почему LD_PRELOAD работает с динамически скомпилированным двоичным файлом, чтобы перехватывать системные вызовы?

Потому что это обычные функции libc, ни больше, ни меньше.


Единственный способ вручную вызвать системный вызов без использования библиотеки C (и, следовательно, без разрешения символов), кроме статической компиляции, — это использовать встроенная сборка. Вы можете взглянуть на man 2 syscall, чтобы узнать, какие регистры и инструкции по использованию. Например, в ARM AArch64 вы можете вызвать системный вызов, загрузив номер системного вызова в регистр x8, параметры в регистры с x0 по x5, а затем выполнив инструкцию svc #0.

person Marco Bonelli    schedule 28.02.2020
comment
Итак, если в моем коде я буду вызывать write напрямую с syscall, например syscall(WRITE_SYSCALL,fd, buf,nbytes);, никто не сможет применить LD_PRELOAD к этому процессу, даже если он компилируется динамически? Это мое объяснение написать? Что LD_PRELOAD помещает my so перед любым so, чтобы загрузчик сначала нашел мою функцию? - person yfr24493AzzrggAcom; 28.02.2020
comment
Нет. syscall() — это просто еще одна обертка libc. Как я уже сказал, единственный способ сделать это — либо (1) связать статически, либо (2) вручную написать сборку. Если вы не хотите, чтобы библиотечные функции перехватывались при динамическом связывании, не используйте библиотечные функции. - person Marco Bonelli; 28.02.2020
comment
спасибо (1) Это мое объяснение написать? Что LD_PRELOAD помещает my so перед любым so, поэтому загрузчик сначала находит мою функцию, а не исходную функцию? (2) могу ли я увидеть в /proc/pid эту специальную функцию, разрешенную mylib.so? - person yfr24493AzzrggAcom; 28.02.2020
comment
(1) да, верно. (2) /proc/pid/* вам особо не поможет. Если вы хотите увидеть, что функция разрешается через mylib.so, вам следует скомпилировать с отладочной информацией (-g), затем использовать gdb для запуска процесса и выполнять next до тех пор, пока не будет вызвана ваша функция. После вызова проверьте его адрес с помощью p funcname, затем проверьте info proc mappings, чтобы убедиться, что адрес находится внутри mylib.so. - person Marco Bonelli; 28.02.2020
comment
Другой способ обойти перехваты LD_PRELOAD — это явно открыть нужную библиотеку, dlsym к нужной функции и вызвать ее напрямую. - person Gem Taylor; 28.02.2020
comment
Конечно, LD_PRELOAD может перехватить dlopen и dlsym и солгать вам, но это будет сложно сделать таким образом, чтобы это не повлияло на других пользователей этих методов. - person Gem Taylor; 28.02.2020