首页
社区
课程
招聘
[原创] 基于Bionic/linker修改, 实现无痕 so_loader...
发表于: 2017-3-6 00:32 13151

[原创] 基于Bionic/linker修改, 实现无痕 so_loader...

2017-3-6 00:32
13151

最近研究了一些防内存检测方面的姿势, 异常so模块检测在对抗中占了挺重要的部分. 由于`Bionic/linker`完全是一个用户态的实现, 所以就想着对linker的代码做一番改造, 实现一个自己的so loader, 目的是隐藏so模块,躲过检测.


目前遍历进程内已加载模块的方法大概有两个:

  遍历soinfo->next(本身为一个环形链表).

  读取/proc/pid/maps.


涉及的核心逻辑主要在: linker.cpp与linker_phdr.cpp两个文件中, linker_phdr.cpp负责elf内存的映射与读取, linker.cpp主要负责对数据进行展开和初始化.

linker里面涉及的引用比较多,弄了很久才剥离出来,最后修修补补,提取出了以下几个必须的文件:

    elf_machdep.h 

    exec_elf.h 

    linker.cpp 

    linker.h 

    linker_phdr.cpp 

    linker_phdr.h 


在linker中是不允许调用malloc,free等函数的. 这是因为linker作为第一个被加载的模块(早于libc.so),所以可用资源方面比较严苛, 从代码中的一段注释可以得知原因:


 */


虽然上面列举了linker中的诸多限制, 但是这仅仅是对于原生linker而言. 而我们自己改造的linker在使用时周围的资源已经是非常丰富了, libc等各种库基本都已经加载完毕. 所以可以放开手脚的干一番. 废话不多, 下面开始干活.

第一步: 改造各种输出宏定义.

linker中有很多不同种类的调试信息输出宏, 我并不想一次性删除, 因为这些输出对后面的调错还有很大帮助, 毕竟linker里的逻辑还是比较复杂的. 我全部都用__android_log_print():



第二步: 替换DT_NEED的依赖加载

在static bool soinfo_link_image(soinfo* si)函数的后半段,有一处代码是遍历DT_NEED并加载依赖库的代码,这里将代码直接替换成dlopen(), 调用原生linker来加载依赖库.


  }


修改后为:

    }


第三步: 去除soinfo链.

该链作为原生linker中的一条很关键的结构, 每个加载的soinfo都会被串到这条链上来. 去除soinfo链后我们加载的模块就无法被通过遍历soinfo链表检测到. 

先删除掉以下变量定义, 编译一把使引用部位报错, 然后一点点清理.


一处关键的引用在函数soinfo_alloc中, 这里用于分配新的soinfo空间:



由于我们剥离了全局的soinfo链, 所以这里清理掉相关代码, 直接用malloc代替, 修改后的soinfo_alloc如下:



第四步: 从/proc/pid/maps中隐藏map信息

很多的对抗行为都发生在/proc/pid/目录下, 对于模块检测来说maps一定是非常重要的检测点. 所以下面我们修改代码, 不让模块信息出现在maps中. 

首先理清原理: 之所以能在maps文件中看到模块信息, 是因为linker在加载so时使用mmap(xx, xx, xx, xx, fd_, xx)映射了so文件的fd(文件描述符). 这个操作会被内核记录下来体现在maps中:



下面我们必须改变直接映射fd的方式, 并且还不影响原有功能, 思路为: 先mmap一块无fd内存, 然后使用read读出so指定偏移内容填充到mmap的内存处, 最后将mmap的内存属性设置为segment的属性. 代码如下:



具体思路如上, nexus 5+ 4.4.4下测试通过. 对linker了解不深, 如果有偏差和错误还请大家指正. 附上代码:~


/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
 *
 * Do NOT use malloc() and friends or pthread_*() code here.
 * Don't use printf() either; it's caused mysterious memory
 * corruption in the past.
 * The linker runs before we bring up libc and it's easiest
 * to make sure it does not depend on any complex libc features
 *
 * open issues / todo:
 *
 * - are we doing everything we should for ARM_COPY relocations?
 * - cleaner error reporting
 * - after linking, set as much stuff as possible to READONLY
 *   and NOEXEC
// linker.h#define DL_ERR(x...) __android_log_print(ANDROID_LOG_DEBUG, "linker_ERR", x);
#define DL_WARN(fmt, x...) __android_log_print(ANDROID_LOG_DEBUG, "linker_WARN", fmt, x);
#define DL_TRACE(fmt, x...) __android_log_print(ANDROID_LOG_DEBUG, "linker_TRACE", fmt, x);
#define TRACE_TYPE(x, y...) __android_log_print(ANDROID_LOG_DEBUG, "linker_TRACE_TYPE", y);
#define DEBUG(x...) __android_log_print(ANDROID_LOG_DEBUG, "linker_DEBUG", x);
#define INFO(x...) __android_log_print(ANDROID_LOG_DEBUG, "linker_INFO", x);
#define LOOKUP 1  // 某个宏...作用忘了#define __libc_format_buffer(b, s, f, p...) sprintf(b, f, p);     // 这里用sprintf代替, 否则就要把libc里面的一大堆文件剥离出来, 不建议入坑.
// linker.cpp
  if (dynamic != NULL) {
    for (Elf32_Dyn* d = dynamic; d->d_tag != DT_NULL; ++d) {
      if (d->d_tag == DT_NEEDED) {
        const char* library_name = strtab + d->d_un.d_val;
        TRACE("\"%s\": calling constructors in DT_NEEDED \"%s\"", name, library_name);
        find_loaded_library(library_name)->CallConstructors();
      }
    }
    for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        if (d->d_tag == DT_NEEDED) {
            const char* library_name = si->strtab + d->d_un.d_val;
            DEBUG("%s needs %s", si->name, library_name);

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 4
支持
分享
最新回复 (9)
雪    币: 9479
活跃值: (757)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
建议代码用C++重新排下版,没有背景色。
2017-3-6 04:26
0
雪    币: 4
活跃值: (327)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
全平台上不好整,2.x-7.x soinfo 的结构略有差别,还不谈国产化的一对破设备,这条路会搞死你
2017-3-6 09:40
0
雪    币: 158
活跃值: (196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
加油楼主
2017-3-6 09:59
0
雪    币: 93
活跃值: (136)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
如果国产自修改rom,兼容性要死吧。。。
2017-3-6 10:22
0
雪    币: 148
活跃值: (278)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
N年前就搞了,内存加载而已
2017-3-6 14:43
0
雪    币: 53
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
这个东西很多年前就有加固厂商在用了,不过貌似兼容性是个大坑,所以现在流行得还是加壳和混淆。
2017-3-6 16:12
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
不错的思路
2017-3-7 09:35
0
雪    币: 900
活跃值: (96)
能力值: ( LV3,RANK:26 )
在线值:
发帖
回帖
粉丝
9
9.0上无法运行,而且缺少很多代码
2019-11-4 17:15
0
雪    币: 237
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
改dlopen、malloc有什么作用?脱裤子放屁
2021-7-20 16:03
0
游客
登录 | 注册 方可回帖
返回
//