После того, как я еще немного поигрался с проблемой, у меня есть решение, для которого требуется небольшая внешняя помощь от patchelf
, поэтому я подожду, чтобы принять это решение, на случай, если есть другой подход к проблеме.
Это решение работает путем создания нового общего объекта, shared.so
, с измененным puts
, как показано ниже
int puts(const char *s){
fputs("Hooked: ", stdout);
fputs(s, stdout);
fputc('\n', stdout);
return 0;
}
Затем нам нужно заставить other.so
зависеть от этого нового общего объекта , и мы можем сделать это, используя patchelf --add-needed shared.so other.so
Этот включает в себя модификацию other.so
, но не требует повторной компиляции из источника (что делает этот подход более выполнимо).
Теперь, когда мы загружаем other.so
, нам нужно указать RTLD_DEEPBIND
внутри loader.c
вот так
void *other = dlopen("./libother.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
, чтобы порядок поиска не запускался из глобального контекста, но из самой библиотеки. Поскольку other.so
не определяет puts
, будут найдены прямые зависимости, а puts
будет найден в shared.so
. Свойства RTLD_DEEPBIND
гарантируют, что даже возможные LD_PRELOAD
ed объекты имеют приоритет.
Поэтому, если puts
отключен внутри предварительно загруженного общего объекта, мы можем обойти это и вызвать реальный, немодифицированный puts
из glib c (и только для исходящих вызовов от other.so
).
Нам не нужны patchelf
или shared.so
, если все, что нам нужно, это восстановить исходное поведение