Как я могу переопределить глобальный символ в библиотеке, загруженной с помощью dlopen? - PullRequest
3 голосов
/ 19 июня 2020

Здесь задействованы 3 компонента

  • main: основная программа, загружает loader.so
  • loader.so: скомпилирован с помощью -Bsymbolic, отменяет puts и загружает other.so
  • other.so: вызывает puts и не может быть изменен

Как я могу использовать other.so вместо puts из loader.so?

Обратите внимание, что я хочу, чтобы puts был заменен только начиная с loader.so и далее (включая other.so), основная программа не должна быть затронута

Пример кода следует

основной. c

#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char *argv[]){
    dlopen("./loader.so", RTLD_NOW | RTLD_GLOBAL | RTLD_DEEPBIND);
    puts("Normal");
    return 0;
}

загрузчик. c

#include <stdio.h>
#include <dlfcn.h>

extern int puts(const char *s){
    fputs("Hooked: ", stdout);
    fputs(s, stdout);
    fputc('\n', stdout);
    return 0;
}

__attribute__((constructor))
void ctor(void) {
    puts("Something");
    void *other = dlopen("./other.so", RTLD_NOW);
}

другое . c

#include <stdio.h>

__attribute__((constructor))
void ctor(void) {
    puts("Hello!");
}

марка. sh

#!/bin/bash
gcc main.c -o main -ldl
gcc loader.c -fPIC -shared -Wl,-Bsymbolic -o loader.so
gcc other.c -fPIC -shared -o other.so

Желаемая мощность

Hooked: Something
Hooked: Hello!
Normal

Фактический выход

Hooked: Something
Hello!
Normal

Ответы [ 2 ]

1 голос
/ 19 июня 2020

После того, как я еще немного поигрался с проблемой, у меня есть решение, для которого требуется небольшая внешняя помощь от 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, если все, что нам нужно, это восстановить исходное поведение

0 голосов
/ 19 июня 2020

Попробуйте добавить флаг -Wl,--no-as-needed

gcc loader.c -fPIC -shared -Wl,-Bsymbolic -Wl,--no-as-needed -o loader.so

Я успешно подключил функции, связанные со временем, из библиотеки C в time-machine .

...