文章目录
- exit_hook
- 概述
- 例题:
- 思路:
- 利用:
- setcontext
- glibc-2.27以及 之前
- glibc-2.29以及之后:
exit_hook
概述
大佬文章:exit_hook在pwn题中的应用 - 不会修电脑 - 博客园 (cnblogs.com)
-
exit_hook :是程序在执行exit函数时,会去该位置拿一个函数指针,进而执行的一段程序,如果能修改掉这个函数指针就能挟持程序的控制流,执行想要的gadget。
-
观察执行exit函数时程序的运行状态:
#include <stdio.h> #include <stdlib.h>int main(){exit(0);return 0; }
这里用libc-2.32.so演示一下exit的调用过程:
先进__run_exit_handlers函数:
这里会调用到**_dl_fini函数** ,进入:
_dl_fini函数开头的for循环中就调用到了rtld_lock_default_lock_recursive函数 ,可以看到该函数的地址是直接通过*(rip + 偏移)拿到的:
在ida中反汇编一下ld文件,找到_dl_fini函数,可以看到该处的汇编指令是直接通过 _rtld_local拿到的 _dl_rtld_lock_recursive地址:
gdb看一下_rtld_local的结构,可以看到两个函数指针的位置,所以只要我们覆盖掉指针的值即可挟持程序的控制流了:
这里再反过来看一下_dl_fini函数的源码:
void _dl_fini (void) {/* Lots of fun ahead. We have to call the destructors for all stillloaded objects, in all namespaces. The problem is that the ELFspecification now demands that dependencies between the modulesare taken into account. I.e., the destructor for a module iscalled before the ones for any of its dependencies.To make things more complicated, we cannot simply use the reverseorder of the constructors. Since the user might have loaded objectsusing `dlopen' there are possibly several other modules with itsdependencies to be taken into account. Therefore we have to startdetermining the order of the modules once again from the beginning. *//* We run the destructors of the main namespaces last. As for theother namespaces, we pick run the destructors in them in reverseorder of the namespace ID. */ #ifdef SHAREDint do_audit = 0;again: #endiffor (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns){/* Protect against concurrent loads and unloads. */__rtld_lock_lock_recursive (GL(dl_load_lock)); // 这里直接调用没有判断条件unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;/* No need to do anything for empty namespaces or those used forauditing DSOs. */if (nloaded == 0 #ifdef SHARED|| GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit #endif)__rtld_lock_unlock_recursive (GL(dl_load_lock)); // 这里有一个if判断条件通过才能调用else{/* Now we can allocate an array to hold all the pointers andcopy the pointers in. */struct link_map *maps[nloaded];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