Можно ли обернуть объект dynamic c в динамически связанный двоичный файл ELF? - PullRequest
0 голосов
/ 27 мая 2020

Я пытаюсь обернуть символ glib c своим собственным определением этого символа. Для функций, которые предоставляет glib c, это было так же просто, как определение __wrap_function_name в моем исходном коде и последующее добавление Wl,--wrap=external_function_name к флагам компоновщика шагов компоновки моей системы сборки. На практике это будет выглядеть примерно так:

extern "C" void __wrap_external_function_name(void) {
    my_internal function();
}

Однако я недавно попытался сделать то же самое с переменной, которую предоставляет glib c, в данном случае __signgam. Я снова определил флаги компоновщика для его оболочки, но я не уверен, как и возможно ли вообще определить оболочку для переменной. Я попробовал __wrap__signgam = signgam, но это не помогло. Фактически таблица символов при отображении с помощью objdump -T binary | grep signgam имела следующее содержимое, показывающее, что даже несмотря на то, что функция переноса определена, исходный символ остается нетронутым:

0000000000000000      DO *UND*  0000000000000000  GLIBC_2.23  __signgam
0000000000000000      DO *UND*  0000000000000000  GLIBC_2.2.5 signgam
0000000001509d24 g    DO .bss   0000000000000004  Base        __wrap___signgam

Есть ли канонический способ обернуть эти динамические c объектов?

1 Ответ

0 голосов
/ 27 мая 2020

Вы можете использовать динамическую c загрузочную библиотеку (например, -ldl) и использовать некоторые из ее функций, в частности, dlsym.

Есть три шага:

  1. Сначала создайте исходный файл.
  2. Создайте общую библиотеку (.so файл) из этого исходного файла
  3. Вызовите целевую программу (установите переменную среды LD_PRELOAD, чтобы она указывала на ваш .so file

Обратите внимание, что для перехвата данной функции ваша функция должна быть определена с таким же именем.

У вас может быть столько же функции перехвата, как вы хотите, в исходном файле.

Вот пример исходного кода для перехвата (например) read ...

// NOTE: need _GNU_SOURCE above for RTLD_NEXT in dlfcn.h
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>

#include <string.h>

static void
msg(const char *buf)
{
    int len;

    len = strlen(buf);
    write(1,buf,len);
}

// read -- read a file
ssize_t
read(int unit,void *buf,size_t buflen)
{
    static ssize_t (*proc)(int,void *,size_t) = NULL;
    ssize_t rlen;

    // get pointer to real function (only needs to be done once)
    if (proc == NULL)
        proc = dlsym(RTLD_NEXT,"read");

    // do [whatever] stuff before real read ...
    msg("PHONY: before\n");

    // invoke the real function
    rlen = proc(unit,buf,buflen);

    // do [whatever] stuff after real read ...
    msg("PHONY: after\n");

    return rlen;
}

Вот пример целевой программы :

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int
main(void)
{
    int fd;
    int rlen;
    char buf[100];

    fd = open("/etc/passwd",O_RDONLY);

    rlen = read(fd,buf,sizeof(buf));

    close(fd);

    printf("main: read %d bytes\n",rlen);

    return 0;
}

Теперь создайте общую библиотеку (.so).

Обратите внимание, что ниже представлен только один исходный файл. Но вы можете создать библиотеку из такого количества отдельные исходные файлы, как вы sh (например, вы можете поместить одну функцию перехвата для каждого исходного файла или поместить все в один источник файл на ваш выбор).

Вот [грубый] Makefile (который создает общую библиотеку и пример целевой программы):

all: mylib.so target

read.o: read.c
    cc -c -fPIC read.c

mylib.so: read.o
    cc -shared -o mylib.so read.o -ldl

target: target.c
    cc -o target target.c

test:
    env LD_PRELOAD=./mylib.so ./target

clean:
    rm -f mylib.so *.o target

Теперь, чтобы вызвать целевую программу (например):

make test

Вот сгенерированный результат теста:

env LD_PRELOAD=./mylib.so ./target
PHONY: before
PHONY: after
main: read 100 bytes
...