более тонкий контроль, чем с LD_PRELOAD? - PullRequest
1 голос
/ 19 февраля 2020

У меня есть динамически связанный исполняемый файл ELF на Linux, и я хочу поменять местами функцию в библиотеке, с которой она связана. Конечно, с помощью LD_PRELOAD я могу предоставить небольшой библиотеке замену функции, которую я сам компилирую. Однако что если в замене я хочу вызвать оригинальную библиотечную функцию? Например, функция может быть srand (), и я хочу перехватить ее с моим собственным выбором семени, но в противном случае позвольте srand () делать то, что обычно делает.

Если бы я делал ссылку на этот исполняемый файл, я будет использовать опцию wrap компоновщика, но здесь у меня есть только скомпилированный двоичный файл.

Одним из тривиальных решений, которое я вижу, является вырезание и вставка исходного кода для исходной библиотечной функции в замену, но я хочу обработать более общий случай, когда источник недоступен. Или я мог бы в шестнадцатеричном виде отредактировать необходимый дополнительный код в двоичный файл, но это указывает c для двоичного файла, а также отнимает много времени. Возможно ли что-то более элегантное, чем любой из них? Например, некоторые волхвы c с загрузчиком?

(Извините, если я не использовал терминологию точно ...)

Ответы [ 3 ]

0 голосов
/ 20 февраля 2020

Канонический ответ - использовать dlsym(RTLD_NEXT, ...).

со страницы руководства :

RTLD_NEXT
          Find the next occurrence of the desired symbol in the search
          order after the current object.  This allows one to provide a
          wrapper around a function in another shared object, so that,
          for example, the definition of a function in a preloaded
          shared object (see LD_PRELOAD in ld.so(8)) can find and invoke
          the "real" function provided in another shared object (or for
          that matter, the "next" definition of the function in cases
          where there are multiple layers of preloading).

См. Также эту статью .

0 голосов
/ 23 февраля 2020

Просто для полноты, относительно редактирования имени функции в двоичном коде - я проверил, и это работает, но не без потенциальных сбоев. Например, в примере, который я упомянул, можно найти смещение «srand» (например, через strings -tx exefile | grep srand ) и отредактировать строку в «sran0». Но имена символов могут перекрываться (для экономии места), поэтому, если код также вызывает rand (), то в двоичном коде есть только одна строка «srand» для обоих. После изменения неразрешенные ссылки будут на sran0 и run0. Конечно, не шоу-шоу, но нужно помнить. Решение dlsym () определенно более гибкое.

0 голосов
/ 19 февраля 2020

Вот пример упаковки Малло c:

// LD_PRELOAD will cause the process to call this instead of malloc(3)
// report malloc(size) calls
void *malloc(size_t size)
    {
    // on first call, get a function pointer for malloc(3)
    static void *(*real_malloc)(size_t) = NULL;
    static int malloc_signal = 0;
    if(!real_malloc)
        {
        // real_malloc = (void *(*)(size_t))dlsym(RTLD_NEXT, "malloc");
        *(void **) (&real_malloc) = dlsym(RTLD_NEXT, "malloc");
        }
    assert(real_malloc);
    if (malloc_signal == 0)
        {
        char *string = getenv("MW_MALLOC_SIGNAL");
        if (string != NULL)
            {
            malloc_signal = 1;
            }
        }

    // call malloc(3)
    void *retval = real_malloc(size);
    fprintf(stderr, "MW! %f malloc size %zu, address %p\n", get_seconds(), size, retval);
    if (malloc_signal == 1)
        {
        send_signal(SIGUSR1);
        }
    return retval;
    }
...