static void init (void) { void *resume, *personality; void *handle; handle = __libc_dlopen (LIBGCC_S_SO); if (handle == NULL || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) __libc_fatal (LIBGCC_S_SO " must be installed for pthread_cancel to work\n"); libgcc_s_resume = resume; libgcc_s_personality = personality; atomic_write_barrier (); /* At the point at which any thread writes the handle to libgcc_s_handle, the initialization is complete. The writing of libgcc_s_handle is atomic. All other threads reading libgcc_s_handle do so atomically. Any thread that does not execute this function must issue a read barrier to ensure that all of the above has actually completed and that the values of the function pointers are correct. */ libgcc_s_handle = handle; }
void pthread_cancel_init (void) { void *resume, *personality, *forcedunwind, *getcfa; void *handle; if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) return; handle = __libc_dlopen ("libgcc_s.so.1"); if (handle == NULL || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) == NULL || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL #ifdef ARCH_CANCEL_INIT || ARCH_CANCEL_INIT (handle) #endif ) __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); libgcc_s_resume = resume; libgcc_s_personality = personality; libgcc_s_forcedunwind = forcedunwind; libgcc_s_getcfa = getcfa; }
static void init (void) { libgcc_handle = __libc_dlopen ("libgcc_s.so.1"); if (libgcc_handle == NULL) return; unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace"); unwind_vrs_get = __libc_dlsym (libgcc_handle, "_Unwind_VRS_Get"); if (unwind_vrs_get == NULL) unwind_backtrace = NULL; }
static void init (void) { void *resume, *personality; void *handle; handle = __libc_dlopen ("libgcc_s.so.1"); if (handle == NULL || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); libgcc_s_resume = resume; libgcc_s_personality = personality; }
void * DLLLoader::GetFunction(const char *functionName) { // Now that dlsym is substituted by our own version, we need to use // libc private version of the function for our own purposes // return dlsym(handle, functionName); return __libc_dlsym(handle, functionName); }
/* * 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); }
void __attribute_noinline__ pthread_cancel_init (void) { void *resume; void *personality; void *forcedunwind; void *getcfa; void *handle; if (__builtin_expect (libgcc_s_handle != NULL, 1)) { /* Force gcc to reload all values. */ asm volatile ("" ::: "memory"); return; } handle = __libc_dlopen (LIBGCC_S_SO); if (handle == NULL || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) == NULL || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL #ifdef ARCH_CANCEL_INIT || ARCH_CANCEL_INIT (handle) #endif ) __libc_fatal (LIBGCC_S_SO " must be installed for pthread_cancel to work\n"); PTR_MANGLE (resume); libgcc_s_resume = resume; PTR_MANGLE (personality); libgcc_s_personality = personality; PTR_MANGLE (forcedunwind); libgcc_s_forcedunwind = forcedunwind; PTR_MANGLE (getcfa); libgcc_s_getcfa = getcfa; /* Make sure libgcc_s_handle is written last. Otherwise, pthread_cancel_init might return early even when the pointer the caller is interested in is not initialized yet. */ atomic_write_barrier (); libgcc_s_handle = handle; }
__libgcc_s_init(void) { void *resume, *personality; void *handle; handle = __libc_dlopen (LIBGCC_S_SO); if (handle == NULL || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) { fprintf (stderr, LIBGCC_S_SO " must be installed for pthread_cancel to work\n"); abort(); } __libgcc_s_resume = resume; libgcc_s_personality = personality; }
static void init (void) { libgcc_handle = __libc_dlopen ("libgcc_s.so.2"); if (libgcc_handle == NULL) return; unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace"); unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP"); unwind_getcfa = __libc_dlsym (libgcc_handle, "_Unwind_GetCFA"); unwind_getgr = __libc_dlsym (libgcc_handle, "_Unwind_GetGR"); if (unwind_getip == NULL || unwind_getgr == NULL || unwind_getcfa == NULL) { unwind_backtrace = NULL; __libc_dlclose (libgcc_handle); libgcc_handle = NULL; } }
void *libc_dlsym(const char *name) { void *ret, *libc = dlopen("libc.so", RTLD_LAZY); if (!libc) libc = dlopen("/lib/arm-linux-gnueabihf/libc.so.6", RTLD_LAZY); if (!libc) libc = dlopen("/lib/arm-linux-gnueabi/libc.so.6", RTLD_LAZY); ret = __libc_dlsym(libc, name); dlclose(libc); return ret; }
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); }
struct frame_state * __frame_state_for (void *pc, struct frame_state *frame_state) { static framesf frame_state_for; if (frame_state_for == NULL) { void *handle = __libc_dlopen (LIBGCC_S_SO); if (handle == NULL || (frame_state_for = (framesf) __libc_dlsym (handle, "__frame_state_for")) == NULL) #ifndef __USING_SJLJ_EXCEPTIONS__ frame_state_for = fallback_frame_state_for; #else frame_state_for = abort; #endif } return frame_state_for (pc, frame_state); }
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; }
void *dlsym(void *handle, const char *name) { if(!real_dlsym) { fprintf(stderr, "with_smaa: Getting real dlsym...\n"); void *libdl = dlopen(lib_path("libdl.so"), RTLD_NOW); real_dlsym = __libc_dlsym(libdl, "dlsym"); fprintf(stderr, "with_smaa: real_dlsym=%p\n", real_dlsym); } if (!strcmp(name, "dlsym")) { return (void*) dlsym; } else if(!strcmp(name, "glXGetProcAddressARB")) { fprintf(stderr, "with_smaa: dlsym: redirecting glXGetProcAddressARB\n"); return (void*) glXGetProcAddress; } else if(!strcmp(name, "glXGetProcAddress")) { fprintf(stderr, "with_smaa: dlsym: redirecting glXGetProcAddress\n"); return (void*) glXGetProcAddress; } else if(!strcmp(name, "glXSwapBuffers")) { fprintf(stderr, "with_smaa: dlsym: redirecting glXSwapBuffers\n"); return (void*) glXSwapBuffers; } return real_dlsym(handle, name); }
void * __nss_lookup_function (service_user *ni, const char *fct_name) { void **found, *result; /* We now modify global data. Protect it. */ __libc_lock_lock (lock); /* Search the tree of functions previously requested. Data in the tree are `known_function' structures, whose first member is a `const char *', the lookup key. The search returns a pointer to the tree node structure; the first member of the is a pointer to our structure (i.e. what will be a `known_function'); since the first member of that is the lookup key string, &FCT_NAME is close enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ found = __tsearch (&fct_name, (void **) &ni->known, &known_compare); if (*found != &fct_name) /* The search found an existing structure in the tree. */ result = ((known_function *) *found)->fct_ptr; else { /* This name was not known before. Now we have a node in the tree (in the proper sorted position for FCT_NAME) that points to &FCT_NAME instead of any real `known_function' structure. Allocate a new structure and fill it in. */ known_function *known = malloc (sizeof *known); if (! known) { remove_from_tree: /* Oops. We can't instantiate this node properly. Remove it from the tree. */ __tdelete (&fct_name, (void **) &ni->known, &known_compare); result = NULL; } else { /* Point the tree node at this new structure. */ *found = known; known->fct_name = fct_name; if (ni->library == NULL) { /* This service has not yet been used. Fetch the service library for it, creating a new one if need be. If there is no service table from the file, this static variable holds the head of the service_library list made from the default configuration. */ static name_database default_table; ni->library = nss_new_service (service_table ?: &default_table, ni->name); if (ni->library == NULL) { /* This only happens when out of memory. */ free (known); goto remove_from_tree; } } #if !defined DO_STATIC_NSS || defined SHARED if (ni->library->lib_handle == NULL) { /* Load the shared library. */ size_t shlen = (7 + strlen (ni->library->name) + 3 + strlen (__nss_shlib_revision) + 1); int saved_errno = errno; char shlib_name[shlen]; /* Construct shared object name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"), ni->library->name), ".so"), __nss_shlib_revision); ni->library->lib_handle = __libc_dlopen (shlib_name); if (ni->library->lib_handle == NULL) { /* Failed to load the library. */ ni->library->lib_handle = (void *) -1l; __set_errno (saved_errno); } } if (ni->library->lib_handle == (void *) -1l) /* Library not found => function not found. */ result = NULL; else { /* Get the desired function. */ size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), ni->library->name), "_"), fct_name); /* Look up the symbol. */ result = __libc_dlsym (ni->library->lib_handle, name); } #else /* We can't get function address dynamically in static linking. */ { # define DEFINE_ENT(h,nm) \ { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, # define DEFINE_GET(h,nm) \ { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, # define DEFINE_GETBY(h,nm,ky) \ { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = { # include "function.def" { NULL, NULL } }; size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (name, ni->library->name), "_"), fct_name); result = NULL; for (tp = &tbl[0]; tp->fname; tp++) if (strcmp (tp->fname, name) == 0) { result = tp->fp; break; } } #endif /* Remember function pointer for later calls. Even if null, we record it so a second try needn't search the library again. */ known->fct_ptr = result; } } /* Remove the lock. */ __libc_lock_unlock (lock); return result; }
static void* real_dlsym(void *handle, const char* symbol) { static fnDlsym internal_dlsym = (fnDlsym)__libc_dlsym(dlopen("libdl.so.2", RTLD_LAZY), "dlsym"); return (*internal_dlsym)(handle, symbol); }
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; }
/* Open the gconv database if necessary. A non-negative return value means success. */ struct __gconv_loaded_object * __gconv_find_shlib (const char *name) { struct __gconv_loaded_object *found; void *keyp; /* Search the tree of shared objects previously requested. Data in the tree are `loaded_object' structures, whose first member is a `const char *', the lookup key. The search returns a pointer to the tree node structure; the first member of the is a pointer to our structure (i.e. what will be a `loaded_object'); since the first member of that is the lookup key string, &FCT_NAME is close enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ keyp = __tfind (&name, &loaded, known_compare); if (keyp == NULL) { /* This name was not known before. */ size_t namelen = strlen (name) + 1; found = malloc (sizeof (struct __gconv_loaded_object) + namelen); if (found != NULL) { /* Point the tree node at this new structure. */ found->name = (char *) memcpy (found + 1, name, namelen); found->counter = -TRIES_BEFORE_UNLOAD - 1; found->handle = NULL; if (__builtin_expect (__tsearch (found, &loaded, known_compare) == NULL, 0)) { /* Something went wrong while inserting the entry. */ free (found); found = NULL; } } } else found = *(struct __gconv_loaded_object **) keyp; /* Try to load the shared object if the usage count is 0. This implies that if the shared object is not loadable, the handle is NULL and the usage count > 0. */ if (found != NULL) { if (found->counter < -TRIES_BEFORE_UNLOAD) { assert (found->handle == NULL); found->handle = __libc_dlopen (found->name); if (found->handle != NULL) { found->fct = __libc_dlsym (found->handle, "gconv"); if (found->fct == NULL) { /* Argh, no conversion function. There is something wrong here. */ __gconv_release_shlib (found); found = NULL; } else { found->init_fct = __libc_dlsym (found->handle, "gconv_init"); found->end_fct = __libc_dlsym (found->handle, "gconv_end"); #ifdef PTR_MANGLE PTR_MANGLE (found->fct); PTR_MANGLE (found->init_fct); PTR_MANGLE (found->end_fct); #endif /* We have succeeded in loading the shared object. */ found->counter = 1; } } else /* Error while loading the shared object. */ found = NULL; } else if (found->handle != NULL) found->counter = MAX (found->counter + 1, 1); } return found; }
/* returns the address of a symbol or dies */ void *find_symbol(void *hnd, const char *symbol, void *repl) { static void *libc_handle; char *error; void *addr; int i = 0; int free_idx = -1; if (libc_handle == NULL) { libc_handle = dlopen("libc.so.6", RTLD_LAZY); if (libc_handle == NULL) { fprintf(stderr, "%s: %s\n", symbol, dlerror()); exit(1); } } dlerror(); if (hnd == NULL) hnd = libc_handle; // lookup cache if (hnd == libc_handle) { pthread_mutex_lock(&cache_mutex); for (i = 0; i < SYMBOL_CACHE_SIZE; ++i) { if (repl && !symbol_cache[i].name[0]) { free_idx = i; break; } if (!strncmp(symbol, symbol_cache[i].name, SYMBOL_MAX_NAME)) { addr = symbol_cache[i].addr; if (addr == repl) fprintf(stderr, "FATAL!!! libdlsym detected a potential endless loop.\n'%s' redirection from %p to %p.\nPlease check your preload libs!", symbol, addr, repl); if (repl) symbol_cache[i].addr = repl; pthread_mutex_unlock(&cache_mutex); return addr; } } if (free_idx == -1) pthread_mutex_unlock(&cache_mutex); } addr = __libc_dlsym(hnd, symbol); error = dlerror(); if (error != NULL) { fprintf(stderr, "%s: %s\n", symbol, error); exit(1); } /* NULL may be a valid address of a symbol, but we're not going to call it. */ if (symbol == NULL) { fprintf(stderr, "%s: is a NULL pointer\n", symbol); exit(1); } if (repl) { if (free_idx != -1) { strncpy(symbol_cache[i].name, symbol, SYMBOL_MAX_NAME); symbol_cache[i].addr = repl; pthread_mutex_unlock(&cache_mutex); } else { fprintf(stderr, "symbol_cache too small!!! abort\n"); exit(1); } } return addr; }