Как я могу перехватить вызовы dlsym, используя LD_PRELOAD?

Я хочу перехватывать вызовы приложения к dlsym, я пытался объявить внутри .so, что я предварительно загружаю dlsym, и использую сам dlsym, чтобы получить его реальный адрес, но это по вполне очевидным причинам не сработало.

Есть ли способ проще, чем брать карты памяти процесса и использовать libelf, чтобы найти реальное местоположение dlsym внутри загруженного libdl.so?

4

Решение

Я наткнулся на ту же проблему с ответом hdante, что и комментатор: __libc_dlsym() непосредственно падает с segfault. Прочитав некоторые источники glibc, я нашел следующий способ:

extern void *_dl_sym(void *, const char *, void *);
extern void *dlsym(void *handle, const char *name)
{
/* my target binary is even asking for dlsym() via dlsym()... */
if (!strcmp(name,"dlsym"))
return (void*)dlsym;
return _dl_sym(handle, name, dlsym);
}

Обратите внимание на две вещи с этим «решением»:

  1. Этот код обходит блокировку, которая выполняется внутри (__libc_)dlsym(), чтобы сделать этот потокобезопасным, вы должны добавить некоторые блокировки.
  2. Третий аргумент _dl_sym() является адресом вызывающей стороны, glibc, кажется, восстанавливает это значение путем разматывания стека, но я просто использую адрес самой функции. Адрес вызывающего абонента используется внутри, чтобы найти карту ссылок, в которой звонящий, чтобы получить такие вещи, как RTLD_NEXT право (и использование NULL в качестве аргумента thrid вызовет сбой с ошибкой при использовании RTLD_NEXT). Тем не менее, я не смотрел на функциональность glibc по раскручиванию, поэтому я не уверен на 100%, что приведенный выше код будет работать правильно, и может случиться, что он сработает просто случайно …

Представленное решение имеет ряд существенных недостатков: _dl_sym() действует совсем не так, как предполагалось dlsym() в некоторых ситуациях. Например, попытка разрешить несуществующий символ действительно завершает программу, а не просто возвращает NULL. Чтобы обойти это, можно использовать _dl_sym() просто получить указатель на оригинал dlsym() и использовать это для всего остального (как в «стандарте» LD_PRELOAD крюк приближается без зацепления dlsym совсем):

extern void *_dl_sym(void *, const char *, void *);
extern void *dlsym(void *handle, const char *name)
{
static void * (*real_dlsym)(void *, const char *)=NULL;
if (real_dlsym == NULL)
real_dlsym=_dl_sym(RTLD_NEXT, "dlsym", dlsym);
/* my target binary is even asking for dlsym() via dlsym()... */
if (!strcmp(name,"dlsym"))
return (void*)dlsym;
return real_dlsym(handle,name);
}
3

Другие решения

http://www.linuxforu.com/2011/08/lets-hook-a-library-function/

Из текста:

Остерегайтесь функций, которые сами вызывают dlsym (), когда вам нужно вызвать __libc_dlsym (handle, symbol) в хуке.

extern void *__libc_dlsym (void *, const char *);
void *dlsym(void *handle, const char *symbol)
{
printf("Ha Ha...dlsym() Hooked\n");
void* result = __libc_dlsym(handle, symbol); /* now, this will call dlsym() library function */
return result;
}
0

По вопросам рекламы [email protected]