【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术

2024-03-23 18:58

本文主要是介绍【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57e3a3bc42eb88da6d4be143

作者:王赛

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 文件结构有一定的了解。

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); // 查找 SOif (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 文件,获得文件描述符 fdElfReader 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 文件装载到内存
2. 分配soinfo:调用 soinfo_alloc 函数为 SO 分配新的 soinfo 结构,并按照装载结果更新相应的成员变量
3. 链接: 调用 soinfo_link_image 完成 SO 的链接

通过前面的分析,可以看到, load_library 函数中包含了 SO 装载链接的主要过程, 后文主要通过分析 ElfReader 类和 soinfo_link_image 函数, 来分别介绍 SO 的装载和链接过程。

2.2 装载

在 load_library 中, 首先初始化 elf_reader 对象, 第一个参数为 SO 的名字, 第二个参数为文件描述符 fd:
ElfReader elf_reader(name, fd)
之后调用 ElfReader 的 load 方法装载 SO。

    ...// Read the ELF header and load the segments.if (!elf_reader.Load(extinfo)) {return NULL;}...

ElfReader::Load 方法如下:

bool ElfReader::Load(const Android_dlextinfo* extinfo) {return ReadElfHeader() &&             // 读取 elf headerVerifyElfHeader() &&           // 验证 elf headerReadProgramHeader() &&         // 读取 program headerReserveAddressSpace(extinfo) &&// 分配空间LoadSegments() &&              // 按照 program header 指示装载 segmentsFindPhdr();                    // 找到装载后的 phdr 地址
}

ElfReader::Load 方法首先读取 SO 的elf header,再对elf header进行验证,之后读取program header,根据program header 计算 SO 需要的内存大小并分配相应的空间,紧接着将 SO 按照以 segment 为单位装载到内存,最后在装载到内存的 SO 中找到program header,方便之后的链接过程使用。
下面深入 ElfReader 的这几个成员函数进行详细介绍。

2.2.1 read&verify elfheader
bool ElfReader::ReadElfHeader() {ssize_t rc = read(fd_, &header_, sizeof(header_));if (rc != sizeof(header_)) {return false;}return true;
}

ReadElfHeader 使用 read 直接从 SO 文件中将 elf_header 读取 header_ 中,header_ 为 ElfReader 的成员变量,类型为 Elf32_Ehdr,通过 header 可以方便的访问 elf header中各个字段,elf header中包含有 program header table、section

这篇关于【腾讯Bugly干货分享】Android Linker 与 SO 加壳技术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/839234

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

金融业开源技术 术语

金融业开源技术  术语 1  范围 本文件界定了金融业开源技术的常用术语。 本文件适用于金融业中涉及开源技术的相关标准及规范性文件制定和信息沟通等活动。

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出 在数字化时代,文本到语音(Text-to-Speech, TTS)技术已成为人机交互的关键桥梁,无论是为视障人士提供辅助阅读,还是为智能助手注入声音的灵魂,TTS 技术都扮演着至关重要的角色。从最初的拼接式方法到参数化技术,再到现今的深度学习解决方案,TTS 技术经历了一段长足的进步。这篇文章将带您穿越时

系统架构设计师: 信息安全技术

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师: 信息安全技术前言信息安全的基本要素:信息安全的范围:安全措施的目标:访问控制技术要素:访问控制包括:等保

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk