尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

编译引用 Android 隐藏 API 的完整套路:PI 的 stub 模块编译技巧深度剖析

编译引用 Android 隐藏 API 的完整套路:PI 的 stub 模块编译技巧深度剖析 编译引用 Android 隐藏 API 的完整套路PI 的 stub 模块编译技巧深度剖析【免费下载链接】PIPackageInstaller项目地址: https://gitcode.com/gh_mirrors/pi1/PIPI 是一款基于 PackageInstaller 的 Android 静默安装包管理工具。为了实现静默安装、深度查询系统包状态等功能它必须调用一批官方未开放的隐藏 API。本文带你深度剖析 PI 的完整套路用独立的 stub 模块声明隐藏 API 签名、配合 Refine 字节码重写与 HiddenApiBypass 运行时解锁让项目既能顺利编译又不会在运行时出冲突。一、为什么需要隐藏 API 的“替身”Android 对第三方应用只开放 public API。像ServiceManager、IPackageInstaller、AppOpsManager的部分常量这些隐藏 API存在两个经典难题编译期SDK 里没有这些符号直接引用会编译失败Lint 也会报RestrictedApi运行期Android 9 的隐藏 API 黑名单greylist/blacklist会拦截反射调用。PI 的思路是把两个问题拆开解决阶段手段作用编译期独立 stub 模块提供“长得和系统类一模一样”的替身骗过编译器运行期框架真实类 HiddenApiBypass替身不进包运行时用的是系统真实实现一句话编译时用假的运行时用真的这就是 stub 模块编译技巧的核心。二、模块结构stub 只编译、不打包在 settings.gradle.kts 中PI 声明了四个模块include(:stub, :core, :su, :app)依赖方向是这样的app ──compileOnly──▶ stub 编译替身 app ──implementation──▶ core / su core ──compileOnly──▶ stub core ──implementation──▶ refine-runtime关键在两个compileOnly(project(:stub))见app/build.gradle.kts第 88 行、core/build.gradle.kts第 16 行compileOnly意味着 stub 只参与编译不会被打包进 APK运行时这些android.os、android.content.pm包下的类由系统框架自己提供天然不会 DuplicateClass模块划分也干净stub 零业务逻辑core 放解析/委托逻辑su 放 Shizuku/LibSu 等提权通道su/src/main/kotlin/dev/sanmer/su/AnySu.kt。模块基础配置统一由约定式插件管理如build-logic/plugins/src/main/kotlin/LibraryConventionPlugin.kt统一设置了 compileSdk 37、minSdk 29、Java 21各模块 build 脚本因此非常干净。三、stub 的三种写法打开stub/src/main/java/目录结构直接照搬了 Android 框架包名android/app、android/os、android/content/pm、com/android/internal/app…这是刻意为之——包名类名必须和框架完全一致运行期反射与 Binder 才能无缝对上。1️⃣ 手写 AIDL 接口方法体统一 throw Stub以stub/src/main/java/android/content/pm/IPackageInstallerSession.java为例这是安装会话的 AIDL 接口PI 没有跑aidl工具而是把 AOSP 中 AIDL 生成的接口手工誊抄了一份public interface IPackageInstallerSession extends IInterface { ParcelFileDescriptor openWrite(String name, long offset, long length) throws RemoteException; void commit(IntentSender statusReceiver, boolean forTransferred) throws RemoteException; void abandon() throws RemoteException; abstract class Stub extends Binder implements IPackageInstallerSession { public static IPackageInstallerSession asInterface(IBinder obj) { throw new RuntimeException(Stub!); } } }注意细节有方法体的地方一律throw new RuntimeException(Stub!)如stub/src/main/java/android/os/ServiceManager.java的getService(String)、android/app/ActivityThread.java的currentApplication()。这是给“误调用”的保险丝——真被调到说明依赖配错立刻炸出来。2️⃣ RefineAs给系统类的“双胞胎”声明隐藏常量有些隐藏 API 是系统类里的常量或方法没法用接口表达。PI 用 Refine 框架的RefineAs注解解决看stub/src/main/java/android/content/pm/PackageManagerHidden.javaRefineAs(PackageManager.class) public class PackageManagerHidden { public static int INSTALL_REPLACE_EXISTING; public static int INSTALL_REQUEST_DOWNGRADE; RequiresApi(34) public static int INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK; }套路是新建一个XxxHidden类用RefineAs(真正的系统类.class)标记类里只声明你需要的隐藏字段/方法方法体同样 throw Stub业务代码正常 importXxxHidden使用有类型检查、有 IDE 提示全程无反射。原理是字节码重写stub 模块在stub/build.gradle.kts里挂了annotationProcessor(libs.rikka.refine.compiler)core 模块应用了alias(libs.plugins.rikka.refine)并implementation(refine-runtime)见core/build.gradle.kts。编译后所有指向PackageManagerHidden的调用会被改写成指向真正的android.content.pm.PackageManager运行时直接走框架实现。AppOpsManagerHiddenOP_REQUEST_INSTALL_PACKAGES等常量也是同一套路。3️⃣ 直接抄第三方库的类签名stub/里还有一份com/github/luben/zstd/ZstdInputStream.java——这是编译期的占位替身运行时由真实依赖提供。当某个类只在编译期需要、不想引入传递依赖时可以这样“借壳”。四、运行期配套HiddenApiBypass 是最后一块拼图只解决编译期还不够黑名单里的方法运行期照样被拦。PI 在app/build.gradle.kts第 104 行引入了hiddenapibypassimplementation(libs.hiddenApiBypass)App 启动时调用它的 unlock 接口解除黑名单限制配合前面两套编译技巧隐藏 API 才真正跑通。这就是“stub 编译 bypass 解锁”的完整闭环 ✅五、容易踩的坑ProGuard keep 规则Binder 回调是跨进程按接口名匹配的混淆一旦改了类名回调就会静默失效。PI 在core/proguard-rules.keep中针对性保留了所有回调 Stub 子类-keep,allowoptimization,allowobfuscation public class * extends com.android.internal.app.IAppOpsCallback$Stub { public methods; } -keep,allowoptimization,allowobfuscation public class * extends android.content.pm.IPackageInstallerCallback$Stub { public methods; } -keep,allowoptimization,allowobfuscation public class * extends android.content.IIntentSender$Stub { public methods; }用了allowoptimization,allowobfuscation的精细 keep既保住方法结构又允许字段混淆包体更省。⚠️ 凡是继承 stub 里$Stub的回调实现类都建议照此保留。六、可复用清单给你的项目也搭一套隐藏 API stub把 PI 的套路浓缩成 7 步可直接照做建独立模块如:stub业务模块只以compileOnly依赖它按框架原始包名建目录类名与系统类完全一致手写 AIDL 接口方法体一律throw new RuntimeException(Stub!)系统类的隐藏常量/方法用RefineAs写一个XxxHidden双胞胎类stub 模块接 Refine 注解处理器业务模块接 Refine 插件 runtime运行期引入 HiddenApiBypassApp 启动时 unlockProGuard 中 keep 所有*$Stub回调子类。验证标准构建零RestrictedApi报错、APK 里没有 stub 类、运行期无NoClassDefFoundError即代表这套隐藏 API 编译技巧配置成功 总结PI 的 stub 模块示范了编译引用 Android 隐藏 API 的标准解法替身管编译框架管运行Refine 管桥接Bypass 管解锁。模块边界清晰、风险点混淆、误调用都有兜底是一套值得收藏的完整套路。【免费下载链接】PIPackageInstaller项目地址: https://gitcode.com/gh_mirrors/pi1/PI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表