乐趣区

关于java:Android-CC层hook和java层hook原理以及比较

作者:Denny Qiao(乔喜铭),云智慧 / 架构师。

云智慧团体成立于 2009 年,是全栈智能业务运维解决方案服务商。通过多年自主研发,公司造成了从 IT 运维、电力运维到 IoT 运维的产业布局,笼罩 ITOM、ITOA、ITSM、DevOps 以及 IoT 几大畛域,为金融、政府、运营商、能源、交通、制作等上百家行业的客户,提供了数字化运维体系建设及全生命周期运维治理解决方案。云智慧秉承 Make Digital Online 的使命,致力于通过先进的产品技术,为企业数字化转型和晋升 IT 经营效率继续赋能。

android java 层 hook 机制

android dalvic 虚拟机和 JVM 的区别

  1. Dalvik 虚拟机并不是依照 Java 虚拟机的标准来实现的,与 jvm 并不兼容
  2. Java 虚拟机运行的是 Java 字节码,而 Dalvik 虚拟机运行的则是其专有的文件格式 DEX(Dalvik Executable)
  3. Davic 读取的是 dex 文件,jvm 读取的.class 和 jar 文件
  4. Dalvik 基于寄存器,而 JVM 基于栈
  5. 每一个 Android 利用都运行在一个 Dalvik 虚拟机实例里,而每一个虚拟机实例都是一个独立的过程空间。虚拟机的线程机制,内存调配和治理,Mutex 等等都是依赖底层操作系统而实现的。所有 Android 利用的线程都对应一个 Linux 线程,虚拟机因此能够更多的依赖操作系统的线程调度和管理机制
  6. 有一个非凡的虚拟机过程 Zygote,他是虚拟机实例的孵化器。每当零碎要求执行一个 Android 应用程序,Zygote 就会 FORK 出一个子过程来执行该应用程序。它在系统启动的时候就会产生,它会实现虚拟机的初始化、库的加载、预置类库和初始化的操作。如果零碎须要一个新的虚拟机实例,它会迅速复制本身,以最快的速度提供给零碎

android 的启动流程

android 的编译结构图

android hook 原理

Javac 流程

Java 类文件是 8 位字节的二进制流

Android dalvik 虚拟机相比 jvm 有一个 dex 模块

目标是: 优化 class,减小体积,放慢加载运行速度,咱们 hook 的要害就是批改 class 文件,在原有 class 文件中减少,批改办法或者变量,以便退出咱们的 hook 代码到 class 中,主动埋点。在 android 中 hook 的入口点是 dex 模块。

批改 class 的关键技术:asm 框架

  • ASM 是一个 Java 字节码操控框架。它能被用来动静生成类或者加强既有类的性能。
  • ASM 能够间接产生二进制 class 文件,也能够在类被加载入 Java 虚拟机之前动静扭转类行为。
  • Java class 被存储在严格格局定义的.class 文件里,这些类文件领有足够的元数据来解析类中的所有元素:类名称、办法、属性以及 Java 字节码(指令)。
  • ASM 从类文件中读入信息后,可能扭转类行为,剖析类信息,甚至可能依据用户要求生成新类。

Android hook 的实现计划

  1. 间接批改 android SDK 中的 dex 模块 dx.jar,用 asm 批改 dx.jar 中加载 class 的入口 API,在函数中退出咱们 hook 机制代码,对每一个加载的 class 进行代码注入。最初以安装包的模式提供用户。

长处 :一劳永逸,实用于所有的 android 开发工具,适宜 eclipse,android studio,各种脚本编译等,开发工期短。 在初期,咱们采纳这种办法,很快实现了产品的开发,推向市场

毛病: 装置过程中须要替换用户 android sdk 中的 dx.jar 文件,属于侵入式装置,有一些用户不太承受。Android sdk 一直的降级,咱们也须要一直推出新的 sdk,降级保护比拟麻烦。

  1. 插件机制:须要实现不同的开发环境的插件:eclipse 插件,gradle 插件,各种自动化编译脚本的插件等。

基本原理: 在各个编译工具调用 dx 实现 dex 的过程中,通过编译环境提供的接口,调用咱们 class 注入代码。

长处: 用户应用比拟不便,不必批改用户 android SDk 环境,降级保护不便。比方 gradle 插件,版本放在 jcenter 仓库,间接配置就能够了。

实现计划的特点

针对各个开发环境,实现插件,在编译过程中对 class 文件进行 hook。这是一种动态 hook,不影响零碎运行效率,而且对 android 的零碎兼容性较好。

然而有一个 毛病,不能 hook android sdk,只能 hook sdk 之上的代码,那么随着不同模块代码的降级和扭转,咱们的 hook 代码就不得不随之扭转,而且须要一直适配新呈现的第三发功能模块。一直地推出新的 sdk 版本反对这种变动。须要降级,保护。代码体积以及内存,CPU 等性能逐步升高。

Android c/c++ hook

android 的 ndk 简介

NDK 是 Google 为 Android 进行本地开发而放出的一个本地开发工具,包含 Android 的 Na#ve API、公共库以及编译工具。

留神:NDK 须要 Android 1.5 版本以上的反对,NDK 与 SDK 是并列关系,DNK 是 SDK 的无效补充。

