Я хочу перехватывать вызовы приложения к dlsym, я пытался объявить внутри .so, что я предварительно загружаю dlsym, и использую сам dlsym, чтобы получить его реальный адрес, но это по вполне очевидным причинам не сработало.
Есть ли способ проще, чем брать карты памяти процесса и использовать libelf, чтобы найти реальное местоположение dlsym внутри загруженного libdl.so?
Я наткнулся на ту же проблему с ответом 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);
}
Обратите внимание на две вещи с этим «решением»:
(__libc_)dlsym()
, чтобы сделать этот потокобезопасным, вы должны добавить некоторые блокировки._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);
}
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;
}