Compare commits
2 commits
ed8bbd12e5
...
e4c65b6384
Author | SHA1 | Date | |
---|---|---|---|
e4c65b6384 | |||
5611281c56 |
8 changed files with 528 additions and 28 deletions
|
@ -1,24 +1,451 @@
|
|||
#import "../lib.typ": todo, epigraph
|
||||
#import "../lib.typ": epigraph, APK, pb1-text-fr, pb2-text-fr, pb3-text-fr, eg, etal, APKs, DEX, todo
|
||||
|
||||
#let mp = text(font: "libertinus serif", sym.dot.c)
|
||||
|
||||
= Résumé en Français
|
||||
|
||||
#epigraph("Ellana Caldin, Le Pacte des Marchombres, Tome 1: Ellana, de Pierre Bottero")[Il y a deux réponses à cette question, comme à toutes les questions : celle du savant et celle du poète.]
|
||||
|
||||
== Introduction
|
||||
|
||||
#todo[
|
||||
Write a "Substantial Summary" in french, at least 4 pages: https://ed-matisse.doctorat-bretagne.fr/fr/soutenance-de-these#p-151
|
||||
Android est le système d'exploitation pour téléphones portables le plus utilisé depuis 2014, et depuis 2017, il surpasse même Windows toute platformes confondues.
|
||||
Cette popularité en fait une cible de choix pour les acteurs malveillants.
|
||||
Il est donc important d'être capable d'analyser une application pour savoir exactement ce qu'elle fait.
|
||||
Ce processus est appelé l'ingénierie inverse.
|
||||
|
||||
Beaucoup de travail à été fait dans ce domaine pour les programmes d'ordinateur.
|
||||
Toutefois, les applications Android présentent leur propres difficultés.
|
||||
Par example, les applications sont distribué dans leur format spécifique, le format #APK, et le code des applications est lui même compilé dans un format de code à octets spécifique à Android: Dalvik.
|
||||
La première difficulté pour l'ingénieur#mp;e inverse est donc d'avoir des outils qui comprennent les formats utilisés par Android.
|
||||
Dans le processus d'analyse, une première étape serait alors de lire le contenu de l'application.
|
||||
Des outils comme Apktool peuvent être utilisé pour convertir les fichiers binaire de l'application dans une version lisible par un#mp;e humain#mp;e.
|
||||
D'autres comme Jadx essaient de générer le code source Java depuis le code à octets.
|
||||
Toutefois, les applications Android peuvent être trés grossent et il n'est pas toujours possible de les analyser manuellement.
|
||||
D'autres outils ont été développer pour extraire une représentation plus haut niveau du contenu de l'application.
|
||||
Par example, Flowdroid a pour objectif de détecter les fuites d'informations: l'utilisateur#mp;ice définit une liste de méthodes qui génèrent des informations sensbiles, et une liste de méthodes qui exfiltrent des informations vers l'extérieur.
|
||||
Flowdroid va alors calculer si il existe des chemins dans l'application permettant de relier des méthodes de la première catégorie avec des méthodes de la seconde.
|
||||
|
||||
Malheureusement, ces outils sont difficile a utiliser, et même si ils fonctionnent sur des applications simples construitent dans le but de tester les outils, il n'est pas rare que ces outils échouent sur de vrais applications.
|
||||
Cela pause la problématique #pb1-text-fr
|
||||
|
||||
Il y a deux familles d'analyse: l'analyse statique et l'analyse dynamique.
|
||||
L'analyse statique analyse l'application sans la lancer, alors que l'analyse dynamique examine le comportement de l'application peudant son exécution.
|
||||
Chacune a ses forces et ces faiblesses, et certain problèmes d'analyse sont traditionnellement associé à l'une ou l'autre pour les résoudre.
|
||||
L'un de ces problème est le chargement dynamique de code.
|
||||
Les applications Android sont initiallement prévu pour être codé en Java, et donc Android à hérité de beaucoup de fonctionnalités de Java.
|
||||
En l'occurence, Android utilisent un systeme de chargeur de classes similaire à celui de Java, qui peut être utiliser pour charger, en cour d'exécution, du code extérieur à l'application.
|
||||
Etant donné que ce code chargé dynamiquement n'est pas nécessairement disponnible dans l'application initiallement, ce problème est relégé a l'analyse dynamique.
|
||||
Toutefois, il semblerais qu'une généralisation hâtive soit souvant faite, et que le système de chargement de classe dans sont ensemble soit relégé à l'analyse dynamique.
|
||||
L'absence d'étude détaillé de ce mechanisme nous amène à notre seconde problématique: #pb2-text-fr
|
||||
|
||||
Un autre problème usuellement associé à l'analyse dynamique est la réflection.
|
||||
Android permet à une application de manipuler les classes et méthodes sous forme d'objet.
|
||||
En utilisant cette fonctionnalité, il est donc possible d'appeler une méthode en utilisant son nom sous forme de chaine de caractère au lieu d'utiliser une instruction Dalvik avec une référence vers méthode.
|
||||
Ce cas est déjà compliqué à analyser statiquement quand la chaine de caractère est lisible dans l'application, mais il devient imposible quand elle ne l'ai pas (#eg la chaine est envoyé par un serveur externe lors de l'execution, ou elle est stocké chiffré est n'est déchiffré qu'au dernier moment).
|
||||
L'analyse dynamique permet de capturer à la fois le code chargé dynamiquement et les méthodes appelés par reflection.
|
||||
Toutefois, obtenir ces instructions est insuffisant.
|
||||
Il n'existe pas de solutions standards pour transmettre ces données aux outils d'analysise statique, qui pourtant peuvent en avoir besoin pour analyser l'application dans sont entièreté.
|
||||
Certaine contributions d'ingenierie inverse ont déjà proposé d'instrumenter (modifier) l'application pour y ajouter les résultats de leur analyse avant de l'analyser avec d'autres outils.
|
||||
Cette approche prométeuse motive notre troisième problématique: #pb3-text-fr
|
||||
|
||||
#[
|
||||
== Evaluation de la réutilisabilité des outils d'analyse static pour Android
|
||||
|
||||
#import "../lib.typ": MWE
|
||||
#import "../3_rasta/X_var.typ": *
|
||||
#import "../3_rasta/X_lib.typ": *
|
||||
|
||||
Dans ce chapitre, nous étudions la réutilisabilité d'outils d'analyse statique publiés entre 2011 et 2017.
|
||||
Le but de cette étude n'est pas de quantifier la précision des outils, car ces outils ont des objectifs finaux différents.
|
||||
Au contraire, dans ce chapitre nous allons considéré comme correct tout résultat renvoyé par les outils, et uniquement compter les occurences où les outils échouent a calculer un résultat quel qu'il soit.
|
||||
|
||||
Les questions auxquelles nous voulons répondre sont:
|
||||
|
||||
/ QR1: Quels outils d'analyse statique pour Android vieux de plus de 5 ans peuvent encorent être utilisé aujourd'hui avec un effort résonnable?
|
||||
/ QR2: Comment la réutilisabilité des outils évolue avec le temps, en particulier pour l'analyze d'applications publié avec plus de 5 ans d'éccart avec l'outil?
|
||||
/ QR3: Est-ce-que la réutilisabilité des outils change quand on analyze une application bénine comparé a un maliciel?
|
||||
|
||||
Nous basons notre étude sur revue de litérature systématique de Li #etal qui liste les contributions accompagnées d'outils sous licence libre.
|
||||
Nous avons retrouvé les outils en questions, listé dans le @tab:rasta-outils.
|
||||
Nous avons éliminé les outils utilisant de l'analyse dynamique en plus de l'analyse statique, et vérifié la présence des sources, de la documentation, et d'un optionnel exécutable si jamais les sources ne peuvent pas être compilé.
|
||||
|
||||
#figure({
|
||||
show table: set text(size: 0.80em)
|
||||
show "#etal": etal
|
||||
|
||||
// Trad to fr
|
||||
show "Hybrid tool (static/dynamic)": "Outil hybride (statique et dynamique)"
|
||||
show "Works on source files only": "Nécessite les fichiers sources"
|
||||
show "Authors ack. a partial doc": "Auteurs reconnaissent documentation insufisante"
|
||||
show "Binary obtained from authors": "Binaire obtenu des auteurs"
|
||||
show "Related to Android hardening": "Dédié a la sécurisation d'Android"
|
||||
show "Not built with author’s help": "Ne compille pas même avec l'aide des auteurs"
|
||||
|
||||
let show_citekeys(keys) = [
|
||||
/*
|
||||
#keys.split(",").map(
|
||||
citekey => cite(label(citekey))).join([]
|
||||
) (#keys.split(",").map(
|
||||
citekey => cite(label(citekey), form: "year")
|
||||
).join([]))
|
||||
*/
|
||||
]
|
||||
table(
|
||||
columns: 7,
|
||||
inset: (x: 0% + 5pt, y: 0% + 2pt),
|
||||
stroke: none,
|
||||
align: center+horizon,
|
||||
table.hline(),
|
||||
table.header(
|
||||
table.cell(colspan: 7, inset: 3pt)[],
|
||||
table.cell(rowspan:2)[*Outil*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(colspan:3)[*Disponibilité*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
[*Dépo*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(rowspan:2)[*Décision*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(rowspan:2)[*Commentaires*],
|
||||
|
||||
[Bin],
|
||||
[Src],
|
||||
[Doc],
|
||||
[type],
|
||||
),
|
||||
table.cell(colspan: 7, inset: 3pt)[],
|
||||
table.hline(),
|
||||
table.cell(colspan: 7, inset: 3pt)[],
|
||||
..rasta_tool_data
|
||||
.map(entry => (
|
||||
[#entry.tool #show_citekeys(entry.citekey)],
|
||||
str2sym(entry.binary),
|
||||
str2sym(entry.source),
|
||||
str2sym(entry.documentation),
|
||||
link(entry.url, entry.repo),
|
||||
str2sym(entry.decision),
|
||||
entry.why,
|
||||
)).flatten(),
|
||||
table.cell(colspan: 7, inset: 3pt)[],
|
||||
table.hline(),
|
||||
table.cell(colspan: 7, inset: 3pt)[],
|
||||
table.hline(),
|
||||
)
|
||||
[
|
||||
*binaires, sources*: #nr: non pertinent, #ok: disponible, #bad: partiellement disponible, #ko: non fourni\
|
||||
*documentation*: #okk: excellente, #MWE, #ok: quelques incohérences, #bad: mauvaise qualité, #ko: non disponible\
|
||||
*decision*: #ok: considéré; #bad: considéré mais pas compilé; #ko: sort du cadre de l'étude
|
||||
]},
|
||||
caption: [Outils considérés: disponibilité et réutilisabilité],
|
||||
) <tab:rasta-outils>
|
||||
|
||||
Nous avons ensuite selectionné la version des outils à utiliser.
|
||||
Certain outils ont évolué depuis leur publication, soit en étant maintenu par leurs auteurs, soit suite a un branchement par un autre développeur.
|
||||
Nous avons décidé d'utiliser la dernière version stable en date de 2023 (date de l'étude).
|
||||
Le seul cas de branchement interescant que nous avont trouvé est celui d'IC3, que nous avons décidé d'inclure en plus d'IC3.
|
||||
Le @tab:rasta-choix-sources résume cette étape.
|
||||
|
||||
#figure({
|
||||
show table: set text(size: 0.80em)
|
||||
show "#etal": etal
|
||||
let show_citekeys(keys) = [/*
|
||||
#keys.split(",").map(
|
||||
citekey => cite(label(citekey))).join([]
|
||||
)
|
||||
*/]
|
||||
table(
|
||||
columns: 8,
|
||||
inset: (x: 0% + 5pt, y: 0% + 2pt),
|
||||
stroke: none,
|
||||
align: center+horizon,
|
||||
table.hline(),
|
||||
table.header(
|
||||
table.cell(colspan: 8, inset: 3pt)[],
|
||||
table.cell(rowspan:2)[*Outil*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(colspan:2)[*Original*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(colspan:2)[*Branchement Vivant*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(rowspan:2)[*Date Dernière \ Modification*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
table.cell(rowspan:2)[*Auteurs \ Contacté*],
|
||||
table.vline(end: 3),
|
||||
table.vline(start: 4),
|
||||
[*Environment*],
|
||||
|
||||
[Etoiles],
|
||||
[Vivant],
|
||||
[Nb],
|
||||
[Utilisable],
|
||||
[Langage -- SE],
|
||||
),
|
||||
table.cell(colspan: 8, inset: 3pt)[],
|
||||
table.hline(),
|
||||
table.cell(colspan: 8, inset: 3pt)[],
|
||||
..rasta_tool_data
|
||||
.filter(entry => entry.exclude != "EXCLUDE")
|
||||
.map(entry => (
|
||||
[#entry.tool #show_citekeys(entry.citekey)],
|
||||
entry.stars,
|
||||
str2sym(entry.alive),
|
||||
entry.nbaliveforks,
|
||||
str2sym(entry.forkusable),
|
||||
entry.selecteddate,
|
||||
str2sym(entry.authorconfirmed),
|
||||
[#entry.lang -- #entry.os]
|
||||
)).flatten(),
|
||||
table.cell(colspan: 8, inset: 3pt)[],
|
||||
table.hline(),
|
||||
table.cell(colspan: 8, inset: 3pt)[],
|
||||
table.hline(),
|
||||
)
|
||||
[#ok: oui, #ko: non, UX.04: Ubuntu X.04]},
|
||||
caption: [Outils selectionnés, branchements, version selectionnées et environment d'exécution],
|
||||
) <tab:rasta-choix-sources>
|
||||
|
||||
Nous avons ensuite exécuté ces outils sur deux jeux d'applications: Drebin, un jeu de maliciels connus pour être vieux et biaisé, et Rasta, un jeu que nous avons échantilloné nous même pour réprésenter l'évolution des caractéristiques des applications entre 2010 et 2023, d'un total de #NBTOTALSTRING #APKs.
|
||||
|
||||
Après avoir lancé les outils, nous avons collecté les différents résultats et traces d'execution.
|
||||
@fig:rasta-exit-drebin-fr et @fig:rasta-exit-fr montre les résultas des analyses sur les applications de Drebin et Rasta.
|
||||
L'analyse est considérée comme réussi (vert) si un résultat est obtenu, sinon elle a échoué (rouge).
|
||||
Quand l'analyse met plus de une heure a finir, elle est avorté (bleue).
|
||||
On peut voir que les outils ne s'en sorte pas trop mal sur Drebin, avec Results on the Drebin datasets 11 outils qui ont un taux de finition au dessus de 85%.
|
||||
Sur Rasta par contre, #resultunusablenb outils (#resultunusable) ont un taux de finition en dessous de 50%.
|
||||
Les outils qui avaient des difficultés avec Drebin ont aussi de mauvais résultat sur Rasta, mais d'autre outils avec un résultats acceptable sur Drebin chutent avec Rasta.
|
||||
|
||||
Ces résultats nous permetent de répondre à la notre première question *QR1*:
|
||||
|
||||
Sur un jeu d'applications réscentes nous considérons que #resultunusable des outils sont utilisables.
|
||||
De plus pour les outils que nous avons peu lancer, #resultratio des analyses ont bien terminé correctement.
|
||||
|
||||
#figure(
|
||||
image(
|
||||
"../3_rasta/figs/exit-status-for-the-drebin-dataset.svg",
|
||||
width: 100%,
|
||||
alt: "Bar chart showing the % of analyse apk on the y-axis and the tools on the x-axis.
|
||||
Horizontal blue dotted lines mark the 15%, 50% % and 85% values.
|
||||
Each bar represent a tools, with the finished analysis in green at the bottom, the analysis that timed of in blue, then on top in red the analysis that failed. Their is a last color, grey, for the other category, only visible in the dialdroid bar representing 5% of the result.
|
||||
The results are (approximately) as follow:
|
||||
adagio: 100% finished
|
||||
amandroid: less than 5% timed out, the rest finished
|
||||
anadroid: 85% failed, less than 5% timed out, the rest finished
|
||||
androguard: 100% finished
|
||||
androguard_dad: 5% failled, the rest finished
|
||||
apparecium: arround 1% failed, the rest finished
|
||||
blueseal: less than 5 failed, a little more than 10% timed out, the rest (just under 85%) finished
|
||||
dialdroid: a little more than 50% finished, less than 5% timed out, arround 5% are marked as other, the rest failled
|
||||
didfail: 70% finished, the rest failed
|
||||
droidsafe: 40% finihed, 45% timedout, 15% failed
|
||||
flowdroid: 65% finished, the rest failed
|
||||
gator: 100% finished
|
||||
ic3: 99% finished, 1% failed
|
||||
ic3_fork: 98% finishe, 2% failed
|
||||
iccta: 60% finished, less than 5% timed out, the rest failed
|
||||
mallodroid: 100% finished
|
||||
perfchecker: 75% finished, the rest failed
|
||||
redexer: 100% finished
|
||||
saaf: 90% finished, 5% timed out, 5% failed,
|
||||
wognsen_et_al: 75% finished, 1% failed, the rest timed out
|
||||
"
|
||||
),
|
||||
caption: [Taux de Finition pour le jeu d'applications Drebin],
|
||||
) <fig:rasta-exit-drebin-fr>
|
||||
|
||||
#figure(
|
||||
image(
|
||||
"../3_rasta/figs/exit-status-for-the-rasta-dataset.svg",
|
||||
width: 100%,
|
||||
alt: "Bar chart showing the % of analyse apk on the y-axis and the tools on the x-axis.
|
||||
Horizontal blue dotted lines mark the 15%, 50% % and 85% values.
|
||||
Each bar represent a tools, with the finished analysis in green at the bottom, the analysis that timed of in blue, then on top in red the analysis that failed. Their is a last color, grey, for the other category, only visible in the dialdroid bar representing 10% of the result and in the blueseal bar, for 5% of the results.
|
||||
The results are (approximately) as follow:
|
||||
adagio: 100% finished
|
||||
amandroid: less than 5% failed, 10% timed out, the rest finished
|
||||
anadroid: 95% failed, 1% timed out, the rest finished
|
||||
androguard: 100% finished
|
||||
androguard_dad: a little more than 45% finished, the rest failed
|
||||
apparecium: arround 5% failed, 1% timed out, the rest finished
|
||||
blueseal: 20% finished, a 15% timed out, 5% are marked other, the rest failed
|
||||
dialdroid: 35% finished, 1% timed out, 10 are marked other, the rest failed
|
||||
didfail: 25% finished, less than 5% timed out, the rest failed
|
||||
droidsafe: less than 10% finihed, 20% timedout, the rest failed
|
||||
flowdroid: 55% finished, the rest failed
|
||||
gator: a little more than 85% finished, 5% timed out, 10% failed
|
||||
ic3: less than 80% finished, 5% timed out, the rest failed
|
||||
ic3_fork: 60% finished, 5% times out, the rest failed
|
||||
iccta: 30% finished, 10% timed out, the rest failed
|
||||
mallodroid: 100% finished
|
||||
perfchecker: 25% finished, less than 5% timed out, the rest failed
|
||||
redexer: 90% finished, the rest failed
|
||||
saaf: 40% finished, the rest failed,
|
||||
wognsen_et_al: a little less than 15% finished, a little less than 20% failed, the rest timed out
|
||||
"
|
||||
),
|
||||
caption: [Taux de finition pour le jeu d'application Rasta],
|
||||
) <fig:rasta-exit-fr>
|
||||
|
||||
Nous avons ensuite étudier l'évolution du taux de finition des outils au cour des ans.
|
||||
Le @fig:rasta-exit-evolution-java-fr montre cette évolution pour les outils codé en Java.
|
||||
On peut noter une tendance général où le taux de finition diminu avec le temps.
|
||||
|
||||
Plusieurs facteurs peuvent être responsable.
|
||||
Par example, la librairie standard d'Android et le format des applications à évolué avec les versions d'Android.
|
||||
Un autre changement notable est la taille du code à octets des applications.
|
||||
Les applications les plus récentes ont notablement plus de code.
|
||||
|
||||
Plusieurs facteurs peuvent être responsable.
|
||||
Par example, la librairie standard d'Android et le format des applications à évolué avec les versions d'Android.
|
||||
Un autre changement notable est la taille du code à octets des applications.
|
||||
Les applications les plus récentes ont notablement plus de code.
|
||||
|
||||
Pour déterminer le facteur qui influence le plus le taux de finitions, selectionné des sous-ensembles de Rasta avec certains de ces paramètres fixés.
|
||||
Par example, nous avons tracé l'évolution du taux de finition en fonction de l'année de plublication des applications sur l'ensemble des applications dont le code à octets fait entre 4.08 et 5.2 Mo.
|
||||
|
||||
#figure(
|
||||
image(
|
||||
"../3_rasta/figs/finishing-rate-by-year-of-java-based-tools.svg",
|
||||
width: 90%,
|
||||
alt: ""
|
||||
),
|
||||
caption: [Taux de finition des outils basé sur Java au cour des ans],
|
||||
) <fig:rasta-exit-evolution-java-fr>
|
||||
|
||||
Nous en avons conlus la réponse à notre question de recherche *QR2*:
|
||||
Au cour du temps, le taux de finition des outils diminu, allant de 78% à 61% cinq ans plus tard, à 45% dix ans plus tard.
|
||||
Ce taux varie en fonction de la taille du code à octet, et, dans de moindre mesure, la version d'Android.
|
||||
|
||||
|
||||
Pour répondre à notre dernière recherche question, nous avons comparé le taux de finition entre les applications bénines et les maliciels.
|
||||
Les résultats semble indiquer que les maliciels sont plus facilement analysé.
|
||||
Pour vérifier cette affirmation, nous avons comparé le taux de finition mais aussi la taille du code à octets des applications et effectivement, il semblerais que ce résultat soit vrai, y compris a taille égale.
|
||||
|
||||
Nous avons donc une réponse a notre *RQ3*: Les Maliciels cause moins d'erreures lors de leur analyse par des outils d'analyse statique.
|
||||
|
||||
Finalement, nous avons une réponde à notre première problématique.
|
||||
|
||||
#pb1-text-fr
|
||||
|
||||
Plus de la moitié des outils sélectionnés ne sont plus utilisables.
|
||||
Dans certains cas, c'est due à notre incapicibilité à les installer correctement, mais majoritairement, c'est due au failbe taux de finition des outils lors de l'analyse des applications.
|
||||
Nos résultats montre que les applications avec beaucoup de code sont plus difficile a analyser, et, en moindre mesure, la version d'Android ainsi que la malignité de l'application peut avoir un impact.
|
||||
]
|
||||
|
||||
#text(fill: luma(75%), lorem(200))
|
||||
#[
|
||||
== Chargeurs de classes au milieu: Dérouter les analyseur static pour Android
|
||||
|
||||
#import "../lib.typ": MWE
|
||||
#import "../4_class_loader/X_var.typ": *
|
||||
|
||||
Dans ce chapitre, nous étudions comment Android gère le chargement de classe en présence de mutliple versions de la même classe.
|
||||
Nous modélisons l'algorithme de chargement de classe d'Android, et l'utilisons comme base pour une nouvelle famille de brouillage de code que nous appelons _masquage de classes_.
|
||||
Nous auditons ensuite des applications publiés en 2023 pour déterminer si cette technique de brouillage est actuellement utilisé.
|
||||
|
||||
Le chargement de classe est une fonctionnalité de Java qu'Android a hérité.
|
||||
Les développeurs intéragissent avec elle le plus souvant au travers de classes héritant de `ClassLoader` pour charger dynamiquement du code.
|
||||
Toutefois, il est utilisé a chaque fois qu'un classe est utilisé dans le code.
|
||||
A chaque fois qu'Android rencontre une nouvelle classe en exécutant une méthode, il va charger cette classe au traver du méchanisme de chargement de classe.
|
||||
|
||||
L'interet de ce mechanisme est qu'il permet d'utiliser des classes provenant de différent sources.
|
||||
Pour cela, Android associe à chaque class un objet `ClassLoader`, celui qui a été utilisé pour charger cette classe.
|
||||
Par la suite, Android va utilise ce `ClassLoader` pour charger toutes les classes référencées par cette première classe.
|
||||
Pour permettre aux classes provenant de différent `ClassLoader` d'intéragire entre elles, les `ClassLoader` implémente un méchanisme de délégation.
|
||||
Chaque `ClassLoader` a un "parent", un autre objet de type `ClassLoader`, auquel le `ClassLoader` va déléguer le chargement de classe.
|
||||
Si la classe n'est pas trouvé par le parent, alors le `ClassLoader` va la charger lui même.
|
||||
Bien que ce système de délégation est utilisé par toutes les classes héritant de `ClassLoader` dans la librairie standard d'Android (à l'execption de `DelegateLastClassLoader` qui délègue dans un ordre légèrement différent), ce comportement est spécifié par l'implémentation de chaque classes `ClassLoader`.
|
||||
Une application peut très bien définir une nouvelle classes héritant de `ClassLoader` qui n'implémente pas ce processus.
|
||||
Toutefois, ce cas relève de l'analyse dynamique: un `ClassLoader` défini dans l'application ne peut pas être utilisé par Android sans executer du code de l'application pour l'instancier.
|
||||
Dans ce chapitre, nous nous concentrons sur le comportement par défaut d'Android, aussi nous n'avons besoins d'analyser que les `ClassLoader` instancier par Android lui même pour lancer l'application.
|
||||
|
||||
Le premier `ClassLoader` utilisé par Android est `BootClassLoader`.
|
||||
Cette classe est une classe singleton, ce qui signifie qu'il ne peut y avoir qu'une seule instance de la classe par application.
|
||||
Elle est utilisé pour charger les classes de platforme.
|
||||
Ces classes sont les classes implémentées par Android et qui peuvent être utilisées par une application sans qu'elles soient présent dans l'application.
|
||||
Elles peuvent être séparés en deux catégories, les classes du KDL (Kit de développement logiciel) Android, et les classes de l'IPA cachée.
|
||||
Les premières forment la librairie standard d'Android.
|
||||
Elles sont documentés et courament utilisé par les développeurs.
|
||||
Les secondes sont des classes utilisé par Android en interne, mais que les applications ne sont pas supposés utiliser.
|
||||
Elles ne sont pas documentés, et depuis quelques années Android commence a faire des efforts pour empécher les dévellopeurs de les utiliser.
|
||||
Elles sont toutefois encore utilisées, et au moins jusqu'à présent les mesures d'Android ne suffisent pas à les rendre innaccessible.
|
||||
|
||||
Ce `BootClassLoader` est utilisé comme le parent par défaut par tout les `ClassLoader` définits dans les classes platformes d'Android.
|
||||
Quand le parent d'un `ClassLoader` n'est pas définit (quand ca valeure est nulle), les `ClassLoader` vont déléguer au `BootClassLoader` à la place.
|
||||
L'autre type de `ClassLoader` utilisé par Android par défault est le `PathClassLoader`.
|
||||
Cette classe est utilisé pour charger des classes stockés dans des fichiers.
|
||||
Android en définis deux par défaut, un `PathClassLoader` "système", et un `PathClassLoader` pour l'application.
|
||||
La documentation indique que le chargeur "système" est le le chargeur par défaut pour le processus principale.
|
||||
Toutefois, il ne semble pas être utilisé en pratique.
|
||||
Le chargeur de l'application en revanche est utilisé pour les classes contenus dans l'application, c'est donc le chargeur utilisé par défaut pour toutes les classes codé par le développeur.
|
||||
|
||||
En plus des chargeurs de classes, il y a un dernier critère a considérer.
|
||||
Les fichiers #DEX contenant le code à octets des applications ont une limite du nombre de méthodes qui peuvent être référencées.
|
||||
Pour y remédier, Android utilise a introduit un nouveau format d'application contenant plusieurs fichiers #DEX.
|
||||
Pour notre étude, le point notable de ces appplications est que si Android teste bien qu'un fichier #DEX ne contient qu'une seule implémentation de chaque classe.
|
||||
En revanche, ce test n'est fait que fichier par fichier: deux fichiers #DEX peuvent contenir une implementation d'une même classe chacun.
|
||||
Les fichiers #DEX de ces applications "multi-dex" sont nommés `classes.dex`, puis `classesX.dex` où `X` est un entier supérieur ou égale à 2.
|
||||
Pour savoir quelle implémentation est utilisé par Android, il faut donc savoir dans quel ordre les fichiers sont visités par les `PathClassLoader`.
|
||||
|
||||
Finalement, après avoir étudier le code source d'Android, nous concluons que l'algorithme utilisé est le même que celui que nous avons décrit dans le pseudo code @lst:algo-cl.
|
||||
Cet algorithme a deux points notables.
|
||||
En premier lieux, les classes platformes ont toujours la priorité sur les autres classes.
|
||||
Cela peut sembler évidant pour les classes courantes comme `String`, mais il faut se rappeler que les classes de l'IPA cachée ne sont pas documentées.
|
||||
Ensuite, les classes sont sélectionné parmis les fichiers #DEX dans un ordre non triviale, et s'arrête a la première implémentation trouvé.
|
||||
Le premier fichier testé est `classes.dex`, suivit de `classes2.dex`, puis `classes3.dex` et ainsi de suite, jusqu'à ce qu'un fichier `classesX.dex` n'existe pas.
|
||||
La limite au nombre de fichiers #DEX est très élevé ($2^64$ sur les téléphones actuels), tant que le fichier suivant existe et que la classe n'est pas trouvé, Android va continuer.
|
||||
Aussi, le code contenu fichier `classes100.dex` peut être utilisé par Android, ou non, par example si `classes99.dex` n'existe pas.
|
||||
Plus surprenant, de code contenu dans un fichier `classes1.dex` ou `classes02.dex` ne serra pas utilisé.
|
||||
Lors de l'analyse statique d'applications, ces deux points peuvent mener à des complications que nous allons maintenant explorer.
|
||||
|
||||
#todo[traduire en francais @lst:algo-cl]
|
||||
#figure(
|
||||
```python
|
||||
def get_mutli_dex_classses_dex_name(index: int):
|
||||
if index == 0:
|
||||
return "classes.dex"
|
||||
else:
|
||||
return f"classes{index+1}.dex"
|
||||
|
||||
def load_class(class_name: str):
|
||||
if is_platforn_class(class_nane):
|
||||
return load_from_boot_class_loader(class_name)
|
||||
else:
|
||||
index = 0
|
||||
dex_file = get_nutli_dex_classses_dex_name(index)
|
||||
while file_exists_in_apk(dex_file) and \
|
||||
not class_found in_dex_file(class_name, dex_file):
|
||||
index += 1
|
||||
if file_exists_in apk(dex_file):
|
||||
return load_from_file(dex_file, class_name)
|
||||
else:
|
||||
raise ClassNotFoundrror()
|
||||
```,
|
||||
caption: [Algorithme de chargement de class par défaut pour les applications Android],
|
||||
) <lst:algo-cl>
|
||||
]
|
||||
|
||||
== L'Application de Thésée: Même après avoir ajouté les informations d'exécution, c'est toujours votre application
|
||||
|
||||
== Conclusion
|
||||
|
||||
/*
|
||||
* Vocabulaire:
|
||||
* - Obfuscation: brouillage, Reverse Engineering: Ingénierie Inverse, jofr 1 jav 2013 https://www.legifrance.gouv.fr/jorf/jo/id/JORFCONT000026871045
|
||||
* - Malware: Maliciel, https://cyber.gouv.fr/le-cyberdico#M
|
||||
*
|
||||
* - Bytecode: Code à octets, https://www.culture.gouv.fr/fr/thematiques/langue-francaise-et-langues-de-france/agir-pour-les-langues/moderniser-et-enrichir-la-langue-francaise/nos-publications/Vocabulaire-des-TIC-2017
|
||||
* - API: IPA (interface de programmation d'application) https://www.enseignementsup-recherche.gouv.fr/fr/bo/22/Hebdo21/CTNR2212247K.htm
|
||||
* - SDK: Kit de développement logiciel (KDL?) https://www.cnil.fr/fr/definition/kit-de-developpement-logiciel-ou-sdk-software-development-kit
|
||||
*
|
||||
* autres ref:
|
||||
* - https://www.enseignementsup-recherche.gouv.fr/fr/bo/22/Hebdo21/CTNR2212247K.htm
|
||||
* - https://datafranca.org/wiki/Cat%C3%A9gorie:Cybers%C3%A9curit%C3%A9
|
||||
* - https://cyber.gouv.fr/le-cyberdico
|
||||
*/
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
== Conclusion <sec:rasta-conclusion>
|
||||
|
||||
#todo[Ca serait bien de faire un PR ou deux a Jadx/Androguard/Soot quand même]
|
||||
|
||||
Since the release of Android, many tools have been published in order to analyse Android application.
|
||||
In @sec:bg, we went through contributions benchmarking and comparing some of those tools.
|
||||
Those contributions suggested that analysing real-world applications might be more of a challenged than expected.
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
== Conclusion <sec:cl-conclusion>
|
||||
|
||||
#todo[Ca serait bien de faire un PR ou deux a Jadx/Androguard/Soot quand même]
|
||||
|
||||
This chapter has presented three shadow attacks that allow malware developers to fool static analysis tools when reversing an Android application.
|
||||
By including multiple classes with the same name or by using the same name as a class of the #Asdk, the developer can mislead a reverser or impact the result of a flow analysis, such as the ones of Androguard or Flowdroid.
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#import "../lib.typ": epigraph, highlight-block, todo
|
||||
|
||||
= Theseus <sec:th>
|
||||
= The Application of Theseus: After Adding Runtime Data, it is Still Your Application <sec:th>
|
||||
|
||||
#epigraph("Plutarch, Life of Theseus 23.1")[The ship wherein Theseus and the youth of Athens returned from Crete had thirty oars, and was preserved by the Athenians \[...\] for they took away the old planks as they decayed, putting in new and strong timber in their places]
|
||||
//#epigraph("Plutarch, Life of Theseus 23.1")[The ship wherein Theseus and the youth of Athens returned from Crete had thirty oars, and was preserved by the Athenians \[...\] for they took away the old planks as they decayed, putting in new and strong timber in their places]
|
||||
#epigraph("Toby Fox, Undertale")[Despite everything, it's still you.]
|
||||
|
||||
#align(center, highlight-block(inset: 15pt, width: 75%, block(align(left)[
|
||||
#todo[Abstract for @sec:th]
|
||||
|
|
8
jury.typ
8
jury.typ
|
@ -8,10 +8,10 @@
|
|||
column-gutter: 2em,
|
||||
stroke: 0pt,
|
||||
inset: (x: 0pt, y: .5em),
|
||||
"Présidente :", "Alice", "", "",
|
||||
"Rapporteurs :", "Bob", "", "",
|
||||
"", "Eve", "", "",
|
||||
"Examinatrice :", "Mallory", "", "",
|
||||
"Présidente :", "", "", "",
|
||||
"Rapporteurs :", "Vincent Nicomette", "Professeur des Universités", "INSA Toulouse",
|
||||
"", "Julien Signoles", "Directeur de Recherches", "CEA",
|
||||
"Examinatrice :", "", "", "",
|
||||
"Dir. de thèse :", "Jean-François Lalande", "Professeur des Universités", "CentraleSupélec",
|
||||
"", "Valérie Viet Triem Tong", "Professeure", "CentraleSupélec",
|
||||
)
|
||||
|
|
5
lib.typ
5
lib.typ
|
@ -41,7 +41,12 @@
|
|||
|
||||
#let pb1 = link(<pb-1>)[*Pb1*]
|
||||
#let pb1-text = [_To what extent are previously published Android analysis tools still usable today, and what factors impact their reusability?_]
|
||||
#let pb1-text-fr = [_A quel point les outils d'analyse Android préalablement publiés sont utilisable aujourd'hui, et quels facteurs impactent leur réutilisabilité?_]
|
||||
|
||||
#let pb2 = link(<pb-2>)[*Pb2*]
|
||||
#let pb2-text = [_What is the default Android class loading algorithm, and does it impact static analysis?_]
|
||||
#let pb2-text-fr = [_Quel est l'algorithme de chargement de classe utilisé par défaut par Android, et est ce qu'il impacte l'analyse statique?_]
|
||||
|
||||
#let pb3 = link(<pb-3>)[*Pb3*]
|
||||
#let pb3-text = [_Can we use instrumentation to provide dynamic code loading and reflection data collected dynamically to static analysis tools and improve their results?_]
|
||||
#let pb3-text-fr = [_Peut-on utliser l'instrumentation pour fournir le code chargé dynamiquement et les informations de réflection collecté dynamiquement aux outils d'analyse static pour améliorer leurs résultats?_]
|
||||
|
|
57
main.typ
57
main.typ
|
@ -26,24 +26,44 @@
|
|||
} else {
|
||||
false
|
||||
}
|
||||
#let abstract-only = if "abstract-only" in sys.inputs {
|
||||
assert(
|
||||
sys.inputs.abstract-only == "true" or sys.inputs.draft == "false",
|
||||
message: "If --input abstract-only=<val> is set, <val> must be 'true', or 'false'"
|
||||
)
|
||||
sys.inputs.abstract-only == "true"
|
||||
} else {
|
||||
false
|
||||
|
||||
#let (show_cover, show_body, show_abstracts) = {
|
||||
let show_cover = true
|
||||
let show_body = true
|
||||
let show_abstracts = true
|
||||
let abstract-only = false
|
||||
|
||||
if "abstract-only" in sys.inputs {
|
||||
assert(
|
||||
sys.inputs.abstract-only == "true" or sys.inputs.abstract-only == "false",
|
||||
message: "If --input abstract-only=<val> is set, <val> must be 'true', or 'false'"
|
||||
)
|
||||
if sys.inputs.abstract-only == "true" {
|
||||
show_cover = false
|
||||
show_body = false
|
||||
show_abstracts = true
|
||||
abstract-only = true
|
||||
}
|
||||
}
|
||||
|
||||
(show_cover, show_body, show_abstracts)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#show: matisse-thesis.with(
|
||||
title-fr: todo[Find a title],
|
||||
title-en: todo[Find a title],
|
||||
title-fr: [Rétro-Ingénierie d'applications Android: les inconvénients de l'analyse static], // malheurs -> inconvénients ?
|
||||
// Because "Android Skuldgerries and Other Headache Inducing Fuckeries" won't pass the vibe check
|
||||
title-en: [Android Application Reverse Engineering: the Woes of Static Analysis],
|
||||
author: "Jean-Marie MINEAU",
|
||||
affiliation: "IRISA",
|
||||
defense-place: "Rennes",
|
||||
defense-date: todo[Date],
|
||||
jury-content: [#jury-content \ #todo[Compose a Jury]],
|
||||
defense-date: datetime(
|
||||
year: 2025,
|
||||
month: 12,
|
||||
day: 10,
|
||||
).display("[year]-[month]-XX"),
|
||||
jury-content: jury-content,
|
||||
university: "CS",
|
||||
keywords-en: keywords-en,
|
||||
keywords-fr: keywords-fr,
|
||||
|
@ -51,12 +71,15 @@
|
|||
abstract-fr: abstract-fr,
|
||||
//abstract-font-size: 10pt,
|
||||
draft: draft,
|
||||
abstract-only: abstract-only,
|
||||
show_cover: show_cover,
|
||||
show_body: show_body,
|
||||
show_abstracts: show_abstracts,
|
||||
)
|
||||
|
||||
// Preamble
|
||||
#{
|
||||
set heading(numbering: none, outlined: false)
|
||||
set figure(outlined: false)
|
||||
set page(numbering: "i")
|
||||
counter(page).update(0)
|
||||
|
||||
|
@ -91,7 +114,12 @@
|
|||
|
||||
}
|
||||
|
||||
// Reset page and figure counters
|
||||
#counter(page).update(1)
|
||||
#counter(figure.where(kind: table)).update(0)
|
||||
#counter(figure.where(kind: image)).update(0)
|
||||
#counter(figure.where(kind: raw)).update(0)
|
||||
|
||||
|
||||
// Augment interline when compiling to paper draft
|
||||
#show par: set par(leading: 1.5em) if paper_draft
|
||||
|
@ -102,8 +130,7 @@
|
|||
#todo[Normalize classloaders vs class loaders]
|
||||
#todo[Normalize bullets/item: either end with a '.' or a ';']
|
||||
#todo[footnote numbering]
|
||||
|
||||
#todo[redeveloper le future work des chapitres: expliquer le pb et expliquer dans quel direction le travail devrai être dirigé, direction technique]
|
||||
#todo[Check defence date]
|
||||
|
||||
#include("1_introduction/main.typ")
|
||||
#include("2_background/main.typ")
|
||||
|
|
40
main_french.typ
Normal file
40
main_french.typ
Normal file
|
@ -0,0 +1,40 @@
|
|||
#import "lib.typ": *
|
||||
|
||||
#import "jury.typ": jury-content
|
||||
|
||||
#show: matisse-thesis.with(
|
||||
title-fr: [Rétro-Ingénierie d'applications Android: les inconvénients de l'analyse static], // malheurs -> inconvénients ?
|
||||
title-en: [],
|
||||
author: "Jean-Marie MINEAU",
|
||||
affiliation: "IRISA",
|
||||
defense-place: "Rennes",
|
||||
draft: false,
|
||||
defense-date: datetime(
|
||||
year: 2025,
|
||||
month: 12,
|
||||
day: 10,
|
||||
).display("[year]-[month]-XX"),
|
||||
jury-content: jury-content,
|
||||
university: "CS",
|
||||
lang: "fr",
|
||||
show_cover: true,
|
||||
show_body: true,
|
||||
show_abstracts: false,
|
||||
)
|
||||
|
||||
#set heading(numbering: none, outlined: true)
|
||||
|
||||
// Abrevation are links to `0_preamble/notations.typ`, but we do not include it here, so we need to remove the dangling links.
|
||||
#show link: it => if type(it.dest) == label {
|
||||
context {
|
||||
if query(it.dest).len() == 0 {
|
||||
it.body
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
} else {
|
||||
it
|
||||
}
|
||||
|
||||
#include("0_preamble/french_summary.typ")
|
Loading…
Add table
Add a link
Reference in a new issue