Почему clang удаляет импорт конструктора из двоичного файла?

#c #linux #clang #linker-errors #reverse-engineering

#c #linux #clang #компоновщик-ошибки #обратная разработка

Вопрос:

Сегодня я обнаружил странное поведение clang с конструкторами. Когда g экспортирует _ZN14string_wrapperC1EPcm и _ZN14string_wrapperC2EPcm конструкторы. Только экспорт Clang _ZN14string_wrapperC2EPcm , и моя внедренная библиотека не может разрешить symbol во время выполнения.

Примечание: -rdynamic указывает компилятору экспортировать все символы из двоичного файла. Следовательно, символы связаны во время выполнения. Почему в моем коде нет объявлений этой функции.(см injector.cpp )

Пожалуйста, посоветуйте мне, как исправить ошибку времени выполнения. Я думаю, нужно что-то вроде библиотеки импорта из Windows. Дело в том, что нужно сообщить компоновщику, что символы объявлены в моем ./output/binary файле. Теперь он помечен как UND (неопределенный) и будет разрешен во время выполнения.

 $ readelf -Ws output/injector.so | grep _ZN

     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZN14string_wrapper5printEv
     3: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _ZN14string_wrapperC1EPcm
  

binary.cpp:

 #include <cstdio>

class string_wrapper {
private:
    char *data;
    size_t size;
public:
    string_wrapper(char *data, size_t size) : data(data), size(size) {}

    void print() {
        printf("%sn", data);
    }
};

int main() {
    char data[] = "regular string from this executable";
    string_wrapper string = string_wrapper(data, sizeof(data));
    string.print();

    return 0;
}
  

injector.cpp:

 #include <cstdio>

class string_wrapper {
private:
    char *data;
    size_t size;
public:
    string_wrapper(char *data, size_t size);

    void print();
};

__attribute__((constructor))
static void injector_init() {
    puts("injected into process");

    char data[] = "custom string from injector.so";
    string_wrapper string = string_wrapper(data, sizeof(data));
    string.print();
}
  

Makefile:

 all: targets binary injector run
targets:
    mkdir -p output
binary:
    clang   -rdynamic binary.cpp -o output/binary
injector:
    clang   -fPIC -shared injector.cpp -o output/injector.so
run:
    LD_PRELOAD=./output/injector.so ./output/binary
  
 $ make

mkdir -p output
clang   -rdynamic binary.cpp -o output/binary
clang   -frewrite-imports -fPIC -shared injector.cpp -o output/injector.so
LD_PRELOAD=./output/injector.so ./output/binary
injected into process
./output/binary: symbol lookup error: ./output/injector.so: undefined symbol: _ZN14string_wrapperC1EPcm
Makefile:9: recipe for target 'run' failed
make: *** [run] Error 127
  

Комментарии:

1. Ваш код нарушает одно правило определения, потому что два определения string_wrapper не идентичны. Поведение не определено. Поместите определение вашего класса в заголовочный файл, а #include его — в оба источника.

2. @n.’местоимения’m. спасибо, но это всего лишь пример. Кроме того, у меня обычно нет исходного кода binary.cpp , и заголовки this были бы перепроектированы.

3. Я не могу сказать вам, что не так с кодом, который я не вижу. Если у вас возникли проблемы с каким-либо другим кодом, пожалуйста, опубликуйте этот другой код. Если у вас возникли проблемы с обратным проектированием чего-либо, пожалуйста, задайте вопрос о обратном проектировании.

4. @n.’местоимения’m. нет, этот вопрос больше связан с ошибками компоновщика. Ограничениями является невозможность изменения флагов компиляции для двоичного файла. Можно коснуться только библиотеки инжекторов.

5. Пожалуйста, укажите свое ограничение и все остальное, что вы можете найти важным в самом вопросе. В любом случае, string_wrapper конструктор не экспортируется, потому что он не существует как отдельный символ. Он встроенный. Вы ничего не можете с этим поделать.