Comment contourner la liste noire des API cachées sur Android 9+

Google a introduit des restrictions dans Android 9 sur lesquelles les API peuvent être accessibles aux développeurs. Voici comment contourner ces restrictions cachées de l'API.

En 2018, Google a lancé Android Pie. Parmi les modifications de l’interface utilisateur et les nouvelles fonctionnalités, il y a également eu quelques modifications du côté des développeurs. Ces modifications comprenaient de nouvelles API, des corrections de bugs pour les API existantes, ainsi que restrictions d'accès aux API cachées.

Heureusement, il existe des moyens de contourner ces restrictions. Avant d'expliquer comment contourner les restrictions, je dois expliquer un peu ce que sont les API cachées, pourquoi elles ont été restreintes en premier lieu et pourquoi vous souhaiterez peut-être y accéder.

Les API cachées sont les API d'Android que les développeurs d'applications ne peuvent normalement pas voir. Si vous jetez un œil au code d'AOSP, vous verrez tout un tas de classes, de variables et de méthodes qui ont un @hide annotation à l’intérieur d’un bloc de commentaires au-dessus d’eux.

Cette annotation indique à l'outil utilisé par Google lors de la compilation du SDK d'exclure l'élément qui s'y trouve. Ce SDK est ensuite distribué aux développeurs dans les SDK téléchargés via Android Studio. À moins que vous n'utilisiez un SDK modifié, Android Studio pensera qu'aucun de ces éléments cachés n'existe tout simplement pas. Si vous essayez d'en utiliser un directement, il l'affichera en rouge et refusera de compiler.

Il existe de nombreuses raisons pour lesquelles une API peut être masquée. Certaines choses sont uniquement destinées à être utilisées par des applications internes ou système et ne fonctionneront pas si elles sont utilisées par une application tierce. D'autres sont expérimentaux ou instables et pourraient être supprimés ou modifiés à l'avenir. Certaines ne sont même que des API que Google ne veut tout simplement pas appliquer au cycle de dépréciation normal si elles sont un jour supprimées.

Bien que le SDK Android standard ait un parcelle dedans, parfois ce n'est pas suffisant. Parfois, vous souhaitez faire quelque chose qui existe déjà dans Android, mais qui n'est tout simplement pas exposé publiquement.

Par exemple, la plupart des applications que je crée, notamment Tuner d'interface utilisateur système et Widgets d'écran de verrouillage, utilisez un tas de différentes API cachées. SystemUI Tuner doit accéder à certaines pour suivre, modifier et réinitialiser correctement les options. Lockscreen Widgets en utilise certains pour afficher le fond d'écran en dessous, entre autres.

La plupart des développeurs n'ont pas besoin d'accéder aux API cachées, mais elles peuvent parfois s'avérer très utiles.

Avec la sortie d'Android 9 (Pie), Google a introduit la liste noire des API cachées. Toutes les API cachées n'étaient pas incluses et il existait différents niveaux de listes. Les API cachées sur la liste blanche sont accessibles à tous. Les API cachées sur la liste gris clair sont accessibles par n'importe quelle application, mais pourraient être inaccessibles dans les futures versions d'Android. Tout ce qui figure sur la liste gris foncé n'est accessible qu'aux applications ciblant les niveaux d'API antérieurs à Pie (c'est-à-dire avant le niveau d'API 28). Les applications ciblant Pie et versions ultérieures se verraient refuser l’accès. Enfin, les API masquées sur la liste noire ne pouvaient être accessibles par aucune application non système (ou non sur liste blanche), quelle que soit l'API cible.

Android 10 a modifié la façon dont les listes étaient organisées et les a légèrement simplifiées, mais l'idée est restée la même. Certaines API cachées étaient accessibles aux applications tandis que d'autres étaient bloquées. Android 11 renforcé la détection d'accès à bloquer un contournement utilisé pour Pie et 10.

Dans toutes les versions d'Android, chaque fois qu'une application tierce tente d'accéder à une API cachée sur liste noire, Android génère l'erreur « introuvable » appropriée.

Il existe en fait plusieurs façons de contourner la liste noire des API cachées. En fonction de vos besoins, vous pouvez choisir ceux qui fonctionnent pour toutes les versions d'Android, ceux qui fonctionnent uniquement pour Android 9 et 10, ceux qui utilisent du code C++ natif et ceux qui sont entièrement basés sur Java. Il existe même une solution de contournement réservée au développement utilisant ADB.

Solution de contournement de la BAD

Si votre appareil exécute Android Pie, exécutez les deux commandes ADB suivantes pour activer l'accès à l'API masquée.

adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1

Si votre appareil exécute Android 10 ou une version ultérieure, exécutez la commande ADB suivante pour activer l'accès à l'API masquée.

adb shell settings put global hidden_api_policy 1

Pour revenir au comportement par défaut, remplacez simplement put avec delete et retirez le 1.

