Патч Ansi C с использованием dlsym компилируется нормально под Linux, но не работает на Mac Os X

Я создал небольшой патч для добавления к определенному приложению и отслеживания вызовов некоторых функций. Среди них malloc () и open (). Я использую dlsym, чтобы сохранить указатель на исходный символ и заменить имя функции своим собственным. Он компилируется и отлично работает под Linux. Вот код:

#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <dlfcn.h>

/**
 * Interponemos nuestra funcion open
 * 
 * @param   char*    filename
 * @param   int      flags
 **/

int open(char * filename, int flags)
{
    static int (*real_open)(char*, int) = NULL;
    if (!real_open)
        real_open = dlsym(RTLD_NEXT, "open");

    // Entero
    int p = real_open(filename, flags);
    fprintf(stderr, "Abrimos %s) = %i\n", filename, flags);

    // Devolvemos
    return p;
}

//--------------------------------------------------------

/**
 * Interponemos nuestra funcion malloc
 * 
 * @param   size_t    size
 */

void* malloc(size_t size)
{
    static void* (*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

    void *p = real_malloc(size);

    // Memoria reservada
    fprintf(stderr, "Reserva de memoria (%d) = %p\n", size, p);

    // Devolvemos
    return p;
}

Затем я компилирую его с помощью следующей инструкции, создав файл pi.so.

gcc -Wall -O2 -fPIC -shared -ldl -o pi.so pi.c 

А затем я использую директиву LD_PRELOAD, чтобы внедрить ее в любое приложение.

LD_PRELOAD=/home/.../injection/pi.so <binary>

И это прекрасно работает под Linux! Но когда я возвращаюсь домой и пытаюсь скомпилировать его с помощью GCC под Mac, он не компилируется, и директива LD_PRELOAd не работает. Что мне изменить? Большое Вам спасибо.


person flaab    schedule 28.09.2010    source источник
comment
Просто чтобы вы знали, было опубликовано техническое исправление, чтобы обойти тот факт, что C не определяет поведение для преобразования указателя void в указатель функции. См. Пример на странице POSIX для dlsym, чтобы узнать, как использовать это в соответствии с требованиями.   -  person dreamlax    schedule 28.09.2010


Ответы (3)


На mach вы должны использовать макрос DYLD_INSERT_LIBRARIES вместо LD_PRELOAD, чтобы указать список разделяемых библиотек для предварительной загрузки (1 ... *).

По умолчанию стандартные функции не заменяются функциями из общих объектов только потому, что у них одинаковые имена. Вы должны явно указать, какая функция переопределяет что, используя DYLD_INTERPOSE. Это позволяет вам объявить функцию замены с любым именем (например, переопределить open на my_open) и иметь возможность вызывать исходную функцию, которую вы переопределяете. Кроме того, вам не нужно вручную разрешать адреса реальных функций.

В качестве альтернативы, чтобы добиться поведения, подобного Linux, вы должны определить макрос DYLD_FORCE_FLAT_NAMESPACE.

Происходит еще много чего, подробности см. В руководстве dyld.

Итак, ваш код должен выглядеть примерно так:

#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <mach-o/dyld-interposing.h>

/**
 * Interponemos nuestra funcion open
 * 
 * @param   char*    filename
 * @param   int      flags
 **/

int my_open(char * filename, int flags)
{
    // Entero
    int p = open(filename, flags);
    fprintf(stderr, "Abrimos %s) = %i\n", filename, flags);

    // Devolvemos
    return p;
}
DYLD_INTERPOSE(my_open, open)

//--------------------------------------------------------

/**
 * Interponemos nuestra funcion malloc
 * 
 * @param   size_t    size
 */

void* my_malloc(size_t size)
{
    void *p = malloc(size);

    // Memoria reservada
    fprintf(stderr, "Reserva de memoria (%d) = %p\n", size, p);

    // Devolvemos
    return p;
}
DYLD_INTERPOSE(my_malloc, malloc)
person Community    schedule 28.09.2010
comment
У меня все заработало :-) Большое спасибо !! Дылд тоже пригодится для вставки классов? :) - person flaab; 29.09.2010
comment
@flaab Добро пожаловать. Вероятно, это не будет полезно для классов из-за искажения имен (в зависимости от имени класса, пространства имен и т. Д.). Технически возможно переопределить метод класса, но это было бы почти невозможно поддерживать, поскольку изменение имени не стандартизировано. - person ; 29.09.2010
comment
Привет Влад :) Заменить функции удалось без проблем. сейчас мне действительно нужно переопределить конкретную функцию класса. - person flaab; 29.09.2010
comment
Специальная функция - QString :: append (..., ..., ...). И конструктор также был бы идеален для переопределения: все это дало бы мне именно ту информацию, которая мне нужна: P - person flaab; 29.09.2010
comment
@flaab: Короче, лучше не делай этого. В противном случае см. en.wikipedia.org/wiki/Name_mangling и используйте этот метод как обычную функцию. Возможно, вы получите какие-то результаты, но я сомневаюсь, что это сработает. - person ; 29.09.2010
comment
Заголовок mach-o/dyld-interposing.h больше не существует в текущем SDK для macOS. - person JWWalker; 16.04.2019

Mac OS X (10.6.4) не содержит ссылок на LD_PRELOAD, поэтому он игнорируется, и, следовательно, ваша попытка вставить свой код не удалась. Весь мир не такой, как Linux.

Просматривая страницы руководства, я обнаружил:

$ man dyld

...

DYLD_INSERT_LIBRARIES Это список динамических библиотек, разделенных двоеточиями, для загрузки перед теми, которые указаны в программе. Это позволяет вам тестировать новые модули существующих динамических общих библиотек, которые используются в образах с плоским пространством имен, путем загрузки временной динамической общей библиотеки только с новыми модулями. Обратите внимание, что это не влияет на изображения, созданные в двухуровневом пространстве имен с использованием динамической разделяемой библиотеки, если также не используется DYLD_FORCE_FLAT_NAMESPACE.

person Jonathan Leffler    schedule 28.09.2010

Для OSX вам нужно будет использовать окружение DYLD_INSERT_LIBRARIES. переменная вместо LD_PRELOAD.

Однако я почти уверен, что вы не заставите переопределение работать. Самое близкое, что я могу найти, - вам придется проделать некоторые волшебные трюки со сборкой, которые кто-то аккуратно запаковал в коде в разделе mach_override здесь: http://extendamac.svn.sourceforge.net/viewvc/extendamac/trunk/code/.

person nos    schedule 28.09.2010
comment
Привет :-) Правда? Это сложно под Mac OS X? Я загрузил mach_override и изучаю исходный код, но пока не понимаю, как его использовать. В пакете нет текстовой документации: P Все равно спасибо. Приветствуются любые примеры использования: P - person flaab; 28.09.2010