一个 android 工程 包含 2 局部:java 局部和 ndk 扩大

So 库文件构造

  • ELF 文件格式提供了两种视图,别离是链接视图和执行视图
  • 链接视图是以节(secXon)为单位,执行视图是以段(segment)为单位。链接视图就是在链接时用到的视图,而执行视图则是在执行时用到的视图。上图左侧的视角是从链接来看的,右侧的视角是执行来看的。

咱们比拟关注的是执行视图中,段中.rel.plt 项:重定位的中央在.got.plt 段内(留神也是.got 内, 具体辨别而已)。次要是针对内部函数符号,个别是函数。首次被调用时候重定位。首次调用时会重定位函数地址,把最终函数地址放到.got 内,当前读取该.got 就间接失去最终函数地址。

so hook 关注点

  • 导入表(GOT 表 hook),SO 援用内部函数的时候,在编译时会将内部函数的地址以 Stub 的模式寄存在.GOT 表中,加载时 linker 再进行重定位,行将实在的内部函数写到此 stub 中。
  • HOOK 的思路就是:替换 GOT 表中的内部函数地址。能够了解为 hook 导入函数。

So hook 根本流程:

  1. 通过读取 FILE *fd = fopen(“/proc/self/maps”,”r”) 内存映射表,找到 so 库在过程内存中的基地址。
  2. 通过基地址,读取并解析 SO 的构造,找到内部函数对应在 GOT 表中的寄存地址。
  3. 替换 GOT 表中的内部函数地址

NDK hook 的根本流程:

  • 次要原理:通过解析映射到内存中的 elf 的构造,解析出 got,而后进行 hook 重定位替换。其中必须要基于执行视图(ExecuXon View)进行符号解析;
  • ELF 文件格式是基于链接视图(Linking View),链接视图是基于节(SecXon)对 ELF 进行解析的。然而动态链接库在加载的过程中,linker 只关注 ELF 中的段(Segment)信息。

NDK hook 实现要害办法:

1、从给定的 so 中获取基址,获取 so 句柄 ElfHandle:ElfHandle* handle = openElfBySoname(soname);

2、从 segment 视图获取 elf 信息(即加载到内存的 so):getElfInfoBySegmentView(info, handle);

3、依据符号名寻找函数地址 Sym:findSymByName(info, symbol, &sym, &symidx);

4、遍历链表,进行一次替换 relplt 表函数地址操作,其中须要应用 mprotect 批改拜访内存,而后调用零碎指令 革除缓存:replaceFunc(addr, replace_func, old_func)

5、遍历链表,进行一次替换 reldyn 表函数地址操作,其中须要应用 mprotect 批改拜访内存,而后调用零碎指令 革除缓存:replaceFunc(addr, replace_func, old_func))

6、开释资源, 敞开 elf 句柄:closeElfBySoname(handle);

c/c++ 层与 java 层 hook 的比照

目前的 android hook 形式具备以下毛病:

  • 实现简单:须要反对各种开发环境,eclipse android studio,各种自动化编译工具,每种都比较复杂,开发和保护老本都比拟高。须要反对各种用户应用到的第三方库。
  • 集成降级和保护:用户集成比较复杂,降级比拟艰难,须要一直的适配新呈现的各种第三方库,因为咱们是对用户代码进行 hook,而不是 SDK。

下一代的 android agent 实现构想

以 android naXve sdk 的思路实现,动静 hook app。

  • 长处: 针对 android sdk 进行 hook,acXvity 事件,网络,线程,解体,anr 等间接在 android sdk 的根底上进行 hook,而不是针对用户 app 的实现代码进行 hook,这样就能够大大减少对第三方库新增,降级等问题的适配。缩小对系统资源的占用。
  • 集成形式: 透视宝 android sdk 的提供形式 so 库和 jar 包,以一般的 so 和 jar 的形式集成,不再须要各种集成插件的反对,反对网络动静降级和保护。
  • Hook 形式: 动静 hook,在 app 启动过程中进行 hook,能够各个性能点动态控制。
  • 性能: sdk 的体积会大大减少,对 CPU 的占用会升高
  • 兼容性: 当初的兼容性是对各个 android 零碎版本之间的兼容性,当前只须要对新呈现的 android 手机零碎进行适配。
  • 毛病: 技术难度减少,须要进行大量兼容性测试!

写在最初

近年来,在 AIOps 畛域疾速倒退的背景下,IT 工具、平台能力、解决方案、AI 场景及可用数据集的迫切需要在各行业爆发。基于此,云智慧在 2021 年 8 月公布了 AIOps 社区, 旨在树起一面开源旗号,为各行业客户、用户、研究者和开发者们构建沉闷的用户及开发者社区,独特奉献及解决行业难题、促成该畛域技术倒退。

社区先后 开源 了数据可视化编排平台 -FlyFish、运维治理平台 OMP 、云服务治理平台 - 摩尔平台、 Hours 算法等产品。

可视化编排平台 -FlyFish:

我的项目介绍:https://www.cloudwise.ai/flyF…

Github 地址:https://github.com/CloudWise-…

Gitee 地址:https://gitee.com/CloudWise/f…

行业案例:https://www.bilibili.com/vide…

局部大屏案例:

退出移动版