请选择 进入手机版 | 继续访问电脑版

[Android] Android11绕过反射限定 的方法

[复制链接]
查看57 | 回复5 | 2021-9-13 04:28:36 | 显示全部楼层 |阅读模式
目次

1. 题目 出现的背景

腾讯视频在集成我们 replay sdk 的时间 发现这么个错误,导致整个 db mock 功能完全失效。

  1. Accessing hidden field Landroid/database/sqlite/SQLiteCursor;
  2. ->mDriver:Landroid/database/sqlite/SQLiteCursorDriver; (greylist-max-o, reflection, denied)
  3. java.lang.NoSuchFieldException: No field mDriver in class Landroid/database/sqlite/SQLiteCursor;
  4. (declaration of 'android.database.sqlite.SQLiteCursor' appears in /system/framework/framework.jar)
复制代码

我清楚 的记得我们引入了一个第三方办理 方案,在 9.0 以上已经办理 了这个题目 ,大致的方案是如许 的:

  1. if (SDK_INT >= Build.VERSION_CODES.P) {
  2. try {
  3. Method forName = Class.class.getDeclaredMethod("forName", String.class);
  4. Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
  5. Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
  6. Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
  7. setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
  8. sVmRuntime = getRuntime.invoke(null);
  9. } catch (Throwable e) {
  10. Log.e(TAG, "reflect bootstrap failed:", e);
  11. }
  12. }
复制代码

吓得我赶紧去看下到底有没有猫腻,发如今 Android 11 上果然有题目 :

  1. Accessing hidden method Ldalvik/system/VMRuntime;
  2. ->setHiddenApiExemptions([Ljava/lang/String;)V (blacklist,core-platform-api, reflection, denied)
  3. Caused by: java.lang.NoSuchMethodException: dalvik.system.VMRuntime.setHiddenApiExemptions [class [Ljava.lang.String;]
  4. ......
复制代码

2. 分析题目 出现的缘故起因

本着时间紧使命 重只管 不影响进度的环境 下,我还是想去网上搜刮 看看,但是发现都是一堆旧的方案。必不得已 去看看到底为什么?到底为什么?刚好前几天找同事要了一份 Android 11 的源码。

  1. static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis, jstring name, jobjectArray args) {
  2. // ……
  3. Handle<mirror::Method> result = hs.NewHandle(
  4. mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize>(
  5. soa.Self(),
  6. klass,
  7. soa.Decode<mirror::String>(name),
  8. soa.Decode<mirror::ObjectArray<mirror::Class>>(args),
  9. GetHiddenapiAccessContextFunction(soa.Self())));
  10. if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
  11. return nullptr;
  12. }
  13. return soa.AddLocalReference<jobject>(result.Get());
  14. }
复制代码

假如 ShouldDenyAccessToMember 返回 true,那么就会返回 null,上层就会抛出方法找不到的非常 。这里和 Android P 没什么不同,只是把 ShouldBlockAccessToMember 改了个名而已。

ShouldDenyAccessToMember 会调用到 hiddenapi::ShouldDenyAccessToMember,该函数是如许 实现的:

  1. template<typename T>
  2. inline bool ShouldDenyAccessToMember(T* member,
  3. const std::function<AccessContext()>& fn_get_access_context,
  4. AccessMethod access_method)
  5. REQUIRES_SHARED(Locks::mutator_lock_) {
  6. const uint32_t runtime_flags = GetRuntimeFlags(member);
  7. // 1:如果该成员是公开API,直接通过
  8. if ((runtime_flags & kAccPublicApi) != 0) {
  9. return false;
  10. }
  11. // 2:不是公开API(即为隐藏API),获取调用者和被访问成员的 Domain
  12. // 主要看这个
  13. const AccessContext caller_context = fn_get_access_context();
  14. const AccessContext callee_context(member->GetDeclaringClass());
  15. // 3:如果调用者是可信的,直接返回
  16. if (caller_context.CanAlwaysAccess(callee_context)) {
  17. return false;
  18. }
  19. // ......
  20. }
复制代码

原来的方案失效了能在 FirstExternalCallerVisitor 的 VisitFrame 方法中找到答案

  1. bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
  2. ArtMethod *m = GetMethod();
  3. ......
  4. ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
  5. if (declaring_class->IsBootStrapClassLoaded()) {
  6. ......
  7. // 如果 PREVENT_META_REFLECTION_BLACKLIST_ACCESS 为 Enabled,跳过来自 java.lang.reflect.* 的访问
  8. // 系统对“套娃反射”的限制的关键就在此
  9. ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>();
  10. if (declaring_class->IsInSamePackage(proxy_class) && declaring_class != proxy_class) {
  11. if (Runtime::Current()->isChangeEnabled(kPreventMetaReflectionBlacklistAccess)) {
  12. return true;
  13. }
  14. }
  15. }
  16. caller = m;
  17. return false;
  18. }
复制代码

3. 办理 方案

  • native hook 住 ShouldDenyAccessToMember 方法,直接返回 false
  • 粉碎 调用堆栈绕过去,使 VM 无法辨认 调用方

我们采用的是第二种方案,有什么方法可以让 VM 无法辨认 我的调用栈呢?这可以通过 JniEnv::AttachCurrentThread(…) 函数创建一个新的 Thread 来完成。具体 我们可以看下这里 https://developer.android.com/training/articles/perf-jni ,然后共同 std::async(…)  与 std::async::get(..)  就能搞定了,下面是关键代码:

  1. // java 层直接用 jni 调用这个方法
  2. static jobject Java_getDeclaredMethod(
  3. JNIEnv *env,
  4. jclass interface,
  5. jobject clazz,
  6. jstring method_name,
  7. jobjectArray params) {
  8. // ...... 省掉一些转换代码
  9. // 先用 std::async 调用 getDeclaredMethod_internal 方法
  10. auto future = std::async(&getDeclaredMethod_internal, global_clazz,
  11. global_method_name,
  12. global_params);
  13. auto result = future.get();
  14. return result;
  15. }
  16. static jobject getDeclaredMethod_internal(
  17. jobject clazz,
  18. jstring method_name,
  19. jobjectArray params) {
  20. // 这里就是一些普通的 jni 操作了
  21. JNIEnv *env = attachCurrentThread();
  22. jclass clazz_class = env->GetObjectClass(clazz);
  23. jmethodID get_declared_method_id = env->GetMethodID(clazz_class, "getDeclaredMethod",
  24. "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
  25. jobject res = env->CallObjectMethod(clazz, get_declared_method_id,
  26. method_name, params);
  27. detachCurrentThread();
  28. return env->NewGlobalRef(res);
  29. }
  30. JNIEnv *attachCurrentThread() {
  31. JNIEnv *env;
  32. // AttachCurrentThread 核心在这里
  33. int res = _vm->AttachCurrentThread(&env, nullptr);
  34. return env;
  35. }
复制代码

到此这篇关于Android11绕过反射限定 的方法的文章就先容 到这了,更多相干 Android 绕过反射限定 内容请搜刮 脚本之家从前 的文章或继续欣赏 下面的相干 文章盼望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

avatar 牛股行天下烁 | 2021-9-22 10:28:44 | 显示全部楼层
admin楼主练了葵花宝典吧?
回复

使用道具 举报

avatar a18945178687 | 2021-9-24 01:57:30 | 显示全部楼层
admin楼主今年多大了?
回复

使用道具 举报

avatar 去火星三小时自 | 2021-10-4 09:50:25 | 显示全部楼层
感觉不错!
回复

使用道具 举报

avatar 平衡才能持久 | 2021-10-8 21:22:09 | 显示全部楼层
帖子很有深度!
回复

使用道具 举报

avatar bfdg3 | 2021-10-15 23:10:36 | 显示全部楼层
论坛的人气不行了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则