0x01 GNU ld.so动态库搜索路径

参考材料:https://en.wikipedia.org/wiki/Rpath

下面介绍GNU ld.so加载动态库的先后顺序:

  1. LD_PRELOAD环境变量指定的路径(一般对应文件/etc/ld.so.preload);

  2. ELF .dynamic节中DT_RPATH入口指定的路径,若DT_RUNPATH入口不存在的话;

  3. 环境变量LD_LIBRARY_PATH指定的路径,但如果可执行文件有setuid/setgid权限,则忽略这个路径;编译时指定--library-path会覆盖这个路径;

  4. ELF .dynamic节中DT_RUNPATH入口指定的路径;

  5. ldconfig缓存中的路径(一般对应/etc/ld.so.cache文件),若编译时使用了-z nodeflib的链接选项,则此步跳过;

  6. /lib,然后/usr/lib路径 ,若使用了-z nodeflib链接选项,则此步亦跳过;

0x02 原理分析

参考材料:http://linux.chinaunix.net/techdoc/system/2009/04/30/1109602.shtml

作者:alert7

从上面分析的搜索路径来看,DT_RPTAH先于/lib和/usr/lib,因此通过修改ELF,在.dynamic中加入DT_RPATH的入口,就可以让可执行文件优先加载我们的动态库,实现劫持的目的;

加入自定义的DT_RPTAH有两种方式,修改原有的DT_RPATH入口,插入新的DT_RPATH入口;一般ELF文件.dynamic中,都没有这一入口,因此选择新插入;

这里遇到2个问题,一是定位.dynamic位置,并插入新的entry;二是在ELF中插入我们HOOK用动态库路径;

现在解决第一个问题。

32位系统下,.dynamic入口由下面数据结构表示:

glibc-2.18/elf/elf.h

/* Dynamic section entry.  */
typedef struct
{
  Elf32_Sword d_tag;  /* Dynamic entry type */
  union
    {
      Elf32_Word d_val;  /* Integer value */
      Elf32_Addr d_ptr;  /* Address value */
    } d_un;
} Elf32_Dyn;

其中d_tag表示入口类型:

/* Legal values for d_tag (dynamic entry type).  */

#define DT_NULL      0      /* Marks end of dynamic section */
#define DT_NEEDED   1      /* Name of needed library */
#define DT_STRTAB   5      /* Address of string table */
#define DT_SYMTAB   6      /* Address of symbol table */
#define DT_RPATH   15      /* Library search path (deprecated) */
...

在.dynamic中,有许多未使用的入口,我们只需找到一处,写入即可;而ELF中,根据偏移定位某个节表比较容易的;

接下来解决第二个问题,将动态库路径加入ELF中;考虑到加入新的内容,ELF头等位置的偏移都要重新修正,因此最好的办法是修改一处已有字符串,我们选择修改__gmon_start__,因为它在所有程序中都有;

剩下的任务就是1.定位__gmon_start__并修改,2.返回其在字符串表中的index;

画了张图,帮助理解:

0x03 代码实现

首先实现DT_RPATH定位功能:

#define ERREXIT(err) do {perror(err);return -1;}while(1)

int elf_rpath_entry(const char *filename)
{
printf("+ enter elf_rpath_entry\n");
int fd = open(filename, O_RDONLY);
if (fd < 0) ERREXIT("open"); struct stat statbuf;
fstat(fd, &statbuf); char *fbase = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (fbase == NULL) ERREXIT("mmap"); Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fbase;
Elf32_Shdr *sects = (Elf32_Shdr *)(fbase + ehdr->e_shoff); int shsize = ehdr->e_shentsize;
int shnum = ehdr->e_shnum;
int shstrndx = ehdr->e_shstrndx; Elf32_Shdr *shstrsect = &sects[shstrndx]; 
char *shstrtab = fbase + shstrsect->sh_offset; int i;
int _sh_size, _sh_entsize;
int _sh_offset;
for(i = 0; i < shnum; i++) {
if(!strcmp(shstrtab + sects[i].sh_name, ".dynamic")) {
printf("+ found the .dynamic section\n");
_sh_size = sects[i].sh_size;
_sh_entsize = sects[i].sh_entsize;
_sh_offset = sects[i].sh_offset;
break;
}
} Elf32_Dyn *dyn = (Elf32_Dyn*)(fbase + _sh_offset); for (i = 0; i < _sh_size; i+=_sh_entsize) {
if (dyn->d_tag == DT_RPATH) {
printf("+ got DT_RPATH entry\n");
break;
}
dyn++;
} close(fd);
munmap(fbase, statbuf.st_size); printf("+ exit elf_rpath_entry\n");
return 0;
}

接下来,查找并修改__gmon_start__字符串,并返回其索引:

int modify_symbols(const char *fbase)
{
        Elf32_Ehdr *ehdr = (Elf32_Ehdr*)fbase;
        Elf32_Shdr *shdr = (Elf32_Shdr *)(fbase + ehdr->e_shoff);         Elf32_Shdr *shdrp = shdr;
        Elf32_Shdr *strsym = NULL;         int i;
        int find = 0;
        for(i = 0; i < ehdr->e_shnum; i++) {
                if(shdrp->sh_type == SHT_DYNSYM) {
                        find=1;
                        break;
                }
                shdrp++;
        }   
        if(!find) {
                printf("+ not find SHT_DYNSYM\n");
                return -1; 
        }   
        strsym = &shdr[shdrp->sh_link];         char *str = (char*)(fbase + strsym->sh_offset);         Elf32_Sym *symp;
        symp = (Elf32_Sym*)(fbase + shdrp->sh_offset);         for(i = 0; i < shdrp->sh_size; i += shdrp->sh_entsize) {
                if(!strcmp(&str[symp->st_name], "__gmon_start__")) {
                        /* modify here */
                        return symp->st_name;
                }
                symp++;
        }   
        printf("+ not find match symbol\n");         return -1; 
}

对于__gmon_start__符号的查找涉及3个部分,一是节区头部表,主要用来索引字符串表与符号表;符号表中通过索引,引用字符串中实际字符串,如symp->st_name实际只是索引;

下图帮助理解上述代码过程:

后门技术(HOOK篇)之DT_RPATH的更多相关文章

  1. 【权限维持】window服务端常见后门技术

    0x00 前言 未知攻焉知防,攻击者在获取服务器权限后,通常会用一些后门技术来维持服务器权限,服务器一旦被植入后门,攻击者如入无人之境.这里整理一些window服务端常见的后门技术,了解攻击者的常见后 ...

  2. 后门技术和Linux LKM Rootkit详解

    2010-01-15 10:32 chinaitlab chinaitlab 字号:T | T 在这篇文章里, 我们将看到各种不同的后门技术,特别是 Linux的可装载内核模块(LKM). 我们将会发 ...

  3. Android插件化技术——原理篇

    <Android插件化技术——原理篇>     转载:https://mp.weixin.qq.com/s/Uwr6Rimc7Gpnq4wMFZSAag?utm_source=androi ...

  4. iOS开发——网络使用技术OC篇&网络爬虫-使用正则表达式抓取网络数据

    网络爬虫-使用正则表达式抓取网络数据 关于网络数据抓取不仅仅在iOS开发中有,其他开发中也有,也叫网络爬虫,大致分为两种方式实现 1:正则表达 2:利用其他语言的工具包:java/Python 先来看 ...

  5. iOS开发之多线程技术——NSOperation篇

    本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...

  6. iOS开发之多线程技术——GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  7. android apk 防止反编译技术第一篇-加壳技术

    做android framework方面的工作将近三年的时间了,现在公司让做一下android apk安全方面的研究,于是最近就在网上找大量的资料来学习.现在将最近学习成果做一下整理总结.学习的这些成 ...

  8. iOS开发之多线程技术—GCD篇

    本篇将从四个方面对iOS开发中GCD的使用进行详尽的讲解: 一.什么是GCD 二.我们为什么要用GCD技术 三.在实际开发中如何使用GCD更好的实现我们的需求 一.Synchronous & ...

  9. android apk 防止反编译技术第二篇-运行时修改字节码

    上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372.接下来我们将介绍另一种防止a ...

随机推荐

  1. [转载]Python正则表达式匹配反斜杠'\'问题

    转载自csdnblog:Python正则表达式匹配反斜杠'\'问题 在学习Python正则式的过程中,有一个问题一直困扰我,如何去匹配一个反斜杠(即“\”)? 一.引入 在学习了Python特殊字符和 ...

  2. Python3+ssl实现加密通信

    一.说明 1. python标准库ssl可实现加密通信 2. ssl库底层使用openssl,做了面向对像化改造和简化,但还是可以明显看出openssl的痕迹 3. 本文先给出python实现的soc ...

  3. struts项目部署在Tomca上在断网情况下启动报错

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6015693.html 前段时间,项目部署到现场后,反馈Tomcat能正常启动,但是项目有时访问不了也不报错. ...

  4. 顺序容器----顺序容器操作,vector对象如何增长,额外的string操作,容器适配器

    一.顺序容器操作 1.向顺序容器添加元素 向顺序容器(array除外)添加元素的操作: 操作 说明 c.push_back(t) 在c的尾部创建一个值为t的元素.返回void c.emplace_ba ...

  5. ubuntu默认启动方式修改 psensor命令

    Check UUID sudo blkid Then sudo gedit /etc/default/grub & to pull up the boot loader configurati ...

  6. mac navicate 2013 - Lost connection to MySQL server at 'reading initial communication packet

    mac 本地mysql用navicate打开表时遇到如下错误: 2013 - Lost connection to MySQL server at 'reading initial communica ...

  7. 《Java面向对象编程》

    <Java面向对象编程> 第11章 对象的生命周期 11.1  创建对象的方式 用new语句创建对象 运用反射手段,调用java.lang.Class 或者 java.lang.Const ...

  8. Vue + Element UI 实现权限管理系统(动态加载菜单)

    动态加载菜单 之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的. 我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单. 接口 ...

  9. application Initialization设置导致处理程序ExtensionlessUrlHandler-Integrated-4.0在其模块列表中有一个错误模块问题的解决

    HTTP 错误 500.21 - Internal Server Error 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“Ma ...

  10. bzoj1239

    题解: 首先计算出两两之间的距离 然后二分答案 然后贪心判断是否可以放置少于等于k个 代码: #include<bits/stdc++.h> using namespace std; ; ...