Android反射@hide API 方法、变量,支持Android11和Android12

这篇具有很好参考价值的文章主要介绍了Android反射@hide API 方法、变量,支持Android11和Android12。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android源码中现在有大量的方法和变量被@hide所修饰,而这些被hide修饰的方法和变量是不允许应用层进行反射获取的,所以富有探索精神的程序员们就开始想尽各种办法绕过系统hide限制来使用@hide修饰的方法和变量。

1、套娃(适配Android10即之前)

Android11之前我们可以使用套娃的形式来欺骗系统,让系统误以为是系统调用的hide方法。而到了Android11之后,套娃就已经失效了喽,要寻找新的方法来和系统对抗。

  1. 我们通过反射 API 拿到 getDeclaredMethod 方法。getDeclaredMethod 是 public 的,不存在问题;这个通过反射拿到的方法我们称之为元反射方法。

  1. 我们通过刚刚反射拿到元反射方法去反射调用 getDeclardMethod。这里我们就实现了以系统身份去反射的目的——反射相关的 API 都是系统类,因此我们的元反射方法也是被系统类加载的方法;所以我们的元反射方法调用的 getDeclardMethod 会被认为是系统调用的,可以反射任意的方法。

例子:

Method metaGetDeclaredMethod =
        Class.class.getDeclaredMethod("getDeclardMethod"); // 公开API,无问题
Method hiddenMethod = metaGetDeclaredMethod.invoke(hiddenClass,
        "hiddenMethod", "hiddenMethod参数列表"); // 系统类通过反射使用隐藏 API,检查直接通过。
hiddenMethod.invoke // 正确找到 Method 直接反射调用

代表:FreeReflection

2、源码分析

而目前的Android11和Android12系统修复了这个漏洞,套娃无法在继续使用。

所以我们只能另辟蹊径。

系统在判断调用者的时候是通过调用栈来判断调用者的方向的,所以只要我们在调用栈上做手脚,让系统误以为不是应用层的调用栈,即可绕过@hide限制。

static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis, jstring name, jobjectArray args) {
  // ……
  Handle<mirror::Method> result = hs.NewHandle(
      mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize>(
          soa.Self(),
          klass,
          soa.Decode<mirror::String>(name),
          soa.Decode<mirror::ObjectArray<mirror::Class>>(args),
          GetHiddenapiAccessContextFunction(soa.Self())));
  if (result == nullptr || ShouldDenyAccessToMember(result->GetArtMethod(), soa.Self())) {
    return nullptr;
  }
  return soa.AddLocalReference<jobject>(result.Get());
}

如果ShouldDenyAccessToMember返回true,则getDeclaredMethodInternal会返回null,则上层会抛出异常。

bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
    ArtMethod *m = GetMethod();
    ......
    ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
    if (declaring_class->IsBootStrapClassLoaded()) {
        ......
        // 如果 PREVENT_META_REFLECTION_BLACKLIST_ACCESS 为 Enabled,跳过来自 java.lang.reflect.* 的访问
        // 系统对“套娃反射”的限制的关键就在此
        ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>();
        if (declaring_class->IsInSamePackage(proxy_class) && declaring_class != proxy_class) {
            if (Runtime::Current()->isChangeEnabled(kPreventMetaReflectionBlacklistAccess)) {
                return true;
            }
        }
    }

    caller = m;
    return false;
}

套娃为什么会失效,原因就在VisitFrame中

3、重点来了--解决方案(适配Anroid11&Android12)

我们解决方法的方向就是破坏调用堆栈,让系统无法识别api的真正调用者。

具体做法:

  1. 通过在jni层创建线程来执行真正的反射操作,当然,只是这样还不足以欺骗系统。

  1. 通过对线程调用attachthread方法来改变调用堆栈,从而达到欺骗系统的目的。google对attachthread的部分讲解:https://developer.android.com/training/articles/perf-jni?hl=zh-cn

4、源码

话不多说,直接上源码:

1、通过async来创建线程,因为async可以返回future来把异步同步化,线程内执行getDeclaredField_internal

Java_com_macoli_reflect_1helper_NativeReflect_getDeclaredField(JNIEnv *env, jobject t,
                                                               jclass clz, jstring fieldName) {
    auto global_clazz = env->NewGlobalRef(clz);
    jstring global_method_name = static_cast<jstring>(env->NewGlobalRef(fieldName)) ;
    //通过async来创建线程,因为async可以返回future来把异步同步化,线程内执行getDeclaredField_internal
    auto future = std::async(&getDeclaredField_internal, global_clazz, global_method_name);
    auto result = future.get();

    env->DeleteGlobalRef(global_clazz) ;
    env->DeleteGlobalRef(global_method_name) ;

    return result ;
}

2、真正执行反射操作

关键:attachCurrentThread()来对调用堆栈进行转变。


JNIEnv *attachCurrentThread() {
    JNIEnv *env;
    int res = _vm->AttachCurrentThread(&env, nullptr);
    __android_log_print(ANDROID_LOG_DEBUG, "native", "Found attached %d", res);
    return env;
}

void detachCurrentThread() {
    _vm->DetachCurrentThread();
}


static jobject getDeclaredField_internal(jobject object, jstring field_name) {

    JNIEnv *env = attachCurrentThread();//这里是重点

    jclass clazz_class = env->GetObjectClass(object);
    jmethodID methodId = env->GetMethodID(clazz_class, "getDeclaredField",
                                          "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
    jobject res = env->CallObjectMethod(object, methodId, field_name);
    jobject global_res = nullptr;
    if (res != nullptr) {
        global_res = env->NewGlobalRef(res);
    }

    detachCurrentThread();
    return global_res;
}

测试:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.reflect_btn).setOnClickListener(v -> {
            try {

                 /** {@hide} */
                 /*
                public void setTraceTag(long traceTag) {
                    mTraceTag = traceTag;
                }
                * */
                Method m = ReflectHelper.getDeclaredMethod(Looper.class , "setTraceTag" , new Class[]{long.class}) ;
                m.invoke(Looper.getMainLooper() , 1000) ;
                Log.d("gggl" , "setTraceTag " + m.toString()) ;

                Class<?> activityThreadCls = Class.forName("android.app.ActivityThread") ;
                Field f = ReflectHelper.getDeclaredField(activityThreadCls , "DEBUG_BROADCAST") ;
                Object tag = f.get(null) ;
                Log.d("gggl" , f.toString()) ;
                Log.d("gggl" , tag.toString()) ;
//                CpuUsageInfo cpuUsageInfo = new CpuUsageInfo() ;
                /** @hide */
                /*public CpuUsageInfo(long activeTime, long totalTime) {
                    mActive = activeTime;
                    mTotal = totalTime;
                }*/
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    Constructor cpuUsageInfoConstructor = ReflectHelper.getDeclaredConstructor(CpuUsageInfo.class , new Class[]{long.class , long.class}) ;
                    Object cpuUsageObj = cpuUsageInfoConstructor.newInstance(100 , 100) ;
                    Method getTotalM = CpuUsageInfo.class.getDeclaredMethod("getTotal") ;
                    Object r = getTotalM.invoke(cpuUsageObj) ;
                    Log.d("gggl" , "getTotal = " + r) ;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

华为mate 40 pro 测试结果:

Android反射@hide API 方法、变量,支持Android11和Android12

总结:

源码已上传到gitee:https://gitee.com/gggl/reflect_helper

Android反射@hide API 方法、变量,支持Android11和Android12

反射Android @hide api 适配

Android11&Android12文章来源地址https://www.toymoban.com/news/detail-507349.html

到了这里,关于Android反射@hide API 方法、变量,支持Android11和Android12的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android多屏幕支持-Android12

    android12-release AOSP 文档 心主题 多屏幕概览 术语 在这些文章中,主屏幕和辅助屏幕的定义如下: 主(默认)屏幕的 屏幕 ID 为 DEFAULT_DISPLAY 辅助屏幕的 屏幕 ID 不是 DEFAULT_DISPLAY 主题区域 文章 开发和测试 推荐做法 测试和开发环境 常见问题解答 相关文章集 显示 系统装饰支持

    2024年02月13日
    浏览(39)
  • Android文件选择器 路径选择 支持安卓4.4 ~ 13 支持Android/data目录访问 支持SD卡 适配Android11

    Android上进行文件选择或操作的第三方库,自动申请存储权限,支持 Android4.4 ~ 13,再也不用为了适配各种版本而苦恼了,快速集成,一句代码搞定,完善的文档,支持无root权限访问和操作Android/data和Android/obb目录(适配Android 13),支持SD卡,高度自定义UI满足你的所有需求,使用非常

    2024年02月04日
    浏览(43)
  • 关于Android 11、12和13服务保活问题

    物联网环境,为了解决不同厂商、不同设备、不同网络情况下使用顺畅,同时也考虑到节约成本,缩小应用体积的好处,我们需要一个服务应用一直存在系统中,保活它以提供服务给其他客户端调用。 开机自启动,通过广播通信, 必要权限 开机自启动Service相关代码 注意

    2023年04月08日
    浏览(87)
  • Android RK3588-12 hdmi-in Camera方式最大支持3个

      hdmi-in Camera最大支持3个     modified:   hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp     modified:   hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp     modified:   hardware/interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h     modified:

    2024年02月08日
    浏览(49)
  • 11、Java 变量作用域、构造方法官方教程

    Java 中的变量有3种: 📖 ① 全局变量:被定义在类中( 成员变量 ) 📖 ② 局部变量: 被定义在成员方法、代码块、静态代码块中定义的变量 📖 ③ 参数:方法声明中的变量 There are several kinds of variables (变量): 📋 Member variables (成员变量) in a class:these are called fields(属

    2023年04月08日
    浏览(36)
  • 无涯教程-jQuery - hide( speed, callback)方法函数

    hide(speed,[callback])方法使用优美的动画隐藏所有匹配的元素,并在完成后触发可选的回调。 这是此方法使用的所有参数的描述- speed      -  代表三个预定义速度(\\\"slow\\\",\\\"normal\\\"或\\\"fast\\\")之一或运行动画的毫秒数(如1000)的字符串)。 callback -  这是可选参数,表示动画制作完成后要

    2024年02月15日
    浏览(41)
  • 让chrome支持小于12px-的文字方式(多种方法)

    Chrome 中文版浏览器会默认设定页面的最小字号是12px,英文版没有限制 原由 Chrome 团队认为汉字小于12px就会增加识别难度 中文版浏览器 与网页语言无关,取决于用户在Chrome的设置里(chrome://settings/languages)把哪种语言设置为默认显示语言 系统级最小字号 浏览器默认设定页面

    2024年02月20日
    浏览(38)
  • 【flink番外篇】9、Flink Table API 支持的操作示例(12)- Over Windows(有界和无界的over window)操作

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年02月02日
    浏览(51)
  • 【flink番外篇】9、Flink Table API 支持的操作示例(11)- Group Windows(tumbling、sliding和session)操作

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年02月01日
    浏览(48)
  • 如何通过Android平台的API实现5G网络的支持 安卓系统版本和5g网络相关【一】

    前面分享了两篇5G基带相关的移植修改博文。 安卓高通机型的基带移植 修改 编译的相关 增加信号 支持5G等【一】 安卓高通机型的基带移植 修改 编译的相关 增加信号 支持5G等【二】 今天的帖子聊聊安卓版本与5G网络与机型和修改之间相关的话题。众所周知,目前的机型基本

    2024年02月09日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包