不能访问的类或者接口

Android 有两种类型的 API 不能通过 SDK 访问。一种是在 com.android.internal 包中的 API(源码路径为framework/base/core/)。另一种是被标记为 @hide 属性的类和接口。

对于internal API来说,从来都没有计划将其开放出来。它就是Android的“内部厨房”,对开发者来说,应该将其视作黑盒。

Hidden API之所以被隐藏,是想阻止开发者使用SDK中那些未完成或不稳定的部分(接口或类),因为其可能会在后续的版本中被修改或者移除。

当使用 Android SDK 进行开发的时候,应用默认引用了 android.jar,它位于 sdk-platform-{android版本}-android.jar。SDK 中默认移除了所有的被@hide标识的接口或者类以及 internal 包下的类。

反射

// 当需要实现的功能比较多的时候,需要反射的类和方法就会变得很复杂和繁琐,除非实在没办法,尽量不选择该方式

// 此处跳过

原始android.jar

我们需要修改android.jar,这样它才能包含所有的*.class文件,包括internal和hidden API类,这里我们使用比较简单的方式

github上已经有提供了众多版本完整的android.jar包https://github.com/anggrayudi/android-hidden-api

下载地址转移到谷歌硬盘了

https://drive.google.com/drive/folders/17oMwQ0xBcSGn159mgbqxcXXEcneUmnph

下载android.jar后,替换掉 Android SDK (<SDK location>/platforms/)下面的 jar ,例如android-30/android.jar,build.gradle文件中compileSdkVersion , targetSdkVersion修改为30(因为这里是android-30),最好先备份一下原始的 jar,重新编译工程或者重启 Studio 就行了

可以看到这里就不再爆红了

也能够点击进去查看internal源代码

进行系统签名

我们的APP还需要有系统权限,由于我的测试设备已经ROOT了,所以现在还需要让APK进行系统签名,获取系统级权限,不然我们还是用不了internal方法

设置sharedUserId

通过设置同一个User id使得多个应用可以运行在同一个进程中,这里我们将sharedUserId设置成android.uid.system则可以将该应用和系统应用运行在同一进程中,则拥有了系统权限

AndroidManifest.xml添加sharedUserId

android:sharedUserId="android.uid.system"

如果现在直接编译生成APK安装会出现一个报错

INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: Reconciliation failed

这是由Android的安全机制导致的错误,因为不可能我们随便写一个sharedUserId,就能够和另外的APK在一个进程中了,这样进程之间的隔离又会出现安全隐患,所以在Android中

使用同一个sharedUserId的应用,需要使用同一个签名文件

Android原生签名文件

这里我们是想和系统应用运行在同一个进程中,所以需要找到android原生应用相同的签名

访问https://android.googlesource.com/platform/build/+/donut-release/target/product/security

我们需要的是这两个签名文件

点击tgz就能够对这些文件进行下载

另外我们还需要下载keytool签名工具: https://github.com/getfatday/keytool-importkeypair

都搞定之后,为了方便查看,创建一个signAPK文件夹来放置这些签名文件

生成签名文件

再编写一个shell脚本signature文件来方便直接生成签名,文件内容为

./keytool-importkeypair -k test.jks -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias test
  • test.jks 生成签名文件的名称
  • 123456 是签名的密码
  • test 是签名的别名

双击脚本生成签名文件

AndroidStudio引入签名文件

在AndroidStudio中引入签名文件

先把test.jks丢到项目根目录下

build.gradle进行引入

signingConfigs {
    debug {
        keyAlias 'test'
        keyPassword '123456'
        storeFile file('../test.jks')
        storePassword '123456'
    }
    release {
        keyAlias 'test'
        keyPassword '123456'
        storeFile file('../test.jks')
        storePassword '123456'
    }
}

然后Sync一下,现在Build APK生成的APK文件就是拥有系统签名的了,同时我们可以调用internal相关文件了

检查功能

当然口说无凭,所以我们还是想检查一下是不是真的可以调用internal文件,这里写了一个小demo,主要功能调用查看一些com.android.internal.os.PowerProfile获取的值

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button testbutton = findViewById(R.id.testbutton);
    testbutton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            BatteryStatsHelper mStatsHelper = new BatteryStatsHelper(MainActivity.this, true);
            Bundle nall=null;
            mStatsHelper.create(nall);
            mStatsHelper.clearStats();
            final PowerProfile powerProfile = mStatsHelper.getPowerProfile();
            Log.i(TAG,"powerProfile is "+powerProfile.toString());
            Log.i(TAG,"powerProfile is "+powerProfile.getBatteryCapacity());

            final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
            Log.i(TAG,"averagePower is "+averagePower);
            //                Toast.makeText(MainActivity.this, (int) averagePower, Toast.LENGTH_LONG).show();
        }
    });
}

编译之后安装到手机上

adb install app-debug.apk

点击运行测试,adb连接电脑之后输出日志

运行成功并输出结果

整个过程中的一些报错解决

编译的时候出现了报错,部分错误如下:

Failed to transform file 'android.jar' to match attributes {artifactType=android-mockable-jar

搜索之后发现是gradle plugin插件版本过高的原因,原来我是3.4.1,现在降到3.0.0试试

修改之后出现新报错

ERROR: Unable to find method 'org.gradle.api.tasks.compile.CompileOptions.setBootClasspath

原来gradle和插件版本是有对应关系的

https://developer.android.google.cn/studio/releases/gradle-plugin#updating-plugin

我这里的插件用的是3.0.0,所以对应的gradle版本应该需要降到4.1以下,(当然也可以选择升级插件版本来解决报错)

修改gradle-wrapper.properties文件

出现新报错

Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing META-INF/versions/9/module-info.class

解决方法

  • 使用JDK9
  • 删除module-info.class 文件。(这个方法应该不是对每个人都有效,报错日志里明确指出了该文件报错,可以使用 WinRAR 打开 jar 包,进入对应的目录删除报错的文件,再重新在项目中依赖,如果编译不报错就可行)

我选择第二种方法

然后编译就没问题了,成功打出apk包

END

建了一个微信的安全交流群,欢迎添加我微信备注进群,一起来聊天吹水哇,以及一个会发布安全相关内容的公众号,欢迎关注 ????

如何使用internal或者@hide的类-小白菜博客
GIF