/* * Protect against dlsym interception. * * We implement the whole API, so we don't need to intercept dlsym -- dlopen is * enough. However we need to protect against other dynamic libraries * intercepting dlsym, to prevent infinite recursion, * * In particular the Steam Community Overlay exports dlsym. See also * http://lists.freedesktop.org/archives/apitrace/2013-March/000573.html */ PRIVATE void * dlsym(void * handle, const char * symbol) { /* * We rely on glibc's internal __libc_dlsym. See also * http://www.linuxforu.com/2011/08/lets-hook-a-library-function/ * * Use use it to obtain the true dlsym. We don't use __libc_dlsym directly * because it does not support things such as RTLD_NEXT. */ typedef void * (*PFN_DLSYM)(void *, const char *); static PFN_DLSYM dlsym_ptr = NULL; if (!dlsym_ptr) { void *libdl_handle = __libc_dlopen_mode("libdl.so.2", RTLD_LOCAL | RTLD_NOW); if (libdl_handle) { dlsym_ptr = (PFN_DLSYM)__libc_dlsym(libdl_handle, "dlsym"); } if (!dlsym_ptr) { os::log("apitrace: error: failed to look up real dlsym\n"); return NULL; } } return dlsym_ptr(handle, symbol); }
int main(int argc, char **argv) { void *handle; double (*puts)(char *); char *error; handle = __libc_dlopen_mode("libc.so.6", RTLD_LAZY); if (!handle) { exit(1); } puts = __libc_dlsym(handle, "puts"); (*puts)("Hello World"); __libc_dlclose(handle); }
void * threadfunc (void * arg) { printf ("in threadfunc\n"); void * handle = __libc_dlopen_mode ("./test_unload.so", RTLD_LAZY | 0x80000000); printf ("dlopen ok handle: %p\n", handle); void (*pfn_shared_method)(void) = __libc_dlsym(handle, "shared_method"); printf ("before func\n"); pfn_shared_method (); printf ("after func\n"); printf ("about to dlclose handle: %p\n", handle); __libc_dlclose (handle); printf ("done dlclose\n"); while (!stopping) sleep (1); printf ("leaving threadfunc\n"); stopped = 1; }
static void gum_libdl_prevent_unload (void) { __libc_dlopen_mode ("libdl.so.2", RTLD_LAZY | GUM_RTLD_DLOPEN); }
static void load_library(const char* filename) { // Yay! Using internals of libc! Let's just cross fingers this won't change too fast :/ void* (*__libc_dlopen_mode)(const char*, int) = resolve_symbol("libc.so.6", "__libc_dlopen_mode"); __libc_dlopen_mode(filename, RTLD_NOW | RTLD_GLOBAL); }