How can I intercept dlsym calls using LD_PRELOAD?

I want to intercept application calls for dlsym, I tried to declare inside .so that I preloaded dlsym and used dlsym to get its real address, but for obvious reasons this did not work.

Is there a way that is easier than capturing process memory and using libelf to find the real location of dlsym inside loaded libdl.so?

+4
source share
2 answers

I came across the same problem with hdante's answer as the commenter: calling __libc_dlsym() crashes with segfault. After reading some glibc sources, I applied the following hack as a workaround:

 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); } 

SPECIFY two things with this “solution”:

  • This code bypasses the lock that runs inside (__libc_)dlsym() , so to make this thread safe, you need to add some lock.
  • The test argument _dl_sym() is the address of the caller, glibc seems to recover this value by expanding the stack, but I just use the address of the function itself. The caller’s address is used internally to find the reference map the caller is in to get things like RTLD_NEXT to the right (and using NULL as the thrid argument will fail the call when using RTLD_NEXT ). However, I did not look at glibc unindind functionality, so I am not 100% sure that the above code will work correctly, and it may happen that it works only by accident ...

The solution presented so far has some significant drawbacks: _dl_sym() acts in contrast to the intended dlsym() in some situations. For example, trying to resolve a character that does not exist, exit the program instead of just returning NULL. To get around this, you can use _dl_sym() to just get the pointer to the original dlsym() and use it for everything else (for example, in the "standard" LD_PRELOAD hook connection without any dlsym binding at all):

 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
source

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

From the text:

Beware of functions that themselves call dlsym () when you need to call __libc_dlsym (handle, symbol) in a hook.

 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
source

All Articles