structrtld_global { #endif /* Don't change the order of the following elements. 'dl_loaded' must remain the first element. Forever. */
/* Non-shared code has no support for multiple namespaces. */ #ifdef SHARED # define DL_NNS 16 #else # define DL_NNS 1 #endif EXTERN structlink_namespaces { /* A pointer to the map for the main map. */ structlink_map *_ns_loaded; /* Number of object in the _dl_loaded list. */ unsignedint _ns_nloaded; /* Direct pointer to the searchlist of the main object. */ structr_scope_elem *_ns_main_searchlist; /* This is zero at program start to signal that the global scope map is allocated by rtld. Later it keeps the size of the map. It might be reset if in _dl_close if the last global object is removed. */ unsignedint _ns_global_scope_alloc;
/* During dlopen, this is the number of objects that still need to be added to the global scope map. It has to be taken into account when resizing the map, for future map additions after recursive dlopen calls from ELF constructors. */ unsignedint _ns_global_scope_pending_adds;
/* Once libc.so has been loaded into the namespace, this points to its link map. */ structlink_map *libc_map; ##link_map结构体
/* Search table for unique objects. */ structunique_sym_table { __rtld_lock_define_recursive (, lock) structunique_sym { uint32_t hashval; constchar *name; constElfW(Sym) *sym; conststructlink_map *map; } *entries; size_t size; size_t n_elements; void (*free) (void *); } _ns_unique_sym_table; /* Keep track of changes to each namespace' list. */ structr_debug _ns_debug; } _dl_ns[DL_NNS]; /* One higher than index of last used namespace. */ EXTERN size_t _dl_nns; ................................................................................. };
unsigned int i; struct link_map *l; assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL); for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) /* Do not handle ld.so in secondary namespaces. */ if (l == l->l_real) //检查节点的地址是否跟自己结构体保存的一致 { assert (i < nloaded);
maps[i] = l; l->l_idx = i; ++i;
/* Bump l_direct_opencount of all objects so that they are not dlclose()ed from underneath us. */ ++l->l_direct_opencount; } assert (ns != LM_ID_BASE || i == nloaded); assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); unsigned int nmaps = i;
for (i = 0; i < nmaps; ++i) { struct link_map *l = maps[i]; //l遍历link_map的链表
if (l->l_init_called) //重要的检查点 { l->l_init_called = 0;
/* Is there a destructor function? */ if (l->l_info[DT_FINI_ARRAY] != NULL || (ELF_INITFINI && l->l_info[DT_FINI] != NULL)) { /* When debugging print a message first. */ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", DSO_FILENAME (l->l_name), ns);
/* First see whether an array is given. */ if (l->l_info[DT_FINI_ARRAY] != NULL) { ElfW(Addr) *array = (ElfW(Addr) *) (l->l_addr + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr))); while (i-- > 0) ((fini_t) array[i]) (); //目标位置 }
for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) /* Do not handle ld.so in secondary namespaces. */ // -------------------check0-------------------------------- if (l == l->l_real) // -------------------check0-------------------------------- { assert (i < nloaded);
maps[i] = l; l->l_idx = i; ++i;
/* Bump l_direct_opencount of all objects so that they are not dlclose()ed from underneath us. */ ++l->l_direct_opencount; } assert (ns != LM_ID_BASE || i == nloaded); assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
因为我们必须有四个link_map结构体,所以我们需要找到第三个节点的位置,伪造他的next段
1 2
pwndbg> p &(_rtld_global._dl_ns._ns_loaded->l_next->l_next->l_next) $3 = (struct link_map **) 0x7ffff7ff7018
#define DT_FINI_ARRAY 26/* Array with addresses of fini fct */ #define DT_FINI_ARRAYSZ 28/* Size in bytes of DT_FINI_ARRAY */
for (i = 0; i < nmaps; ++i) { struct link_map *l = maps[i]; // -------------------check1-------------------------------- if (l->l_init_called) // -------------------check1-------------------------------- { /* Make sure nothing happens if we are called twice. */ l->l_init_called = 0;
/* Is there a destructor function? */ // -------------------check2-------------------------------- if (l->l_info[26] != NULL || l->l_info[DT_FINI] != NULL) // -------------------check2-------------------------------- { ....