如何在Android 12版本之后手机上使用hide的系统方法

2023-12-07  本文已影响0人  vb12
参考文章,

一种绕过Android P对非SDK接口限制的简单方法
另一种绕过 Android P以上非公开API限制的办法

背景

Android P 引入了针对非 SDK 接口(俗称为隐藏API)的使用限制。这是继 Android N上针对 NDK 中私有库的链接限制之后的又一次重大调整。从今以后,不论是native层的NDK还是 Java层的SDK,我们只能使用Google提供的、公开的标准接口

解决方案

对于在android14版本上, 我们的思路仍然是前言参考文章中的修改虚拟机类dalvik.system.VMRuntimesetHiddenApiExemptions()方法, 将要进行反射调用的函数进行豁免.
具体的原理, 上面的weishu大佬文章已经解释的很清楚了. 并且提供了一个项目:https://github.com/tiann/FreeReflection
具体实现方法有两种, 如下:

  1. 使用自加载dex代码, 调用其中的方法, 对dalvik.system.VMRuntimesetHiddenApiExemptions()方法进行反射调用. 从而对要反射调用的方法进行豁免. 比如我们的最终想要反射调用方法funcA(), 那么就可以把这个方法前面传给上面的setHiddenApiExemptions()方法. 这也是目前FreeReflection项目中使用的方式.
    这个方法依赖的是在代码中手工加载dex的思路, 在加载dex时, 不去设置classLoader, 从而让加载动作上升到boot classLoader中, 而由boot classloader加载的代码默认就由了系统权限. 从而可以在进行反射操作时绿灯大开.
 DexFile dexFile = new DexFile(code);
// 注意下面最后一个参数null, 此处就是classloader
 Class<?> bootstrapClass = dexFile.loadClass("me.weishu.reflection.BootstrapClass", null);

但是需要注意的是dexFile.loadClass()已经被标注为废弃, 未来很可能被删除.

  1. 在native层面hook修改Runtime结构体
    对于高版本, 比如android 12, 从native层修改Runtime结构体的hidden_api_policy_字段的方法没有在项目中体现. 项目中的unsealNative的方式是失败的. 主要是因为兼容性的问题, 每个android版本的Runtime结构体都不尽相同, 这里我主要针对android 12版本的Runtime结构体进行hook处理.
    代码:http://aospxref.com/android-12.0.0_r3/xref/art/runtime/runtime.h
// Android 12: http://aospxref.com/android-12.0.0_r3/xref/art/runtime/runtime.h
struct PartialRuntimeS {
    // Specifies target SDK version to allow workarounds for certain API levels.
    uint64_t monitor_timeout_ns_;
    bool is_profileable_from_shell_ = false;
    bool is_profileable_ = false;
    uint32_t zygote_max_failed_boots_;
    ExperimentalFlags experimental_flags_;
    std::string fingerprint_;
    void *oat_file_manager_;
    bool is_low_memory_mode_;
    bool madvise_random_access_;
    size_t madvise_willneed_total_dex_size_;
    size_t madvise_willneed_odex_filesize_;
    size_t madvise_willneed_art_filesize_;
    bool safe_mode_;

    // Whether access checks on hidden API should be performed.
    EnforcementPolicy hidden_api_policy_;
};

这里hook的锚点是monitor_timeout_ns_字段, 这个默认值为500000000, 从而可以确定offset. 但是android13, android14 对于Runtime结构体的定义有些许差异, 需要根据版本分开处理, 但原理是相同的.

int offsetOfMonitorNs 
   = findOffset(runtime, targetSdkVersionOffset, MAX, (uint64_t) 500000000);
int findOffset(void *start, int regionStart, int regionEnd, T value) {

    if (NULL == start || regionEnd <= 0 || regionStart < 0) {
        return -1;
    }
    char *c_start = (char *) start;

    for (int i = regionStart; i < regionEnd; i += 4) {
        T *current_value = (T *) (c_start + i);
        if (value == *current_value) {
            LOGV("found offset: %d", i);
            return i;
        }
    }
    return -2;
}

示例代码已经上传到github:
https://github.com/shaopx/SimpleReflectionAndroid12

上一篇下一篇

猜你喜欢

热点阅读