1.android dlopenååå¨åªä¸ªso
2.exit()分析与利用
android dlopenååå¨åªä¸ªso
1ã .soæåº
使ç¨gccæè g++ç¼è¯å¨æåºæ件(å¤g++ç¼è¯å¨ä¾)
g++ -shared -fPIC -c XXX.cpp
g++ -shared -fPIC -o XXX.so XXX.o
2ã .soæåºæè°ç¨æ¥å£å½æ°è¯´æ
æåºè°ç¨å ³ç³»éè¦è°ç¨æåºç¨åºç¼è¯ég++-L-lå½ä»¤æå®ä¾ï¼ç¨åºtestå¯éè¦å è½½ç®å½/root/src/liblibtest_so1.soæåºç¼è¯å½ä»¤ç §ç¼åæ§è¡ï¼
g++ -g -o test test.cpp âL/root/src/lib âltest_so1
ï¼å¤æéç¹è®²è§£æåºæè°ç¨å ³äºéæég++ç¼è¯å½ä»¤è°ç¨å¼ä½è¯¦ç»è®²è§£å ·ä½ç¸å ³å 容ç½æ¥è¯¢)
Linuxæä¾ä¸é¨ç»APIç¨äºå®ææåºæ¥æ¾ç¬¦å·å¤çéå ³éæåºçåè½
é¢äºæ¥å£å½æ°éä»ç»ï¼è°ç¨äºæ¥å£éå¼ç¨æ件#include )ï¼
1) dlopen
å½æ°ååï¼void *dlopen(const char *libname,源码int flag);
åè½æè¿°ï¼dlopenå¿ é¡»dlerrordlsymdlcloseåè°ç¨è¡¨ç¤ºè¦åºè£ è½½å ååå¤ä½¿ç¨è¦è£ è½½åºä¾èµäºå ¶åºå¿ é¡»é¦å è£ è½½ä¾èµåºdlopenæä½å¤±è´¥è¿NULLå¼ï¼åºå·²ç»è£ è½½ådlopenè¿åå¥æ
åæ°libnameè¬åºå ¨è·¯å¾dlopenç´æ¥è£ 载该æ件ï¼æå®åºå称dlopenæç §é¢æºå¶æ寻ï¼
a.æ ¹æ®ç¯å¢åéLD_LIBRARY_PATHæ¥æ¾
b.æ ¹æ®/etc/ld.so.cacheæ¥æ¾
c.æ¥æ¾ä¾/lib/usr/libç®å½æ¥æ¾
flagåæ°è¡¨ç¤ºå¤çæªå®ä¹å½æ°å¼ä½¿ç¨RTLD_LAZYæRTLD_NOWRTLD_LAZY表示æå¤çæªå®ä¹å½æ°å åºè£ è½½å åçç¨æ²¡å®ä¹å½æ°å说ï¼RTLD_NOW表示马æ£æ¥å¦åæªå®ä¹å½æ°è¥åådlopen失败åç»
2) dlerror
å½æ°ååï¼char *dlerror(void);
åè½æè¿°ï¼dlerrorè·è¿dlopen,dlsymædlcloseæä½é误信æ¯è¿NULL表示é误dlerrorè¿é误信æ¯åæ¸ é¤é误信æ¯
3) dlsym
å½æ°ååï¼void *dlsym(void *handle,const char *symbol);
åè½æè¿°ï¼dlopenåºè£ è½½å ådlsymè·æå®å½æ°(symbol)å åä½ç½®(æé)æ¾æå®å½æ°ådlsymè¿NULLå¼å¤æå½æ°å¦å使ç¨dlerrorå½æ°
4) dlclose
å½æ°ååï¼int dlclose(void *);
åè½æè¿°ï¼å·²ç»è£ è½½åºå¥æåå¥æåè³é¶å该åºå¸è½½åææå½æ°ådlcloseææå½æ°è°ç¨
3ã æ®éå½æ°è°ç¨
å¤æºç å®ä¾è¯´æåæºç æä»¶å ³ç³»ï¼
test_so1.htest_so1.cpptest_so1.soæåº
test_so2.htest_so2.cpptest_so2.soæåº
test_dl.cpptest_dlæ§è¡ç¨åºtest_dlédlopenç³»åçAPIå½æ°å¹¶ä½¿ç¨å½æ°æéè¾¾æè°ç¨åsoåºtestå½æ°ç®
-
exit()分析与利用
main()函数结束时,需要执行一些清理工作,源码因此内核层面的源码终止通过`exit`系统调用完成,这实际上是源码调用一个syscall,由libc实现。源码然而,源码副武器的源码直接调用`_exit()`可能导致stdout缓冲区的源码数据被内核立即释放,无法刷新,源码信息丢失。源码因此,源码调用`_exit()`前,源码需要在用户层面完成一些清理工作。源码libc中定义了`exit()`函数,源码其主要作用是源码进行用户层面的资源清理,最后调用`_exit()`进行系统级别的源码ai听写源码清理。
在pwn技术中,`_exit()`无法被利用,而`exit()`则提供了多种攻击点。因此,本文将深入分析libc中`exit()`函数的实现、相关机制以及利用方法。
分析`exit()`源码,源码编译鸿蒙了解libc是如何组织清理函数,并通过`run_exit_handlers()`函数处理这些清理函数。分析`__exit_funcs`链表,探讨是否有可能通过劫持该链表来实现特定函数的调用。进一步研究`__exit_funcs`是如何添加清理函数的,以及其中包含哪些函数。理解程序启动过程,fref指标源码包括ELF的入口点`_start()`和动态链接器ld.so.2的作用,以及`libc_start_main()`函数如何在`exit_funcs`中添加函数,并调用构造函数。
通过深入分析,了解`libc_start_main()`会在`exit_funcs`中放入`__libc_atexit`和构造函数。详细分析这三个关键要素,并讨论ELF的千蛛 源码`fini()`和`init()`函数的作用。理解`ld.so.2`中的`rtdl_fini()`函数如何处理清理工作,并指出其带来的利用可能性。
详细分析`rtdl_fini()`函数的实现和依赖的`rtld_global`数据结构,指出其攻击面。通过动态调试,明确如何劫持`rtld_global`中的函数指针,实现获取shell。进一步探讨如何利用`l_info`伪造`fini_array`节,将其迁移到可控制的位置,并在其中写入函数指针,实现多个函数的调用。
在劫持`fini_array`后,我们具备了连续调用多个函数的能力,探讨如何将这种能力与ROP相结合,完成复杂操作。分析`fini_array`中函数的调用过程,利用寄存器环境的稳定性和栈环境的特性,设计利用策略,如利用`gets()`和`setcontext`实现SROP。
利用`fini`段进行攻击相对简单,但只能执行一个函数,通常设置为`ogg`。通过修改`rtld_global`中的`l_info`指向`fini`段的函数指针,实现特定函数的调用。
回顾`exit()`函数的清理流程,除了调用清理函数链表外,还有调用`__libc_atexit`中的默认清理函数。总结分析内容,强调对清理机制的理解和利用方法。