может показаться, что LD_PRELOAD или -Wl, -wrap, будут жизнеспособными решениями
Решение --wrap
не может быть жизнеспособным: оно работает только во время (статического) соединения, и ваши ld.so
и libc.so.6
и libdl.so.2
уже все связаны, поэтому сейчас слишком поздно используйте --wrap
.
LD_PRELOAD
мог бы сработать, за исключением ... ld.so учитывает тот факт, что dlopen()
вызывает open()
внутреннюю деталь реализации. Таким образом, он просто вызывает внутреннюю функцию __open
, минуя PLT
, и вашу способность вставлять open
в нее.
Каким-то образом malloc обходит проблему
Это потому, что libc
поддерживает пользователей, которые реализуют свои собственные malloc
(например, для целей отладки). Таким образом, вызов, например, calloc
из dlopen
проходит через PLT
и вставляется через LD_PRELOAD
.
Это может означать, что мне нужно собрать свой собственный ld.so напрямую из исходного кода, а не связывать его в оболочку.
Что будет делать восстановленный ld.so
? Я думаю, вы хотите, чтобы он вызывал __llibc_open
(в libc.so.6
), но это не может сработать по очевидной причине: это ld.so
, что open
s libc.so.6
в первую очередь (при запуске процесса) .
Вы можете перестроить ld.so
с вызовом __open
, замененным вызовом open
. Это заставит ld.so
пройти PLT
и выставить его на LD_PRELOAD
вставку.
Если вы пойдете по этому пути, я предлагаю вам не перезаписывать систему ld.so
новой копией (вероятность ошибиться и сделать систему не загружаемой слишком велика). Вместо этого установите его, например, на /usr/local/my-ld.so
, а затем свяжите ваши двоичные файлы с -Wl,--dynamic-linker=/usr/local/my-ld.so
.
Другая альтернатива: исправление во время выполнения. Это что-то вроде хака, но вы можете (как только вы получите контроль над main) просто сканировать .text
из ld.so
и искать CALL __open
инструкции. Если ld.so
не удален, вы можете найти как внутренние __open
, так и функции, которые вы хотите исправить (например, open_verify
в dl-load.c
). Как только вы найдете интересную CALL
, mprotect
страницу, которая содержит его, для записи, и исправите адрес своего собственного посредника (который, в свою очередь, может вызвать __libc_open
, если это необходимо), тогда mprotect
it назад. Любое будущее dlopen()
теперь будет проходить через вашего вставщика.