当前位置: 首页 > 后端技术 > Java

AndroidC-C++层hook与java层hook原理及对比

时间:2023-04-01 19:40:56 Java

作者:DennyQiao(乔希铭),云智/架构师。云智集团成立于2009年,是一家全栈智能业务运维解决方案提供商。公司经过多年自主研发,形成了从IT运维、电力运维到物联网运维的产业布局,涵盖ITOM、ITOA、ITSM、DevOps和IoT,服务于金融、政府、运营商、能源、交通、制造等数百个行业客户提供了数字化运维体系建设和全生命周期运维管理解决方案。秉承让数字在线的使命,云智慧致力于通过先进的产品技术持续赋能企业数字化转型,提升IT运营效率。androidjava层钩子机制androiddalvic虚拟机与JVM的区别是其专有的文件格式DEX(DalvikExecutable)。Davic读取dex文件,jvm读取.class和jar文件。Dalvik是基于寄存器的,而JVM是基于栈的。每个Android应用程序都在Dalvik虚拟机实例上运行,并且每个虚拟机实例都是一个独立的进程空间。虚拟机的线程机制、内存分配与管理、Mutex等都是依赖底层操作系统实现的。所有的Android应用线程都对应一个Linux线程,所以虚拟机可以更多的依赖操作系统的线程调度和管理机制。有一个特殊的虚拟机进程Zygote,它是虚拟机实例的孵化器。每当系统请求执行一个Android应用程序时,Zygote就会FORK一个子进程来执行该应用程序。它会在系统启动时生成,完成虚拟机的初始化、库的加载、预设的类库和初始化。如果系统需要一个新的虚拟机实例,它会迅速复制自己并以最快的速度提供给系统。与jvm相比,dalvik虚拟机多了一个dex模块。目的是:优化类,减少体积,加快加载和运行速度。我们的hook的关键是修改class文件,在原来的class文件中添加,修改方法或者变量,从而将我们的Hook代码添加到类中,自动嵌入。android中钩子的入口点是dex模块。修改类的关键技术:asm框架ASM是一个Java字节码操作框架。它可用于动态生成类或增强现有类的功能。ASM可以直接生成二进制类文件,也可以在类加载到Java虚拟机之前动态改变类的行为。Java类存储在严格格式化的.class文件中,这些文件具有足够的元数据来解析类中的所有元素:类名、方法、属性和Java字节码(指令)。ASM从类文件中读取信息后,可以改变类行为,分析类信息,甚至可以根据用户要求生成新的类。Androidhook的实现方案直接修改androidSDK中的dex模块dx.jar,使用asm修改dx.jar中加载类的入口API,在函数中加入我们的hook机制代码,对每一个加载的进行代码注入班级。最后以安装包的形式提供给用户。优点:一劳永逸,适用于所有android开发工具,适用于eclipse、androidstudio、各种脚本编译等,开发周期短。早期,我们采用这种方式,很快就完成了产品开发并推向市场。缺点:安装过程中需要替换用户androidsdk中的dx.jar文件,属于侵入式安装,部分用户不接受。Androidsdk不断升级,我们也需要不断推出新的sdk,升级维护起来比较麻烦。插件机制:需要实现不同开发环境的插件:eclipse插件、gradle插件、各种自动编译脚本的插件等基本原理:在调用dx的过程中完成dex各个编译工具,通过编译环境提供的接口调用我们的类注入代码。优点:用户使用更方便,无需修改用户的androidSDK环境,升级维护方便。比如gradle插件,版本放在jcenter仓库,直接配置即可。实现方案的特点针对各个开发环境,实现插件化,在编译过程中hook类文件。这是一个静态钩子,不影响系统的运行效率,对android系统有更好的兼容性。但是有一个缺点,不能hookandroidsdk,只能hooksdk上面的代码,那么随着不同模块代码的升级和变化,我们的hook代码也要随之变化,需要不断适应到新兴的第三方发送功能模块。不断发布新的SDK版本以支持此更改。需要升级,维护。代码大小、内存和CPU性能逐渐下降。Androidc/c++hookandroid'sndk介绍NDK是Google发布的用于Android本地开发的本地开发工具,包括Android的Na#veAPI、公共库和编译工具。注意:NDK需要Android1.5以上版本的支持。NDK和SDK是并行的关系,DNK是SDK的有效补充。一个android工程包括两部分:java部分和ndk扩展的So库文件结构。ELF文件格式提供了两种视图,即链接视图和执行视图。)为单位。链接视图是链接时使用的视图,执行视图是执行时使用的视图。上图中左边的视角是从链接上看的,右边的视角是从执行上看的。我们比较关注的是executionview中section中的.rel.plt项:重定位的地方在.got.pltsection中(注意也是在.got中,区分一下即可)。主要为外部函数符号,一般是函数。第一次调用时重新定位。第一次调用时,会重定位函数地址,最终函数地址放在.got中,读取.got后直接获取最终函数地址。sohook专注于导入表(GOTtablehook)。当SO引用外部函数时,外部函数的地址在编译时会以Stub的形式存储在.GOT表中。外部函数写入此存根。HOOK的思路是:替换GOT表中的外部函数地址。可以理解为一个钩子导入函数。Sohook的基本流程:通过读取FILE*fd=fopen("/proc/self/maps","r")的内存映射表找到so库在进程内存中的基地址。通过基地址,读取并解析SO结构,找到GOT表中外部函数对应的存储地址。GOT表NDK钩子替换外部函数地址的基本流程:主要原理:通过解析映射到内存的elf结构,解析got,然后进行钩子重定位替换。其中,符号分析必须基于执行视图(ExecuXonView);ELF文件格式基于链接视图(LinkingView),链接视图基于节(SecXon)分析ELF。但是,在动态链接库的加载过程中,链接器只关注ELF中的段(Segment)信息。NDKhook实现的关键方法:1.从给定的so中获取基地址,获取so句柄ElfHandle:ElfHandle*handle=openElfBySoname(soname);2.从segmentview中获取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层hooks的比较。自动编译工具有3种,每种都比较复杂,开发维护成本也比较高。需要支持各种用户使用的第三方库。集成升级维护:用户集成更复杂,升级难度更大。需要不断适配各种新兴的第三方库,因为我们hook的是用户代码,而不是SDK。下一代androidagent是用androidnaXvesdk的思想实现的,动态hookapp。优点:对androidsdk的hook,acXvity事件,网络,线程,crash,anr等都是在androidsdk的基础上直接hook,而不是对用户app的实现代码进行hook,可以大大减少对new的需求第三方库的添加、升级等适配问题。减少对系统资源的占用。集成方式:透视宝androidsdk提供so库和jar包的方式,以普通so和jar的方式集成,不再需要各种集成插件的支持,支持网络动态升级维护。Hook方法:动态hook,在app启动过程中被hook,可以被各个功能点动态控制。性能:SDK的体积会大大减小,CPU占用率会降低兼容??性:目前的兼容性是各个android系统版本之间的兼容性,以后只需要对新的android手机系统进行适配即可。缺点:增加技术难度,需要大量的兼容性测试!写在最后近年来,在AIOps领域高速发展的背景下,各行业对IT工具、平台能力、解决方案、AI场景和可用数据集的迫切需求呈爆发式增长。基于此,云智于2021年8月发布了AIOps社区,旨在竖起开源大旗,为各行业的客户、用户、研究人员和开发者打造一个活跃的用户和开发者社区,共同贡献和解决行业问题。问题,促进该领域的技术发展。社区先后开源了数据可视化编排平台——FlyFish、运维管理平台OMP、云服务管理平台——Moore平台、Hours算法等产品。视觉编排平台-FlyFish:项目介绍:https://www.cloudwise.ai/flyF...Github地址:https://github.com/CloudWise-...Gitee地址:https://gitee.com/CloudWise/f...行业案例:https://www.bilibili.com/video...部分大屏案例: