void __attribute__ ((constructor)) libhook_main() { HOOKLOG( "LIBRARY LOADED FROM PID %d.", getpid() ); // get a list of all loaded modules inside this process. ld_modules_t modules = libhook_get_modules(); HOOKLOG( "Found %u loaded modules.", modules.size() ); HOOKLOG( "Installing %u hooks.", NHOOKS ); for( ld_modules_t::const_iterator i = modules.begin(), e = modules.end(); i != e; ++i ){ // only hook what is needed if( i->name.find( "libstrings.so" ) != std::string::npos ) { HOOKLOG( "[0x%X] Hooking %s ...", i->address, i->name.c_str() ); for( size_t j = 0; j < NHOOKS; ++j ) { unsigned tmp = libhook_addhook( i->name.c_str(), __hooks[j].name, __hooks[j].hook ); // update the original pointer only if the reference we found is valid // and the pointer itself doesn't have a value yet. if( __hooks[j].original == 0 && tmp != 0 ){ __hooks[j].original = (uintptr_t)tmp; HOOKLOG( " %s - 0x%x -> 0x%x", __hooks[j].name, __hooks[j].original, __hooks[j].hook ); } } } } }
uintptr_t find_original( const char *name ) { for( size_t i = 0; i < NHOOKS; ++i ) { if( strcmp( __hooks[i].name, name ) == 0 ){ return __hooks[i].original; } } HOOKLOG( "[%d] !!! COULD NOT FIND ORIGINAL POINTER OF FUNCTION '%s' !!!", getpid(), name ); return 0; }
unsigned libhook_addhook( const char *soname, const char *symbol, unsigned newval ) { struct soinfo *si = NULL; Elf32_Rel *rel = NULL; Elf32_Sym *s = NULL; unsigned int sym_offset = 0; size_t i; // HOOKLOG( "dlopen(%s)", soname ); // since we know the module is already loaded and mostly // we DO NOT want its constructors to be called again, // ise RTLD_NOLOAD to just get its soinfo address. si = (struct soinfo *)dlopen( soname, 4 /* RTLD_NOLOAD */ ); // si = (struct soinfo *)dlopen( soname, 0 /* RTLD_NOLOAD */ ); if( !si ){ HOOKLOG( "dlopen error: %s.", dlerror() ); return 0; } // HOOKLOG( "libhook_addhook dlopen success [0x%X], soinfo_elf_lookup...",(unsigned int)si); s = soinfo_elf_lookup( si, elfhash(symbol), symbol ); if( !s ){ return 0; } // HOOKLOG( "soinfo_elf_lookup = [0x%X]", (unsigned int)s); sym_offset = s - si->symtab; // HOOKLOG( "sym_offset = [0x%X]", sym_offset); // loop reloc table to find the symbol by index for( i = 0, rel = si->plt_rel; i < si->plt_rel_count; ++i, ++rel ) { unsigned type = ELF32_R_TYPE(rel->r_info); unsigned sym = ELF32_R_SYM(rel->r_info); unsigned reloc = (unsigned)(rel->r_offset + si->base); // HOOKLOG( "[%i] type/reloc/sym = [0x%X/0x%X/0x%X]", i, type, reloc, sym); if( sym_offset == sym ) { switch(type) { case R_ARM_JUMP_SLOT: // HOOKLOG( "found R_ARM_JUMP_SLOT at [0x%X]", reloc); return libhook_patch_address( reloc, newval ); default: HOOKLOG( "Expected R_ARM_JUMP_SLOT, found 0x%X", type ); } } } // HOOKLOG( "find by index finished %i", 0); unsigned original = 0; // loop dyn reloc table for( i = 0, rel = si->rel; i < si->rel_count; ++i, ++rel ) { unsigned type = ELF32_R_TYPE(rel->r_info); unsigned sym = ELF32_R_SYM(rel->r_info); unsigned reloc = (unsigned)(rel->r_offset + si->base); if( sym_offset == sym ) { switch(type) { case R_ARM_ABS32: case R_ARM_GLOB_DAT: original = libhook_patch_address( reloc, newval ); default: HOOKLOG( "Expected R_ARM_ABS32 or R_ARM_GLOB_DAT, found 0x%X", type ); } } } if( original == 0 ){ HOOKLOG( "Unable to find symbol in the reloc tables ( plt_rel_count=%u - rel_count=%u ).", si->plt_rel_count, si->rel_count ); } return original; }