作者: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/

部分大屏案例:

Android C/C++层hook和java层hook原理以及比较的更多相关文章

  1. Android开发实践:Java层与Jni层的数组传递

    转载:http://www.linuxidc.com/Linux/2014-03/97561.htm Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是 ...

  2. Java层与Jni层的数组传递(转)

    源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...

  3. Android java层常见加密算法的hook自吐以及栈信息的打印

    杂谈:其实原理并没有很难,本质就是hook Android的框架层中的api将我们想要的key和iv(也可以没有,就打个比方),但是目前的话,很多厂家已经不在直接调用java层的这些加密算法的api了 ...

  4. android java层实现hook替换method

    Android上的热修复框架 AndFix 大家都很熟悉了,它的原理实际上很简单: 方法替换——Java层的每一个方法在虚拟机实现里面都对应着一个ArtMethod的结构体,只要把原方法的结构体内容替 ...

  5. Android JNI 由C/C++本地代码向Java层传递数据

    最近做的Android项目需要调用C代码,进行串口通信及与硬件设备通信,因此要用到JNI,其中本地代码需要向Java层返回三个参数,分别为 参数一:int型: 参数二: 通信指令,本地代码中为unsi ...

  6. cocos2d-x 通过JNI实现c/c++和Android的java层函数互调

    文章摘要: 本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数. (2)通过c++函数调用Android的java层函 ...

  7. Android中关于JNI 的学习(三)在JNI层訪问Java端对象

    前面两篇文章简介了JNI层跟Java层的一些相应关系,包含方法名,数据类型和方法名称等,相信在理论层面.可以非常好地帮助我们去了解JNI在Native本地开发中的作用,对JNI的一些概念也有了一个初步 ...

  8. Android Multimedia框架总结(十八)Camera2框架从Java层到C++层类关系

    Agenda: getSystemService(Context.CAMERA_SERVICE) CameraManager.getCameraIdList() ICameraService.aidl ...

  9. Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/52420803 前言:在上篇中,分析了MediaPl ...

随机推荐

  1. Docker容器入门介绍

    1.前言 Docker是一种新兴的虚拟化技术,能够一定程度上的代替传统虚拟机.不过,Docker 跟传统的虚拟化方式相比具有众多的优势.Docker: 本意是码头工人,言外之意是集装箱: Java号称 ...

  2. 关于如何让写自然溢出hash的无辜孩子见祖宗这件事

    关于如何让写自然溢出hash的无辜孩子见祖宗这件事 来源博客 这几天考试连着好几次被卡hash卡到死. 我谔谔,为什么连hash都要卡. 码力弱鸡什么时候才能站起来. 只需要任意两种字符,比如噫呜呜噫 ...

  3. CSC3100

    其实是存一下代码 1. AVL的java实现 维护一下每个点左右子树深度差,差绝对值大于2就转,转的方式和treap, splay转的方式差不多.旋转操作可以使两端差归零变得更平衡. 虽然平衡但转的次 ...

  4. 27.Java 飞机游戏小项目

    开篇 游戏项目基本功能开发 飞机类设计 炮弹类设计 碰撞检测设计 爆炸效果的实现 其他功能 计时功能 游戏项目基本功能开发 这里将会一步步实现游戏项目的基本功能. 使用 AWT 技术画出游戏主窗口 A ...

  5. 使用Web Deploy自动打包发布

    在内部测试阶段,经常改一点小东西需要更新给测试继续测试.然后就需要频繁的找到对应更改的视图/JS文件,或者是编译的dll文件,再打开测试服务器找到对应站点替换进去,整套流程下来就非常的繁琐费时. 使用 ...

  6. MM32F0140的复位脚nRST复用成普通GPIO PA10功能

    目录: 1.MM32F0020简介 2.MM32F0020的复位脚nRST和PA10的说明 3.MM32F0020的选项字节说明 4.MM32F0020的FLASH_OBR选项字节寄存器说明 5.MM ...

  7. XML约束DTD

    <元素1> <元素2> <元素3>描述1</元素3> <元素4>描述2</元素4> </元素2> </元素1& ...

  8. C++11最常用的新特性如下

    1.auto关键字:编译器可以根据初始值自动推导出类型.但是不能用于函数传参.定义数组以及非静态成员变量. 2.nullptr关键字:是一种特殊类型的字面值,它可以被转换成任意其它类型的指针:而NUL ...

  9. 三、MyCat主要配置介绍

    一.配置文件 1.server.xml Mycat的配置文件,设置账号.参数等2.schema.xml Mycat对应的物理数据库和数据库表的配置3.rule.xml Mycat分片(分库分表)规则 ...

  10. 什么是可重入锁(ReentrantLock)?

    举例来说明锁的可重入性 public class UnReentrant{ Lock lock = new Lock(); public void outer(){ lock.lock(); inne ...