插件化/热修复

发布时间:2024年01月23日

1、如何规避Android P对私有API的访问限制

● Android:Pie — 9.0 — 28
● 一般都是通过反射访问私有 API

1.1、私有API

Android源码查看网址
在这里插入图片描述

(1)hide public

在这里插入图片描述
hide public方法无法直接使用,可以自行编译系统源码,并导入项目工程,从而访问到。
比如 convertFromTranslucent() 是 Acticity 中的方法,我们可以直接把 Activity 的源码放到工程里,就可以访问到这个方法。
(android.jar编译的Activity中没有convertFromTranslucent()方法,我们可以自己搞一个privaded.jar把系统源码搞过来,就可以骗过编译器,运行时加载的那个类里面肯定是有这个方法的)

(2)private

在这里插入图片描述

private 彻底访问不到,只能通过反射。

Method initMethod = AssetManager.class.getDeclaredMethod("init");
initMethod.setAccessible(true);

反射:1)不仅可以绕过访问权限控制 2)还可以修改final变量

1.2、Android P 的API名单

在这里插入图片描述

● 白名单中的API:谁都能用
● 浅灰名单中的API:反射可用
● 深灰名单中的API:SDK < 28,允许使用;SDK >= 28,不允许使用,同黑名单
● 黑名单中的API:反射不可用。如 getDeclaredField()、getDeclaredMethod() 获取不到任何东西

1.3、Android P对反射做了什么

在这里插入图片描述

在这里插入图片描述

  • 如果 action == kDeny,就会返回 true,就会 block

在这里插入图片描述

  • 有三个 return,只要让这三个 return 的返回值不是 kDeny 就不会 block

(1)第一个 hook 点

在这里插入图片描述

在这里插入图片描述

● GetActionFromAccessFlags() 中,如果是白名单 kWhitelist,就返回 kAllow
● 否则,获取 policy,如果 policy 是 kNoChecks,就返回 kAllow

在这里插入图片描述

● GetHiddenApiEnforcementPolicy() 返回的是一个 Runtime 里的成员 hidden_api_policy_
● 只要能拿到 Runtime 就可以把它篡改掉

修改 Runtime 的 hidden_api_policy

在这里插入图片描述

在这里插入图片描述

● javaVM 我们可以拿到,在写 JNI 的时候就会经常遇到 javaVM
● 要把 javaVM 强转成 JavaVMExt,然后通过指针获取到 runtime
● 但是 JavaVMExt 是系统代码里的,我们拿不到

在这里插入图片描述

● JavaVMExt 继承自 JavaVM,JavaVMExt 中只有两个成员变量,一个是父类继承过来的 JNIInvokeInterface*,一个是自己的 Runtime,剩下的都是函数
● 我们可以利用C++的特性,自己定义一个结构体 struct JavaVMExt,就两个成员,一个叫 functions,一个叫 runtime,管你是什么类型,直接定义成任意类型 void*,后面我想要什么类型时就强转成什么类型,这样就可以拿到 Runtime,这就是 C++
● 需要注意,JavaVMExt 中没有虚方法表,否则自定义的 struct JavaVMExt 结构体中还需要加一个虚方法表的指针

在这里插入图片描述

● 我们的 runtime 是 void*,想要 Runtime 类型是拿不到的,因为 Runtime 是定义在系统源码里的
● 我们自己定义一个 PartialRuntime
● C++ 结构体中的变量都是4个字节4个字节的一个个排下来的,runtime 的指针指向这个结构体的第一个成员,那我们就一个个往下数,直到数到 target_sdk_version,target_sdk_version 我们是知道的,就是我们定义在 build.gradle(:app) 中的 api 版本,比如28。只要数到一个值是28,那么就是 target_sdk_version,就把这个地址作为 PartialRuntime 的起点,然后依次往后数,数到 EnforcementPolicy 就可以了

在这里插入图片描述

  • EnforcementPolicy,ExperimentalFlags 等可以直接自己定义

在这里插入图片描述

  • 找的代码也很简单,就是一个 for 循环,每次 +4,因为是4个字节
hook流程总结

在这里插入图片描述

● 首先拿到 javaVM 的指针:一种方式是从 JNI_ON_LOAD 拿,这个代码一定是个 so 库;另一种方式是直接通过 JNI_ENV去get。此处采用的是方式二
● 然后将拿到的 javaVM 强转成自己定义的 JavaVMExt
● 于是就可以拿到我们定义的 runtime,但它是一个 void *
● 然后我们通过 findOffset() 4个字节4个字节的数到 targetSdkVersion 的地址(指针)
● 于是我们就可以把 targetSdkVersion 指针强转成我们定义的 PartialRuntime*
● 于是就可以获取到 hidden_api_policy_,并对其进行修改

(2)第二个 hook 点

在这里插入图片描述

  • fn_caller_is_trusted():如果是一个信任的调用者就没问题,通常是系统类

在这里插入图片描述

class loader是空,就返回true

【方式 1】Java 反射

在这里插入图片描述

  • classLoader在浅灰名单中,可以通过反射修改

【方式 2】C++

在这里插入图片描述

  • Java的Class对应着Native层的一个struct Class,将他的classLoader置为空即可

注意:
ClassLoader 置空只限于你使用的这一个类,如果想让所有类都可以访问私有API,那么就要将所有类的ClassLoader 置空,工作量比较大

(3)第三个 hook 点

在这里插入图片描述

在这里插入图片描述

● GetHiddenApiExemptions()就是豁免了,就是前两个条件没有满足,但到第三个条件时,被豁免了,直接返回kAllow。一般是给合作的厂商豁免
● 想要在此处Hook只需要修改runtime中的hidden_api_exemptions,跟第一个Hook点的思想是一模一样的

2、VirtualApk实现插件化

  • 如何实现类加载
  • 如何实现资源加载
  • 如何实现对四大组件的支持

2.1、VirtualApk

在这里插入图片描述

● VirtualApk本身就是一个app,只不过它具有加载其他app的能力的代码,如加载类加载资源等
● 每个插件都是独立的Apk,他们之间通过隔离的方式互相不可见。但VirtualApk并不是完全不可见,完全不可见的是DroidPlugin

在这里插入图片描述

3、Tinker实现热修复

4、Shadow实现插件化

文章来源:https://blog.csdn.net/weixin_41733225/article/details/135775461
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。