/* * Locate a symbol in an ELF image. */ int elf32FindSymbolByName(struct ElfObject *o, const char *name, const Elf32_Sym **symp, const char **namep) { struct Section *shdrs, *hash, *syms; const char *symStrings; const Elf32_Sym *sym; Elf32_Word nbucket; Elf32_Word nchain; Elf32_Word i; const Elf32_Word *buckets; const Elf32_Word *chains; const Elf32_Word *hashData; unsigned long hashv; shdrs = o->sectionHeaders; /* First, search the hashed symbols in .dynsym. */ if (elf32FindSectionByName(o, ".hash", &hash) != -1) { syms = &shdrs[hash->shdr.sh_link]; hashData = elf32MapSection(o, hash); sym = elf32MapSection(o, syms); symStrings = elf32MapSection(o, &shdrs[syms->shdr.sh_link]); nbucket = hashData[0]; nchain = hashData[1]; buckets = hashData + 2; chains = buckets + nbucket; hashv = elfhash(name) % nbucket; for (i = buckets[hashv]; i != STN_UNDEF; i = chains[i]) if (strcmp(symStrings + sym[i].st_name, name) == 0) { *symp = sym + i; if (namep) *namep = symStrings + sym[i].st_name; return (0); } } else if (elf32FindSectionByName(o, ".dynsym", &syms) != -1) { /* No ".hash", but have ".dynsym": do linear search */ if (elf32LinearSymSearch(o, syms, name, symp, namep) != -1) { return (0); } } /* Do a linear search of ".symtab" if present */ if (elf32FindSectionByName(o, ".symtab", &syms) != -1 && elf32LinearSymSearch(o, syms, name, symp, namep) != -1) { return (0); } return -1; }
void elfdynhash(void) { Sym *s, *sy, *dynstr; int i, j, nbucket, b, nfile; uint32 hc, *chain, *buckets; int nsym; char *name; Elfaux **need; Elflib *needlib; Elflib *l; Elfaux *x; if(!iself) return; nsym = nelfsym; s = lookup(".hash", 0); s->type = SELFROSECT; s->reachable = 1; i = nsym; nbucket = 1; while(i > 0) { ++nbucket; i >>= 1; } needlib = nil; need = malloc(nsym * sizeof need[0]); chain = malloc(nsym * sizeof chain[0]); buckets = malloc(nbucket * sizeof buckets[0]); if(need == nil || chain == nil || buckets == nil) { cursym = nil; diag("out of memory"); errorexit(); } memset(need, 0, nsym * sizeof need[0]); memset(chain, 0, nsym * sizeof chain[0]); memset(buckets, 0, nbucket * sizeof buckets[0]); for(sy=allsym; sy!=S; sy=sy->allsym) { if (sy->dynid <= 0) continue; if(sy->dynimpvers) need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers); name = sy->dynimpname; if(name == nil) name = sy->name; hc = elfhash((uchar*)name); b = hc % nbucket; chain[sy->dynid] = buckets[b]; buckets[b] = sy->dynid; } adduint32(s, nbucket); adduint32(s, nsym); for(i = 0; i<nbucket; i++) adduint32(s, buckets[i]); for(i = 0; i<nsym; i++) adduint32(s, chain[i]); free(chain); free(buckets); // version symbols dynstr = lookup(".dynstr", 0); s = lookup(".gnu.version_r", 0); i = 2; nfile = 0; for(l=needlib; l; l=l->next) { nfile++; // header adduint16(s, 1); // table version j = 0; for(x=l->aux; x; x=x->next) j++; adduint16(s, j); // aux count adduint32(s, addstring(dynstr, l->file)); // file string offset adduint32(s, 16); // offset from header to first aux if(l->next) adduint32(s, 16+j*16); // offset from this header to next else adduint32(s, 0); for(x=l->aux; x; x=x->next) { x->num = i++; // aux struct adduint32(s, elfhash((uchar*)x->vers)); // hash adduint16(s, 0); // flags adduint16(s, x->num); // other - index we refer to this by adduint32(s, addstring(dynstr, x->vers)); // version string offset if(x->next) adduint32(s, 16); // offset from this aux to next else adduint32(s, 0); } } // version references s = lookup(".gnu.version", 0); for(i=0; i<nsym; i++) { if(i == 0) adduint16(s, 0); // first entry - no symbol else if(need[i] == nil) adduint16(s, 1); // global else adduint16(s, need[i]->num); } free(need); s = lookup(".dynamic", 0); elfverneed = nfile; if(elfverneed) { elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0)); elfwritedynent(s, DT_VERNEEDNUM, nfile); elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0)); } elfwritedynent(s, DT_NULL, 0); }
int main(int argc ,char** argv) { Elf32_Ehdr ehdr; Elf32_Phdr phdr; Elf32_Word dyn_size,dyn_strsz; Elf32_Off dyn_off; Elf32_Dyn dyn; Elf32_Addr dyn_sym,dyn_str,dyn_hash; unsigned func_hash,nbucket,nchain,func_index; char * ptr_dynstr = NULL; char * ptr_func_content = NULL; Elf32_Sym func_sym; int flag = 0; int i = 0; char func_name[] = "getString"; if(argc < 2) { printf("input the so file\n"); return 0; } int fd = open(argv[1],O_RDWR); if(fd < 0) { printf("open file failed\n"); goto _error; } lseek(fd,0,SEEK_SET); if(read(fd,&ehdr,sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)) { printf("read elf header failed\n"); goto _error; } lseek(fd,ehdr.e_phoff,SEEK_SET); for(i=0; i<ehdr.e_phnum;i++) { memset(&phdr,0,sizeof(phdr)); if(read(fd,&phdr,sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)) { printf("read segment failed\n"); goto _error; } if(phdr.p_type == PT_DYNAMIC) { dyn_off = phdr.p_offset; dyn_size = phdr.p_filesz; printf("find .dynamic section\n"); break; } } lseek(fd,dyn_off,SEEK_SET); //for(i = 0;i<dyn_size/sizeof(Elf32_Dyn);i++) do{ if(read(fd,&dyn,sizeof(Elf32_Dyn)) != sizeof(Elf32_Dyn)) { printf("read .dynamic failed\n"); goto _error; } if(dyn.d_tag == DT_SYMTAB) { flag |= SYMTAB; dyn_sym = dyn.d_un.d_ptr; } if(dyn.d_tag == DT_STRTAB) { flag |= STRTAB; dyn_str = dyn.d_un.d_ptr; } if(dyn.d_tag == DT_STRSZ) { flag |= STRSZ; dyn_strsz = dyn.d_un.d_val; } if(dyn.d_tag == DT_HASH) { flag |= HASH; dyn_hash = dyn.d_un.d_ptr; } } while(dyn.d_tag != DT_NULL); if((flag & 0x0f) != 0x0f) { printf("find the needed dynamic section failed\n"); goto _error; } ptr_dynstr = (char*)malloc(dyn_strsz); if(ptr_dynstr == NULL) { printf("malloc .dynstr failed\n"); goto _error; } lseek(fd,dyn_str,SEEK_SET); if(read(fd,ptr_dynstr,dyn_strsz) != dyn_strsz) { printf("read .dynstr failed\n"); goto _error; } func_hash = elfhash(func_name); lseek(fd,dyn_hash,SEEK_SET); if(read(fd,&nbucket,4) != 4) { printf("read hash nbucket failed\n"); goto _error; } if(read(fd,&nchain,4) != 4) { printf("read hash nchain failed\n"); goto _error; } func_hash = func_hash%nbucket; lseek(fd,func_hash*4,SEEK_CUR); if(read(fd,&func_index,4) != 4)//索引是符号表或者chain { printf("read funck index failed\n"); goto _error; } lseek(fd,dyn_sym+func_index*sizeof(Elf32_Sym),SEEK_SET); if(read(fd,&func_sym,sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)) { printf("read func sym entry failed\n'"); } if(strcmp(ptr_dynstr+func_sym.st_name,func_name) != 0) { while(1) //纯C语言是没有true的 { lseek(fd,dyn_hash+4*(2+nbucket+func_index),SEEK_SET); if(read(fd,&func_index,4) != 4) { printf("read func index failed\n"); goto _error; } lseek(fd,dyn_sym + func_index*sizeof(Elf32_Sym),SEEK_SET); memset(&func_sym,0,sizeof(Elf32_Sym)); if(read(fd,&func_sym,sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)) { goto _error; } if(strcmp(func_name,dyn_str+func_sym.st_name) == 0) { break; } } } printf("find target func addr: %x,sizeo:%x\n",func_sym.st_value,func_sym.st_size); ptr_func_content = (char*)malloc(func_sym.st_size); if(ptr_func_content == NULL) { printf("alloc for func failed\n"); goto _error; } lseek(fd,func_sym.st_value,SEEK_SET); if(read(fd,ptr_func_content,func_sym.st_size) != func_sym.st_size) { printf("read func content failed\n"); goto _error; } for(i=0;i<func_sym.st_size;i++) { ptr_func_content[i] = ~ptr_func_content[i]; } lseek(fd,func_sym.st_value,SEEK_SET); if(write(fd,ptr_func_content,func_sym.st_size) != func_sym.st_size) { printf("write to func failed\n"); goto _error; } printf("Complete \n"); _error: if(ptr_dynstr != NULL) { free(ptr_dynstr); } if(ptr_func_content != NULL) { free(ptr_func_content); } 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; }