Android Linker与SO加壳技术

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Android Linker与SO加壳技术

1. 前言

Android 系统安全愈发重要,像传统pc安全的可执行文件加固一

样,应用加固是Android系统安全中非常重要的一环。目前

Android 应用加固可以分为dex加固和Native加固,Native 加

固的保护对象为Native 层的SO 文件,使用加壳、反调试、混

淆、VM 等手段增加SO文件的反编译难度。目前最主流的SO 文

件保护方案还是加壳技术,在SO文件加壳和脱壳的攻防技术领

域,最重要的基础的便是对于Linker 即装载链接机制的理解。对

于非安全方向开发者,深刻理解系统的装载与链接机制也是进阶的

必要条件。

本文详细分析了Linker 对SO 文件的装载和链接过程,最后对SO 加壳的关键技术进行了简要的介绍。

对于Linker 的学习,还应该包括Linker 自举、可执行文件的加载等技术,但是限于本人的技术水平,本文的讨论范围限定在SO 文件的加载,也就是在调用dlopen("libxx.SO")之后,Linker 的处理过程。

本文基于Android 5.0 AOSP 源码,仅针对ARM 平台,为了增强可读性,文中列举的源码均经过删减,去除了其他CPU 架构的相关源码以及错误处理。

P.S. :阅读本文的读者需要对ELF 文件结构有一定的了解。

PP.S.:腾讯御安全,一站式解决安全问题,有android app 安全加固需求的同学欢迎联系我们,官方网站:

2. SO 的装载与链接

2.1 整体流程说明

1. do_dlopen

调用dl_open 后,中间经过dlopen_ext, 到达第一个主要函数do_dlopen:

soinfo* do_dlopen(const char* name, int flags, const Android_dlextinfo* extinfo) {

protect_data(PROT_READ | PROT_WRITE);

soinfo* si = find_library(name, flags, extinfo); // 查找 SO

if (si != NULL) {

si->CallConstructors(); // 调用 SO 的 init 函数

}

protect_data(PROT_READ);

return si;

}

do_dlopen 调用了两个重要的函数,第一个是find_library, 第二个是soinfo 的成员函数CallConstructors,find_library 函数是SO 装载链接的后续函数,完成SO 的装载链接后,通过CallConstructors 调用SO 的初始化函数。

2. find_library_internal

find_library 直接调用了find_library_internal,下面直接看find_library_internal函数:

static soinfo* find_library_internal(const char* name, int dlflags, const Android_dlextinfo* extinfo) {

if (name == NULL) {

return somain;

}

soinfo* si = find_loaded_library_by_name(name); // 判断 SO 是否已经加载if (si == NULL) {

TRACE("[ '%s' has not been found by name. Trying harder...]", name); si = load_library(name, dlflags, extinfo); // 继续 SO 的加载流程 }

if (si != NULL && (si->flags & FLAG_LINKED) == 0) {

DL_ERR("recursive link to \"%s\"", si->name);

return NULL;

}

return si;

}

find_library_internal 首先通过find_loaded_library_by_name 函数判断目标SO 是否已经加载,如果已经加载则直接返回对应的soinfo指针,没有加载的话则调用load_library 继续加载流程,下面看load_library 函数。

3. load_library

static soinfo* load_library(const char* name, int dlflags, const Android_dlextinfo* extinfo) {

int fd = -1;

...

// Open the file.

fd = open_library(name); // 打开 SO 文件,获得文件描述符fd

ElfReader elf_reader(name, fd); // 创建 ElfReader 对象

...

// Read the ELF header and load the segments.

if (!elf_reader.Load(extinfo)) { // 使用 ElfReader 的 Load 方法,完成 SO 装载

return NULL;

}

soinfo* si = soinfo_alloc(SEARCH_NAME(name), &file_stat); // 为 SO 分配新的 soinfo 结构

if (si == NULL) {

return NULL;

}

si->base = elf_reader.load_start(); // 根据装载结果,更新 soinfo 的成员变量

si->size = elf_reader.load_size();

si->load_bias = elf_reader.load_bias();

si->phnum = elf_reader.phdr_count();

si->phdr = elf_reader.loaded_phdr();

...

if (!soinfo_link_image(si, extinfo)) { // 调用 soinfo_link_image 完成 SO 的链接过程

soinfo_free(si);

return NULL;

}

return si;

}

load_library 函数呈现了SO 装载链接的整个流程,主要有3步:

1.装载:创建ElfReader对象,通过ElfReader 对象的Load 方法将SO

文件装载到内存

相关文档
最新文档