Android C /C++レイヤーフックとJavaレイヤーフックの原理と比較

著者:Denny Qiao(Qiao Ximing)、Cloud Wisdom/Architect。

2009年に設立されたCloudWisdomGroupは、フルスタックのインテリジェントなビジネス運用および保守ソリューションプロバイダーです。長年の独立した研究開発の後、同社はITの運用と保守、電力の運用と保守からIoTの運用と保守に至るまで、ITOM、ITOA、ITSM、DevOps、IoTのいくつかの主要分野をカバーし、金融にサービスを提供する産業レイアウトを形成しました。政府、オペレーター、エネルギー、輸送、製造業などの数百の業界の顧客が、デジタル運用および保守システムの構築と、ライフサイクル全体の運用および保守管理ソリューションを提供してきました。Cloud Wisdomは、Make Digital Onlineの使命を順守し、高度な製品テクノロジーを通じて企業のデジタルトランスフォーメーションを継続的に強化し、IT運用効率を向上させることに取り組んでいます。

AndroidのJavaレイヤーフックメカニズム

androiddalvic仮想マシンとJVMの違い

  1. Dalvik仮想マシンは、Java仮想マシンの仕様に従って実装されておらず、jvmと互換性がありません。
  2. Java仮想マシンはJavaバイトコードを実行し、Dalvik仮想マシンは独自のファイル形式DEX(Dalvik Executable)を実行します
  3. Davicはdexファイルを読み取り、jvmは.classファイルとjarファイルを読み取ります
  4. Dalvikはレジスタベースであり、JVMはスタックベースです。
  5. 各AndroidアプリケーションはDalvik仮想マシンインスタンスで実行され、各仮想マシンインスタンスは独立したプロセススペースです。仮想マシンのスレッドメカニズム、メモリの割り当てと管理、ミューテックスなどはすべて、基盤となるオペレーティングシステムに応じて実装されます。すべてのAndroidアプリケーションスレッドはLinuxスレッドに対応しているため、仮想マシンはオペレーティングシステムのスレッドスケジューリングと管理メカニズムにさらに依存できます。
  6. 特別な仮想マシンプロセスであるZygoteがあります。これは、仮想マシンインスタンスのインキュベーターです。システムがAndroidアプリケーションの実行を要求するたびに、Zygoteはアプリケーションを実行するための子プロセスをforkします。システムの起動時に生成され、仮想マシンの初期化、ライブラリのロード、プリセットクラスライブラリ、および初期化が完了します。システムに新しい仮想マシンインスタンスが必要な場合は、システム自体をすばやく複製し、可能な限り迅速にシステムに提供します。

アンドロイドの起動プロセス

Androidコンパイル構造図

アンドロイドフックの原則

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:

项目介绍:www.cloudwise.ai/flyFish.htm…

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

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

行业案例:www.bilibili.com/video/BV1z4…

部分大屏案例:

おすすめ

転載: juejin.im/post/7087860699740766216