您的位置:  首页 > 技术 > 前端 > 正文

Android C/C++层hook和java层hook原理以及比较

2022-04-18 17:00 https://my.oschina.net/yunzhihui/blog/5515524 云智慧AIOps社区 次阅读 条评论
作者: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/flyFish.html
Github地址: https://github.com/CloudWise-OpenSource/FlyFish
Gitee地址: https://gitee.com/CloudWise/fly-fish
行业案例:https://www.bilibili.com/video/BV1z44y1n77Y/
部分大屏案例:
 
展开阅读全文                                    
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接