Évidemment, ces commandes ne sont pas vraiment utiles pour une application de production. Je peux vous dire de première main qu'il est incroyablement difficile d'instruire correctement les utilisateurs sur la façon d'utiliser ADB. Mais ils peuvent être utiles si vous devez mettre à jour une ancienne application pour vous conformer aux nouvelles restrictions.

Solution de contournement native/JNI

Il existe deux manières de contourner la liste noire des API cachées à l'aide de JNI dans votre application Android. L’un fonctionne pour Android 9 et 10, et l’autre fonctionne pour Android 9 et versions ultérieures.

Android 9 et 10

Si vous disposez déjà d’une partie native de votre application, cela sera facile à mettre en œuvre. Utilisez simplement le JNI_OnLoad() fonction.

art statique: Runtime* runtime = nullptr ;

extern "C"jint JNI_OnLoad(JavaVM *vm, void *reserved){
...
runtime = reinterpret_cast<: javavmext>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art:: hiddenapi:: EnforcementPolicy:: kNoChecks);
...
}

Sachez que cette méthode ne fonctionne que sur Android 9 et 10.

Android 9 et versions ultérieures

Pour n'importe quelle version d'Android, vous avez le choix entre deux bibliothèques pour contourner la restriction cachée de l'API: FreeReflection et RestrictionBypass.

Les deux sont faciles à mettre en œuvre et à utiliser.

Pour implémenter FreeReflection, ajoutez la dépendance à votre build.gradle au niveau du module.

implementation 'me.weishu: free_reflection: 3.0.1'

Puis remplacez attachBaseContext() dans votre classe Application.

@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);
Reflection.unseal(base);
}

Si vous n'avez pas de classe Application, vous pouvez l'ajouter assez facilement. Créer une nouvelle classe qui s'étend Application puis pointez-le dans votre AndroidManifest.xml.

Exemple:

publicclassAppextendsApplication{
...
@Override
protectedvoidattachBaseContext(Context base){
super.attachBaseContext(base);

Reflection.unseal(base);
}
}

<manifest>
...
...
name=".App">
...
application>
manifest>

Pour implémenter RestrictionBypass, ajoutez le référentiel JitPack à votre build.gradle au niveau du projet.

allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}

Ajoutez ensuite la dépendance à votre build.gradle au niveau du module.

implementation 'com.github.ChickenHook: RestrictionBypass: 2.2'

Et c'est tout. Cette bibliothèque supprime automatiquement les restrictions de la liste noire.

Solution de contournement Java

Bien que les solutions JNI soient efficaces, il peut arriver que vous ne souhaitiez pas utiliser de code natif. Si vous ne faites pas déjà des choses en C++, cela peut ajouter une taille inutile, ainsi que des restrictions de plate-forme, à votre application. Heureusement, il existe des moyens de contourner la liste noire des API cachées en utilisant uniquement Java.

Android 9 et 10

Sous Android 9 et 10, vous pouvez utiliser ce que l’on peut appeler la double réflexion ou la méta-réflexion pour contourner la liste noire des API cachées. Étant donné que le système vérifie uniquement les appels des applications tierces, la double réflexion lui fait croire que le système effectue les appels d'API cachés.

Cette astuce peut être utilisée pour appeler une méthode permettant d'accorder à votre application des exemptions d'API cachées, bien nommée setHiddenApiExemptions(). Ajoutez simplement le code suivant quelque part au début du cycle de vie de votre application (comme le code de l'application). onCreate() méthode), et il gérera le contournement de la liste noire.

Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class vmRuntimeClass = (Class) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", newClass[] { String[].class} );

Object vmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(vmRuntime, newString[][] { newString[] { "L" } });

Si votre application est compatible avec les versions d'Android inférieures à 9, n'oubliez pas de l'inclure dans une vérification de version.

Android 9 et versions ultérieures

Pour contourner la liste noire des API cachées sur Android 9 et toute version ultérieure, vous pouvez utiliser la bibliothèque de LSPosed. Cette bibliothèque utilise l'API Unsafe de Java, il est donc peu probable qu'elle tombe en panne.

Pour l'implémenter, ajoutez simplement la dépendance à votre build.gradle au niveau du module.

implementation 'org.lsposed.hiddenapibypass: hiddenapibypass: 2.0'

Utilisez-le ensuite pour contourner la liste noire.

HiddenApiBypass.addHiddenApiExemptions("L");

Si votre application est compatible avec les versions d'Android inférieures à 9, n'oubliez pas de l'inclure dans une vérification de version.

Conclusion et plus d'informations

Il existe de nombreuses options pour contourner la liste noire des API cachées sur Android, quelle que soit la version de plate-forme que vous ciblez ou utilisez. Si vous souhaitez en savoir plus sur le fonctionnement de ces méthodes et bibliothèques, assurez-vous de consulter les liens suivants.

  • Mes questions et réponses sur le débordement de pile.
  • Bibliothèque de contournement d'API cachée de LSposed sur GitHub.
  • Bibliothèque RestrictionBypass de ChickenHook sur GitHub.
  • Bibliothèque FreeReflection de Tiann sur GitHub.
  • Documentation de Google sur la liste noire des API cachées.