typedefstruct { Elf64_Word st_name; /* Symbol name (string tbl index) */ unsignedchar st_info; /* Symbol type and binding */ unsignedchar st_other; /* Symbol visibility */ Elf64_Section st_shndx; /* Section index */ Elf64_Addr st_value; /* Symbol value */ Elf64_Xword st_size; /* Symbol size */ } Elf64_Sym;
/* This function is called through a special trampoline from the PLT the first time each PLT entry is called. We must perform the relocation specified in the PLT of the given shared object, and return the resolved function address to the trampoline, which will restart the original call to that address.Future calls will bounce directly from the PLT to the function. */
/* Sanity check that we're really looking at a PLT relocation. */ assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
/* Look up the target symbol. If the normal lookup rules are not used don't look in the global scope. */ if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0) { conststructr_found_version *version =NULL;
if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) { constElfW(Half) *vernum = (constvoid *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]); ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff; version = &l->l_versions[ndx]; if (version->hash == 0) version = NULL; }
/* We need to keep the scope around so do some locking. This is not necessary for objects which cannot be unloaded or when we are not using any threads (yet). */ int flags = DL_LOOKUP_ADD_DEPENDENCY; if (!RTLD_SINGLE_THREAD_P) { THREAD_GSCOPE_SET_FLAG (); flags |= DL_LOOKUP_GSCOPE_LOCK; }
/* Currently result contains the base load address (or link map) of the object that defines sym. Now add in the symbol offset. */ value = DL_FIXUP_MAKE_VALUE (result, SYMBOL_ADDRESS (result, sym, false)); } else { /* We already found the symbol. The module (and therefore its load address) is also known. */ value = DL_FIXUP_MAKE_VALUE (l, SYMBOL_ADDRESS (l, sym, true)); result = l; }
/* And now perhaps the relocation addend. */ value = elf_machine_plt_value (l, reloc, value);
if (sym != NULL && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value));
/* Finally, fix up the plt itself. */ if (__glibc_unlikely (GLRO(dl_bind_not))) return value;
/* Inner part of the lookup functions. We return a value > 0 if we found the symbol, the value 0 if nothing is found and < 0 if something bad happened. */
staticint __attribute_noinline__ do_lookup_x(constchar *undef_name, uint_fast32_t new_hash, unsignedlongint *old_hash, const ElfW(Sym) *ref, struct sym_val *result, struct r_scope_elem *scope, size_t i, conststruct r_found_version *const version, int flags, struct link_map *skip, int type_class, struct link_map *undef_map) { size_t n = scope->r_nlist; /* Make sure we read the value before proceeding. Otherwise we might use r_list pointing to the initial scope and r_nlist being the value after a resize. That is the only path in dl-open.c not protected by GSCOPE. A read barrier here might be to expensive. */ __asm volatile("" : "+r" (n), "+m" (scope->r_list)); structlink_map **list = scope->r_list;
do { conststructlink_map *map =list[i]->l_real;
/* Here come the extra test needed for `_dl_lookup_symbol_skip'. */ if (map == skip) continue;
/* Don't search the executable when resolving a copy reloc. */ if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable) continue;
/* Do not look into objects which are going to be removed. */ if (map->l_removed) continue;
/* Print some debugging info if wanted. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS)) _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n", undef_name, DSO_FILENAME (map->l_name), map->l_ns);
/* If the hash table is empty there is nothing to do here. */ if (map->l_nbuckets == 0) continue;
Elf_Symndx symidx; int num_versions = 0; constElfW(Sym) *versioned_sym = NULL;
/* The tables for this map. */ constElfW(Sym) *symtab = (constvoid *) D_PTR (map, l_info[DT_SYMTAB]); constchar *strtab = (constvoid *) D_PTR (map, l_info[DT_STRTAB]);
/* Use the old SysV-style hash table. Search the appropriate hash bucket in this object's symbol table for a definition for the same symbol name. */ for (symidx = map->l_buckets[*old_hash % map->l_nbuckets]; symidx != STN_UNDEF; symidx = map->l_chain[symidx]) { sym = check_match (undef_name, ref, version, flags, type_class, &symtab[symidx], symidx, strtab, map, &versioned_sym, &num_versions); if (sym != NULL) goto found_it; } }
/* If we have seen exactly one versioned symbol while we are looking for an unversioned symbol and the version is not the default version we still accept this symbol since there are no possible ambiguities. */ sym = num_versions == 1 ? versioned_sym : NULL;
if (sym != NULL) { found_it: /* When UNDEF_MAP is NULL, which indicates we are called from do_lookup_x on relocation against protected data, we skip the data definion in the executable from copy reloc. */ if (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA && undef_map == NULL && map->l_type == lt_executable && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA) { constElfW(Sym) *s; unsignedint i;
for (i = 0; i < rela_count; i++, rela++) if (elf_machine_type_class (ELFW(R_TYPE) (rela->r_info)) == ELF_RTYPE_CLASS_COPY) { s = &symtab[ELFW(R_SYM) (rela->r_info)]; if (!strcmp (strtab + s->st_name, undef_name)) goto skip; } } #endif #if ! ELF_MACHINE_NO_REL if (map->l_info[DT_REL] != NULL && map->l_info[DT_RELSZ] != NULL && map->l_info[DT_RELSZ]->d_un.d_val != 0) { constElfW(Rel) *rel = (const ElfW(Rel) *) D_PTR (map, l_info[DT_REL]); unsignedint rel_count = map->l_info[DT_RELSZ]->d_un.d_val / sizeof (*rel);
for (i = 0; i < rel_count; i++, rel++) if (elf_machine_type_class (ELFW(R_TYPE) (rel->r_info)) == ELF_RTYPE_CLASS_COPY) { s = &symtab[ELFW(R_SYM) (rel->r_info)]; if (!strcmp (strtab + s->st_name, undef_name)) goto skip; } } #endif }
/* Hidden and internal symbols are local, ignore them. */ if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym))) goto skip;
switch (ELFW(ST_BIND) (sym->st_info)) { case STB_WEAK: /* Weak definition. Use this value if we don't find another. */ if (__glibc_unlikely (GLRO(dl_dynamic_weak))) { if (! result->s) { result->s = sym; result->m = (struct link_map *) map; } break; } /* FALLTHROUGH */ case STB_GLOBAL: /* Global definition. Just what we need. */ result->s = sym; result->m = (struct link_map *) map; return1;
default: /* Local symbols are ignored. */ break; } }
skip: ; } while (++i < n);
/* We have not found anything until now. */ return0; }
staticuint_fast32_t dl_new_hash(constchar *s) { uint_fast32_t h = 5381; for (unsignedchar c = *s; c != '\0'; c = *++s) h = h * 33 + c; return h & 0xffffffff; }
这个函数就是寻找符号的关键
[house_of_muney] 综上,伪造以下几个值就能劫持解析函数指向我们想要的函数:
1 2 3 4
bitmask_word bucket hasharr target symbol ->st_value
command = """ dir /home/str1k3/Desktop/glibc-2.31/glibc-2.31/build/elf dir /home/str1k3/Desktop/glibc-2.31/glibc-2.31/elf dir /home/str1k3/Desktop/glibc-2.31/glibc-2.31/elf/dl-lookup.c b *0x4021CA """