All checks were successful
/ test_checkout (push) Successful in 1m50s
1665 lines
37 KiB
Typst
1665 lines
37 KiB
Typst
#import "@preview/polylux:0.4.0": *
|
|
#import "slides/lib.typ": *
|
|
#import "slides/icons.typ" as ico
|
|
|
|
#import "@preview/codly:1.3.0": *
|
|
#import "@preview/codly-languages:0.1.1": *
|
|
#show: codly-init.with()
|
|
#let default-codly = (
|
|
display-name: false,
|
|
display-icon: false,
|
|
zebra-fill: none,
|
|
fill: luma(240),
|
|
radius: 1em,
|
|
inset: (y: 0.15em),
|
|
highlighted-default-color: highlight-color,
|
|
highlight-fill: it => it.lighten(40%), //highlight-color,
|
|
)
|
|
#codly-disable()
|
|
|
|
#let analyse-apk = move(dx: -50pt, image("slides/imgs/apk-analysis.svg", width: 300pt))
|
|
|
|
#set text(lang: "en")
|
|
#set list(marker: none)
|
|
#set par(leading: 0.2em)
|
|
#set list(spacing: 1em)
|
|
|
|
#show: sns-polylux-template.with(
|
|
txt-font: "New Computer Modern",
|
|
title-font: "TeX Gyre Heros",
|
|
aspect-ratio : "16-9",
|
|
title : [From Large Scale Analysis to Dynamic Deobfuscation],
|
|
subtitle : [The Woes of Android Reverse Engineering],
|
|
footer-text : [Jean-Marie Mineau -- PhD Defense],
|
|
//short-event : [Rennes, 2025/12/9],
|
|
title-size : 32pt,
|
|
section-size : 18pt,
|
|
size : 22pt,
|
|
//logo-1 : image("slides/imgs/logo_irisa.png"),
|
|
//logo-2 : image("slides/imgs/logo_pirat.png"),
|
|
//
|
|
colormap : sns-polylux-template_sns-pirat,
|
|
authors : (
|
|
{
|
|
set text(weight: "bold")
|
|
[MINEAU Jean-Marie]
|
|
v(1em)
|
|
},
|
|
text(size: 16pt)[LALANDE Jean-François, PhD supervisor],
|
|
text(size: 16pt)[VIET TRIEM TONG Valérie, PhD co-supervisor],
|
|
//text(size: 15pt)[NICOMETTE Vincent, Rapporteur],
|
|
//text(size: 15pt)[SIGNOLES Julien, Rapporteur],
|
|
//text(size: 15pt)[BARAIS Olivier, Jury],
|
|
//text(size: 15pt)[AONZO Simone, Jury],
|
|
),
|
|
date : datetime(year: 2025, month: 12, day: 9),
|
|
)
|
|
|
|
|
|
/*
|
|
* Intro:
|
|
* Dear jury, gentle people of the audience, here and online, thank you for your presence.
|
|
* I am Jean-Marie Mineau, and today I will be defending my thesis about Android Application reverse engineering and the many difficulties a reverse engineer might encounter.
|
|
* This thesis was suppervised by Jean-François Lalande and Valerie Viet Triem Tong, within the PIRAT research team at IRISA.
|
|
*/
|
|
|
|
#title-slide(
|
|
logo: grid(columns: 2,
|
|
image("slides/imgs/logo_pirat.png"),
|
|
image(width: 500pt, "slides/imgs/logo_cs.png"),
|
|
image("slides/imgs/logo_irisa.png"),
|
|
image("slides/imgs/platypus.png"),
|
|
)
|
|
)
|
|
|
|
#slide(
|
|
new-sec: true,
|
|
title: [Introduction],
|
|
hide-title: true,
|
|
/*foreground: {
|
|
ghost-5(x: 10%, y: 30pt)
|
|
ghost-4(x: 95%, y: 80%)
|
|
//ghost-4(x: 45%, y: 43%)
|
|
}*/
|
|
)[
|
|
#set align(center+horizon)
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
image("slides/imgs/google.png", width: 200pt),
|
|
//image("slides/imgs/phone.png", height: 350pt)
|
|
ico.phone(
|
|
height: 350pt,
|
|
body: {
|
|
ico.android(height: 150pt, stroke: none)
|
|
}
|
|
)
|
|
)
|
|
#v(2em)
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
|
|
#slide(
|
|
foreground: ghost-4(x: 60%, y: 25%, rot: 45deg)
|
|
)[
|
|
#set align(center+horizon)
|
|
#grid(
|
|
columns: (3fr, 2fr), stack(dir: ltr,
|
|
item-by-item[
|
|
- Personal Data and PII
|
|
- Computing Power
|
|
- Phone
|
|
- Mic, Camera, \ Geolocalisation
|
|
],
|
|
[ $ => $ ],
|
|
item-by-item()[
|
|
- Ransomware/Spyware
|
|
- Cryptojacker
|
|
- Expander (phone billing)
|
|
- Stalkerware
|
|
]
|
|
),
|
|
{
|
|
move(
|
|
dx: 20pt,
|
|
ico.phone(
|
|
height: 350pt,
|
|
body: {
|
|
ico.android(height: 150pt, stroke: none)
|
|
}
|
|
)
|
|
)
|
|
}
|
|
)
|
|
]
|
|
|
|
#slide(
|
|
title: [Obfuscation],
|
|
//foreground: eye-1(x: 95%, y: 85%, mirror: true)
|
|
)[
|
|
#set list(marker: [-])
|
|
|
|
Applications might use *obfuscation* to either:
|
|
|
|
- protect their IP
|
|
- hide malicious behaviour
|
|
|
|
#v(1em)#uncover(2)[
|
|
|
|
We will focus on two techniques:
|
|
|
|
- *Dynamic Code Loading*
|
|
- *Reflection*
|
|
|
|
/*
|
|
* Low effort yet efficiant, commonly found
|
|
*/
|
|
]
|
|
]
|
|
|
|
#for i in range(4) {
|
|
if i != 0 {
|
|
counter("logical-slide").update( n => n - 1 )
|
|
}
|
|
show: yes-codly
|
|
|
|
slide(
|
|
title: [Obfuscation],
|
|
subtitle: if i == 0 [Example] else if i == 1 [Dynamic Code Loading] else if i in (2, 3) [Reflection] else { none },
|
|
foreground: eye-1(x: 95%, y: 85%, mirror: true)
|
|
)[
|
|
#if i == 0 {
|
|
codly(..default-codly)
|
|
} else if i == 1 {
|
|
codly(
|
|
highlighted-lines: (1, 5, 6, 7, 8),
|
|
..default-codly
|
|
)
|
|
} else if i == 2 {
|
|
codly(
|
|
highlighted-lines: (2, 3),
|
|
highlights: (
|
|
(line: 10, start: 42, end: 59, fill: pirat-color.blue),
|
|
(line: 13, start: 3, end: 21, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
} else if i == 3 {
|
|
codly(
|
|
highlighted-lines: (10,),
|
|
highlights: (
|
|
(line: 12, start: 14, end: 34, fill: pirat-color.blue),
|
|
(line: 15, start: 2, end: 19, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
}
|
|
#scale(70%, reflow: true)[
|
|
```java
|
|
String DEX = "ZGV4CjA [...] EAAABEAwAA";
|
|
String className = "W5f3 [...] 3sls=";
|
|
String methodName = "n6WGYJzjDrUvR9cYljlNlw==";
|
|
|
|
ClassLoader cl = new InMemoryDexClassLoader(
|
|
ByteBuffer.wrap(Base64.decode(DEX, 2)),
|
|
Main.class.getClassLoader()
|
|
);
|
|
|
|
Class<?> loadedClass = this.cl.loadClass(decrypt(className));
|
|
Object obj = "FooBar";
|
|
Object ret = loadedClass.getMethod(
|
|
decrypt(methodName),
|
|
String.class
|
|
).invoke(null, obj);
|
|
```]
|
|
]
|
|
}
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Obfuscation],
|
|
subtitle: [Deobfuscated],
|
|
foreground: {
|
|
place-fg(x: 44%, y: 55%, $ lr(}, size: #130pt) $ )
|
|
place-fg(x: 44%, y: 26%, $ lr(}, size: #110pt) $ )
|
|
arrow((385pt, -260pt), (450pt, -230pt))
|
|
arrow((385pt, -125pt), (450pt, -110pt))
|
|
},
|
|
)[
|
|
#show: yes-codly
|
|
#grid(
|
|
columns: (1fr, 4em, 1fr),
|
|
[
|
|
#scale(60%, reflow: true)[
|
|
```java
|
|
String DEX = "ZGV4CjA [...] EAAABEAwAA";
|
|
String className = "W5f3 [...] 3sls=";
|
|
String methodName = "n6WGYJzjDrUvR9cYljlNlw==";
|
|
|
|
ClassLoader cl = new InMemoryDexClassLoader(
|
|
ByteBuffer.wrap(Base64.decode(DEX, 2)),
|
|
Main.class.getClassLoader()
|
|
);
|
|
|
|
Class<?> loadedClass = this.cl.loadClass(decrypt(className));
|
|
Object obj = "FooBar";
|
|
Object ret = loadedClass.getMethod(
|
|
decrypt(methodName),
|
|
String.class
|
|
).invoke(null, obj);
|
|
```]
|
|
],
|
|
[],
|
|
[
|
|
#codly(
|
|
skips: ((3, 10),),
|
|
..default-codly
|
|
)
|
|
#scale(100%)[
|
|
```java
|
|
public class Foo {
|
|
public static String bar(String arg) {
|
|
}
|
|
}
|
|
```
|
|
```java
|
|
String ret = Foo.bar("FooBar");
|
|
```]
|
|
]
|
|
)
|
|
]
|
|
|
|
#slide(
|
|
title: [Analysis Methods],
|
|
foreground: eye-3(x: 3%, y: 5%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#analyse-apk
|
|
]
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
|
|
#slide(
|
|
foreground: ghost-5(x: 10%, y: 7%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
gutter: 2em,
|
|
[
|
|
== Dynamic Analysis
|
|
#item-by-item[
|
|
- Run the application
|
|
- _See_ dynamically loaded bytecode
|
|
- _See_ reflection calls
|
|
- Limited by code coverage
|
|
]
|
|
],
|
|
[
|
|
== Static Analysis
|
|
#item-by-item(start: 5)[
|
|
- Do *not* run the application
|
|
- *Not* limited by code coverage
|
|
- But only for the *code available*
|
|
//- Some values cannot be computed
|
|
]
|
|
|
|
],
|
|
//grid.cell(colspan: 2, uncover(8)[
|
|
// #text(size: 30pt)[Can we combine both?]
|
|
//]),
|
|
)
|
|
]
|
|
|
|
#slide(
|
|
title: [Which Tools?],
|
|
foreground: eye-3(x: 3%, y: 5%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#analyse-apk
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Which Tools are Working?],
|
|
foreground: eye-3(x: 3%, y: 5%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#analyse-apk
|
|
]
|
|
|
|
#slide(
|
|
title: [Problem Statement 1],
|
|
)[
|
|
#item-by-item[
|
|
- Which tool to use?
|
|
- Are they easy to install?
|
|
- Are they working?
|
|
]
|
|
#highlight-block(pb1-text)
|
|
]
|
|
|
|
#slide(
|
|
title: [How does Class Loading works?],
|
|
foreground: eye-3(x: 3%, y: 5%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#analyse-apk
|
|
]
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
|
|
#slide(
|
|
title: [Class Loading],
|
|
)[
|
|
#set align(center)
|
|
#show: yes-codly
|
|
#grid(
|
|
columns: (2fr, 1em, 1fr),
|
|
scale(70%, reflow: true)[
|
|
#codly(
|
|
highlights: (
|
|
(line: 1, start: 0, end: 11, fill: pirat-color.blue),
|
|
(line: 1, start: 22, end: 43, fill: pirat-color.blue),
|
|
(line: 3, start: 14, end: 27, fill: pirat-color.blue),
|
|
(line: 6, start: 32, end: 40, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
```java
|
|
ClassLoader cl = new InMemoryDexClassLoader(
|
|
ByteBuffer.wrap(Base64.decode(DEX, 2)),
|
|
Main.class.getClassLoader()
|
|
);
|
|
|
|
Class<?> loadedClass = this.cl.loadClass(decrypt(className));
|
|
```
|
|
], [], uncover(2, scale(70%, reflow: true)[
|
|
#codly(
|
|
..default-codly
|
|
)
|
|
```java
|
|
class A {
|
|
public static void foo() {
|
|
B b = new B();
|
|
b.bar();
|
|
}
|
|
}
|
|
```
|
|
|
|
Where is the class loader?
|
|
])
|
|
)
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Class Loading],
|
|
)[
|
|
#item-by-item[
|
|
- Used to select classes implementation
|
|
- More complexe than it looks
|
|
- Doubious documentation
|
|
- Not studied in the context of Android Static Analysis
|
|
]
|
|
#highlight-block(pb2-text)
|
|
]
|
|
|
|
#slide(
|
|
title: [Can we Deobfuscate?],
|
|
foreground: eye-3(x: 3%, y: 5%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#analyse-apk
|
|
]
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Deobuscation],
|
|
)[
|
|
#set align(center+horizon)
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
gutter: 2em,
|
|
[
|
|
== Dynamic Analysis
|
|
|
|
Easier to solve Dynamic Code Loading and Reflection Calls
|
|
],
|
|
[
|
|
== Static Analysis
|
|
|
|
Better code coverage
|
|
],
|
|
grid.cell(colspan: 2, uncover(2)[
|
|
#text(size: 30pt)[Can we combine both?]
|
|
]),
|
|
)
|
|
]
|
|
|
|
//#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Problem Statement 3],
|
|
)[
|
|
#item-by-item[
|
|
- Dynamic analysis is good against DCL and reflection
|
|
- Dynamic analysis is limited by code coverage
|
|
- Static analysis is not
|
|
- How to use existing tools without modifying them?
|
|
]
|
|
#highlight-block(pb3-text)
|
|
]
|
|
|
|
#for i in range(3) {
|
|
let stage = (
|
|
"static-only",
|
|
"static-vs-dyn",
|
|
"theseus",
|
|
).at(i)
|
|
slide(
|
|
//foreground: rotate(30deg, smallcaps(text(fill: pirat-color.red, size: 50pt)[#stage]))
|
|
)[
|
|
#if i == 0 {
|
|
place(
|
|
top+left,
|
|
dx: 70%,
|
|
dy: 25%,
|
|
align(center, text(fill: pirat-color.red.darken(15%))[
|
|
*PB 1*: Static Analysis \ are the tools working?
|
|
]))
|
|
}
|
|
#if i == 1 {
|
|
place(
|
|
top+left,
|
|
dx: 35%,
|
|
dy: 25%,
|
|
align(center, text(fill: pirat-color.red.darken(15%))[
|
|
*PB 2*: Do Static Tools \ match Android Runtime?
|
|
]))
|
|
}
|
|
#if i == 2 {
|
|
place(
|
|
top+left,
|
|
dx: 5%,
|
|
dy: 5%,
|
|
align(center, text(fill: pirat-color.red.darken(15%))[
|
|
*PB 3*: Improve any Static Tools \ with dynamic analysis?
|
|
]))
|
|
}
|
|
#set align(horizon+center)
|
|
#theseus-outline(stage: stage)
|
|
]
|
|
}
|
|
|
|
#new-section-slide([Tool Reusability])
|
|
|
|
#slide(
|
|
title: [State of the Art],
|
|
)[
|
|
#set list(spacing: 0.5em)
|
|
Li #etal (2017):
|
|
#v(0pt)
|
|
#item-by-item[
|
|
- Systematic literature review for Android static analysis
|
|
- Lists open-sourced tools
|
|
- Does not test the tools
|
|
]
|
|
#uncover("4-")[Reaves #etal (2016):]
|
|
#v(0pt)
|
|
#item-by-item(start: 4)[
|
|
- Tests 7 Android analysis tools
|
|
- Tests analysing 16 real-world applications
|
|
- Raises concerns about reusability and analysis of real-world applications
|
|
]
|
|
]
|
|
|
|
#slide(
|
|
title: [Methodology]
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(100%, get_figure(<fig:rasta-methodo-collection>))
|
|
|
|
#v(1em)
|
|
|
|
#text(size: 25pt)[22 tools selected, 2 we could not package]
|
|
|
|
/*
|
|
#stack(dir: ltr,
|
|
scale(40%, reflow: true, get_figure(<tab:rasta-tools>)),
|
|
scale(55%, reflow: true, get_figure(<tab:rasta-sources>)),
|
|
)*/
|
|
]
|
|
|
|
#slide(
|
|
title: [Methodology],
|
|
foreground: place(
|
|
bottom + left,
|
|
dx: 88%,
|
|
dy: -63%,
|
|
)[
|
|
#set align(center+horizon)
|
|
#set text(size: 15pt)
|
|
62 525 APKs #v(-1.5em) from #v(-1.5em) 2010 to 2023
|
|
]
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(90%, get_figure(<fig:rasta-overview>))
|
|
|
|
#text(size: 25pt)[We check if the results *exist* after running a tool]
|
|
]
|
|
|
|
#slide(
|
|
title: [Results],
|
|
foreground: ghost-2(x: 97%, y: 10%)
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(100%, get_figure(<fig:rasta-exit>))
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Results],
|
|
foreground: {
|
|
ghost-2(x: 97%, y: 10%)
|
|
|
|
let x_0 = 112pt
|
|
let y_0 = -116pt
|
|
let w = 21pt
|
|
let h = 236pt
|
|
let dx = 33.3
|
|
let h_legend = 60pt
|
|
|
|
for i in range(20) {
|
|
let color = if i in (2, 4, 6, 7, 8, 9, 14, 16, 18, 19) {
|
|
white.transparentize(100%)
|
|
} else {
|
|
white.transparentize(10%)
|
|
}
|
|
if i == 1 {
|
|
place(
|
|
bottom + left,
|
|
dx: x_0 + i*dx*1pt + w/2,
|
|
dy: y_0,
|
|
rect(
|
|
width: w/2,
|
|
height: h_legend,
|
|
//stroke: red,
|
|
fill: color,
|
|
)
|
|
)
|
|
}
|
|
let (y_0, h) = if i in (0, 1) {
|
|
(y_0 - h_legend, h - h_legend)
|
|
} else {
|
|
(y_0, h)
|
|
}
|
|
place(
|
|
bottom + left,
|
|
dx: x_0 + i*dx*1pt,
|
|
dy: y_0,
|
|
rect(
|
|
width: w,
|
|
height: h,
|
|
//stroke: red,
|
|
fill: color,
|
|
)
|
|
)
|
|
}
|
|
|
|
place(bottom + left, line(
|
|
start: (x_0 - 20pt, y_0 - h/2),
|
|
end: (x_0 + dx * 20 * 1pt, y_0 - h/2),
|
|
stroke: pirat-color.red + 3pt
|
|
))
|
|
}
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(100%, get_figure(<fig:rasta-exit>))
|
|
]
|
|
|
|
/*
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Results],
|
|
foreground: {
|
|
ghost-2(x: 97%, y: 10%)
|
|
|
|
let x_0 = 112pt
|
|
let y_0 = -117pt
|
|
let w = 21pt
|
|
let h = 235pt
|
|
let dx = 33.3
|
|
|
|
for i in range(20) {
|
|
let color = if i in (3, 10) {
|
|
white.transparentize(100%)
|
|
} else {
|
|
white.transparentize(10%)
|
|
}
|
|
place(
|
|
bottom + left,
|
|
dx: x_0 + i*dx*1pt,
|
|
dy: y_0,
|
|
rect(
|
|
width: w,
|
|
height: h,
|
|
//stroke: red,
|
|
fill: color,
|
|
)
|
|
)
|
|
}
|
|
|
|
place(bottom + left, line(
|
|
start: (x_0 - 20pt, y_0 - h/2),
|
|
end: (x_0 + dx * 20 * 1pt, y_0 - h/2),
|
|
stroke: pirat-color.red + 3pt
|
|
))
|
|
}
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(100%, get_figure(<fig:rasta-exit>))
|
|
]
|
|
|
|
#slide(
|
|
title: [Results over Time],
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(150%, get_figure(<fig:rasta-exit-evolution-java>))
|
|
]
|
|
|
|
#slide(
|
|
title: [Bytecode Size],
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#scale(120%, get_figure(<fig:rasta-rate-evolution-java-2022>))
|
|
|
|
#text(size: 22pt)[Finishing rate as a function of the bytecode size, for APKs discovered in 2022]
|
|
]
|
|
*/
|
|
|
|
#slide(
|
|
title: [Conclusion],
|
|
)[
|
|
#v(1fr)
|
|
//#set align(center)
|
|
#item-by-item[
|
|
- Over 22 tools, 10 are usable
|
|
- Newer applications are harder to analyse
|
|
- Applications with more bytecode are harder to analyse
|
|
- Applications targetting more recent versions of Android are harder to analyse
|
|
- Confirms and extends Reaves #etal
|
|
]
|
|
#v(1fr)
|
|
#align(center, text(fill: pirat-color.blue.darken(30%))[International Conference on Software and Systems Reuse (ICSR 2024)])
|
|
#v(1em)
|
|
]
|
|
|
|
#new-section-slide([Class Shadowing])
|
|
|
|
#slide(
|
|
title: [Class Loading],
|
|
)[
|
|
#set align(center)
|
|
#show: yes-codly
|
|
#grid(
|
|
columns: (2fr, 1em, 1fr),
|
|
scale(70%, reflow: true)[
|
|
#codly(
|
|
highlights: (/*
|
|
(line: 1, start: 0, end: 11, fill: pirat-color.blue),
|
|
(line: 1, start: 22, end: 43, fill: pirat-color.blue),
|
|
(line: 3, start: 14, end: 27, fill: pirat-color.blue),
|
|
(line: 6, start: 32, end: 40, fill: pirat-color.blue),
|
|
*/),
|
|
..default-codly
|
|
)
|
|
```java
|
|
ClassLoader cl = new InMemoryDexClassLoader(
|
|
ByteBuffer.wrap(Base64.decode(DEX, 2)),
|
|
Main.class.getClassLoader()
|
|
);
|
|
|
|
Class<?> loadedClass = this.cl.loadClass(decrypt(className));
|
|
```
|
|
], [], scale(70%, reflow: true)[
|
|
#codly(
|
|
..default-codly
|
|
)
|
|
```java
|
|
class A {
|
|
public static void foo() {
|
|
B b = new B();
|
|
b.bar();
|
|
}
|
|
}
|
|
```
|
|
]
|
|
)
|
|
]
|
|
|
|
#slide(
|
|
title: [State of the Art],
|
|
//foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[State of the Art])
|
|
)[
|
|
#set list(spacing: 3em)
|
|
#item-by-item[
|
|
- Previous contributions focus on Java runtime (#eg Gong 1998)
|
|
- Android related contributions focus on Dynamic Code Loading (#eg Zhang #etal 2015)
|
|
]
|
|
]
|
|
|
|
#for i in range(5) {
|
|
let strong-at(i, str-idxs, body) = {
|
|
if i in str-idxs {
|
|
strong(body)
|
|
} else {
|
|
body
|
|
}
|
|
}
|
|
slide(
|
|
title: [Android Ecosystem],
|
|
foreground: {
|
|
let c = white.transparentize(10%)
|
|
let place-rect(x, y, w, h) = place-fg(
|
|
x: x, y: y,
|
|
rect(
|
|
width: w,
|
|
height: h,
|
|
stroke: c,
|
|
fill: c,
|
|
)
|
|
)
|
|
// phone
|
|
if i in () {
|
|
place-rect(15%, 15%, 16.5%, 55%)
|
|
}
|
|
// Platform Classes
|
|
if i in (1,) {
|
|
place-rect(18%, 38%+4pt, 12%, 15%)
|
|
place-rect(21%, 54%, 8%, 5%)
|
|
}
|
|
// API access
|
|
if i in (1,4) {
|
|
place-rect(26%-4pt, 31%+2.3pt, 5%, 7%+2pt)
|
|
}
|
|
// APK file
|
|
if i in (2,3, 4) {
|
|
place-rect(19%+3pt, 22%, 9%, 9%+1pt)
|
|
place-rect(21%+5pt, 32%, 4%, 3%)
|
|
}
|
|
// doc
|
|
if i in (1,2,4) {
|
|
place-rect(31.5%, 45%, 30%, 25%)
|
|
}
|
|
// dev
|
|
if i in (2,4) {
|
|
place-rect(39.5%, 15%, 22%, 30%)
|
|
}
|
|
// Dev SDK
|
|
if i in (1,) {
|
|
place-rect(49.6%, 18%, 10%, 15%)
|
|
}
|
|
// Dev classes
|
|
if i in (3,) {
|
|
place-rect(41.5%-1pt, 18%, 8%+2pt, 10%)
|
|
}
|
|
// compil
|
|
if i in (2,3, 4) {
|
|
place-rect(31.5%, 22%, 8%, 5%)
|
|
}
|
|
}
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#grid(
|
|
columns: (3fr, 1fr),
|
|
scale(reflow: true, get_figure(<fig:cl-archisdk>)),
|
|
[
|
|
#set align(left)
|
|
#set text(size: 20pt)
|
|
#set list(marker: [-])
|
|
|
|
=== Types of classes:
|
|
|
|
- #strong-at(i, (1,))[APK Classes]
|
|
- #strong-at(i, (2,))[Platform Classes]
|
|
- #strong-at(i, (3,))[SDK Classes]
|
|
- #strong-at(i, (4,))[Hidden APIs]
|
|
]
|
|
)
|
|
]
|
|
}
|
|
|
|
#slide(
|
|
title: [Android ClassLoaders],
|
|
foreground: {
|
|
let stroke = black + 5pt
|
|
let y0 = -177pt
|
|
let y1 = -270pt
|
|
let x0 = 250pt
|
|
let x1 = 272pt
|
|
let x2 = 570pt
|
|
let x3 = 600pt
|
|
arrow(
|
|
(x0, y0),
|
|
(x0, y1),
|
|
(x1, y1),
|
|
stroke: stroke
|
|
)
|
|
arrow(
|
|
(x3, y0),
|
|
(x3, y1),
|
|
(x2, y1),
|
|
stroke: stroke
|
|
)
|
|
place-fg(x: x0 - 2.5em, y: (y0+y1)/2)[Delegate]
|
|
place-fg(x: x3 + 2.5em, y: (y0+y1)/2)[Delegate]
|
|
}, {
|
|
let stroke = black + 3pt
|
|
let width = 13em
|
|
let height = 4.5em
|
|
set align(center+horizon)
|
|
set rect(width: 250pt, height: 75pt, radius: 20pt, inset: 20pt)
|
|
|
|
v(1fr)
|
|
|
|
rect(
|
|
stroke: stroke,
|
|
height: height,
|
|
width: width,
|
|
{
|
|
[*Boot Class Loader*]
|
|
v(-0.5em)
|
|
line(length: 80%)
|
|
v(-0.5em)
|
|
[_Platform Classes_]
|
|
}
|
|
)
|
|
|
|
v(1fr)
|
|
|
|
stack(
|
|
dir: ltr,
|
|
1fr,
|
|
rect(
|
|
stroke: stroke,
|
|
height: height,
|
|
width: width,
|
|
{
|
|
[*System Class Loader*]
|
|
v(-0.5em)
|
|
line(length: 80%)
|
|
v(-0.5em)
|
|
sym.emptyset
|
|
}
|
|
),
|
|
1fr,
|
|
rect(
|
|
stroke: stroke,
|
|
height: height,
|
|
width: width,
|
|
{
|
|
[*APK Class Loader*]
|
|
v(-0.5em)
|
|
line(length: 80%)
|
|
v(-0.5em)
|
|
[_APK Classes_]
|
|
}
|
|
),
|
|
1fr,
|
|
)
|
|
|
|
v(1fr)
|
|
|
|
})
|
|
|
|
#slide(
|
|
title: [MultiDex]
|
|
)[
|
|
#set align(center + horizon)
|
|
#let apk-block = block.with(
|
|
//fill: green.lighten(50%),
|
|
stroke: black,
|
|
inset: 10pt,
|
|
radius: 12pt,
|
|
)
|
|
|
|
#only(1)[
|
|
#apk-block[
|
|
#set align(left+top)
|
|
|
|
=== `app.apk`
|
|
#line(length: 30%)
|
|
```
|
|
AndroidManifest.xml
|
|
resources.arsc
|
|
META-INF/
|
|
res/
|
|
classes.dex
|
|
```
|
|
]
|
|
]
|
|
#only(2)[
|
|
#apk-block[
|
|
#set align(left+top)
|
|
=== `app.apk`
|
|
#line(length: 50%)
|
|
#stack(dir: ltr,
|
|
```
|
|
AndroidManifest.xml
|
|
resources.arsc
|
|
META-INF/
|
|
res/
|
|
classes.dex
|
|
```,
|
|
h(2em),[
|
|
```
|
|
classes2.dex
|
|
classes3.dex
|
|
```
|
|
]
|
|
)
|
|
]
|
|
]
|
|
#only(3)[
|
|
#apk-block[
|
|
#set align(left+top)
|
|
=== `app.apk`
|
|
#line(length: 75%)
|
|
#stack(dir:ltr,
|
|
```
|
|
AndroidManifest.xml
|
|
resources.arsc
|
|
META-INF/
|
|
res/
|
|
classes.dex
|
|
classes2.dex
|
|
classes3.dex
|
|
```, h(2em),
|
|
```
|
|
classes4.dex
|
|
classes5.dex
|
|
classes6.dex
|
|
classes7.dex
|
|
classes8.dex
|
|
classes9.dex
|
|
classes10.dex
|
|
```, h(2em),
|
|
```
|
|
classes11.dex
|
|
classes12.dex
|
|
classes13.dex
|
|
classes14.dex
|
|
classes15.dex
|
|
classes16.dex
|
|
...
|
|
```
|
|
)
|
|
]
|
|
#ghost-4(x: 2%, y: 2%, mirror: true)
|
|
]
|
|
|
|
#only(4)[
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
apk-block[
|
|
#set align(left+top)
|
|
|
|
=== `app.apk`
|
|
#line(length: 30%)
|
|
#show "classes.dex": set text(fill: pirat-color.red.darken(10%))
|
|
#show "classes2.dex": set text(fill: pirat-color.red.darken(10%))
|
|
#show "classes3.dex": set text(fill: pirat-color.red.darken(10%))
|
|
```
|
|
AndroidManifest.xml
|
|
resources.arsc
|
|
META-INF/
|
|
res/
|
|
classes.dex
|
|
classes2.dex
|
|
classes3.dex
|
|
```
|
|
],
|
|
yes-codly[
|
|
#scale(100%, reflow: true,
|
|
```python
|
|
def get_dex_name(index: int):
|
|
if index == 0:
|
|
return "classes.dex"
|
|
else:
|
|
return f"classes{index+1}.dex"
|
|
```)
|
|
]
|
|
)
|
|
]
|
|
|
|
#only(5)[
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
apk-block[
|
|
#set align(left+top)
|
|
|
|
=== `app.apk`
|
|
#line(length: 30%)
|
|
```
|
|
AndroidManifest.xml
|
|
resources.arsc
|
|
META-INF/
|
|
res/
|
|
classes.dex
|
|
classes2.dex
|
|
classes3.dex
|
|
```
|
|
],
|
|
yes-codly[
|
|
#set list(spacing: 0.5em)
|
|
#scale(100%, reflow: true,
|
|
```python
|
|
def get_dex_name(index: int):
|
|
if index == 0:
|
|
return "classes.dex"
|
|
else:
|
|
return f"classes{index+1}.dex"
|
|
```)
|
|
- `classes0.dex` ?
|
|
- `classes02.dex` ?
|
|
- `classes10.dex` ?
|
|
]
|
|
)
|
|
#ghost-4(x: 2%, y: 2%, mirror: true)
|
|
]
|
|
]
|
|
|
|
#for i in range(4) {
|
|
if i != 0 { counter("logical-slide").update( n => n - 1 ) }
|
|
slide(
|
|
title: [Shadow Attacks]
|
|
)[
|
|
|
|
#if i in (0, 4) {
|
|
codly(
|
|
..default-codly
|
|
)
|
|
} else if i == 1 {
|
|
codly(
|
|
highlighted-lines: (7, 8),
|
|
..default-codly
|
|
)
|
|
} else if i == 2 {
|
|
codly(
|
|
highlighted-lines: (1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15),
|
|
..default-codly
|
|
)
|
|
}
|
|
#let partial-hide(
|
|
i,
|
|
hidden: (),
|
|
partial: (),
|
|
body
|
|
) = {
|
|
if i in hidden {
|
|
hide(body)
|
|
} else if i in partial {
|
|
set text(fill: luma(200))
|
|
body
|
|
} else {
|
|
body
|
|
}
|
|
}
|
|
#set align(center+horizon)
|
|
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
column-gutter: 2em,
|
|
yes-codly[
|
|
#scale(55%, reflow: true,
|
|
```python
|
|
def get_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_platform_class(class_name):
|
|
return boot_cl.load(class_name)
|
|
else:
|
|
index = 0
|
|
dex_file = get_dex_name(index)
|
|
while exists_in_apk(dex_file) and \
|
|
class_name not in classes_of(dex_file):
|
|
index += 1
|
|
dex_file = get_dex_name(index)
|
|
if file_exists_in_apk(dex_file):
|
|
return load_from_file(dex_file, class_name)
|
|
else:
|
|
raise ClassNotFoundError()
|
|
```)
|
|
#v(-1em)
|
|
#smallcaps(text(size: 15pt)[Android Class Loading Algorithm])
|
|
], [
|
|
#set align(left)
|
|
#set text(size: 18pt)
|
|
#partial-hide(i, hidden: (0,), partial: (2,))[
|
|
=== SDK shadowing
|
|
Trick the tool into using an APK class instead of an SDK class
|
|
]
|
|
#partial-hide(i, hidden: (0,), partial: (2,))[
|
|
=== Hidden API shadowing
|
|
Trick the tool into using an APK class instead of an hidden API class
|
|
]
|
|
#partial-hide(i, hidden: (0,1))[
|
|
=== Self Shadowing
|
|
Trick the tool into using an APK class instead of another APK class
|
|
]
|
|
]
|
|
)
|
|
]
|
|
}
|
|
|
|
#slide(
|
|
title: [Impact on Tools],
|
|
// TODO: IF PR: Add REF
|
|
foreground: move(dx: 300pt, rotate(30deg, text(fill: pirat-color.red, size: 30pt)[We want PR!])),
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#show link.where(dest: <acr-sdk>): it => it.body
|
|
#show figure: it => {
|
|
set align(left)
|
|
show table: set align(center+horizon)
|
|
it
|
|
}
|
|
#show "not working": "attack failed"
|
|
#show "working": "attack sucessful"
|
|
#show "works": "sucessful"
|
|
#scale(100%, reflow: true, get_figure(<tab:cl-results>))
|
|
]
|
|
|
|
#slide(
|
|
title: [Example: Androguard],
|
|
foreground: eye-4(x: 97%, y: 85%, mirror: true)
|
|
)[
|
|
#set align(center+horizon)
|
|
#show image: scale.with(250%)
|
|
#set figure(gap: 4em)
|
|
#v(3em)
|
|
#grid(
|
|
columns: (1fr, 1fr),
|
|
get_figure(<fig:cl-andro_non_obf_cg>),
|
|
get_figure(<fig:cl-andro_obf_cg>)
|
|
)
|
|
]
|
|
|
|
#for i in range(3) {
|
|
if i != 0 { counter("logical-slide").update( n => n - 1 ) }
|
|
slide(
|
|
title: [In the Wild: 49 975 APKs],
|
|
)[
|
|
#set align(center+horizon)
|
|
// TODO: Simplifier table, mettre nb apk dans titre
|
|
// enlever SDK et 1ere partie 100%
|
|
//#scale(90%, reflow: true, get_figure(<tab:cl-shadow>))
|
|
#import "4_class_loader/X_var.typ": scan_50k, scan_only_shadow
|
|
#import "lib.typ": num
|
|
#let nb_col = 7
|
|
#scale(90%, reflow: true, table(
|
|
columns: nb_col,
|
|
stroke: none,
|
|
align: center+horizon,
|
|
fill: (x, y) => {
|
|
if (
|
|
i == 1 and (x, y) in ((1, 4), (2, 4), (4, 4), (6, 4))
|
|
) or (
|
|
i == 2 and (x, y) in ((1, 5), (2, 5))
|
|
) {
|
|
highlight-color
|
|
} else {
|
|
none
|
|
}
|
|
},
|
|
inset: (x: 0% + 7pt, y: 0% + 5pt),
|
|
table.hline(),
|
|
table.header(
|
|
table.cell(colspan: nb_col, inset: 3pt)[],
|
|
table.cell(rowspan: 2, eye-2(x: 35pt, y: 30pt, height: 70pt)),
|
|
table.vline(end: 3),
|
|
table.vline(start: 4),
|
|
table.cell(colspan: 3)[*Number of apps*],
|
|
table.vline(end: 3),
|
|
table.vline(start: 4),
|
|
table.cell(colspan: 2)[*Nb Shadow Classes*],
|
|
table.vline(end: 3),
|
|
table.vline(start: 4),
|
|
table.cell(rowspan: 2)[*Identical Code*],
|
|
|
|
[], [%], [% malware],
|
|
[Average], [Median],
|
|
),
|
|
table.hline(),
|
|
table.cell(colspan: nb_col, inset: 3pt)[],
|
|
|
|
..scan_only_shadow.map(e => (
|
|
[*#e.method*],
|
|
num(e.nbapp), [#e.ratioapp%], [#e.ratiomal%],
|
|
num(e.avgshadow), num(e.median),
|
|
[#e.id%]
|
|
)).flatten(),
|
|
|
|
table.cell(colspan: nb_col, inset: 3pt)[],
|
|
table.hline(),
|
|
))
|
|
]
|
|
}
|
|
|
|
#slide(
|
|
title: [Conclusion]
|
|
)[
|
|
#v(1fr)
|
|
#item-by-item[
|
|
- We modeled the class loading algorithm
|
|
- Static Analysis Tools did not
|
|
- We introduced obfuscation techniques based on this model
|
|
- Ambiguous cases exists in the wild
|
|
- We did not find deliberate shadow attacks
|
|
]
|
|
#v(1fr)
|
|
#align(center, text(fill: pirat-color.blue.darken(30%))[Digital Threats: Research and Practice])
|
|
#v(0.5em)
|
|
]
|
|
|
|
#new-section-slide([The Application of Theseus])
|
|
|
|
// TODO put everywhere Theseus Transformeur
|
|
|
|
#slide(
|
|
title: [State of the Art],
|
|
)[
|
|
#align(center+horizon, text(fill: pirat-color.red, size: 30pt)[INSERT SoA])
|
|
]
|
|
|
|
#slide(
|
|
title: [Overview],
|
|
foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[FINIR DESSIN]),
|
|
)[
|
|
// TODO: bien tout rappeler l'objectif
|
|
#set align(center+horizon)
|
|
#theseus-outline()
|
|
]
|
|
|
|
#slide(
|
|
title: [Dynamic Analysis],
|
|
)[
|
|
- Frida: intercepts method calls
|
|
|
|
#v(2em)
|
|
|
|
#uncover("2-")[
|
|
- Android Emulator: runs on computer/server
|
|
- Grodd Runner: clicks buttons // TODO: ref
|
|
]
|
|
|
|
#v(2em)
|
|
#uncover(3)[
|
|
- Phone with adb enable: actuall hardware
|
|
- Human: intelligent button clicker
|
|
]
|
|
]
|
|
|
|
#slide(
|
|
title: [Transformation: Dynamic Code Loading],
|
|
foreground: {
|
|
ghost-6(x: 80%, y: 15%, mirror: true)
|
|
align(horizon+center, line(length: 80%, stroke: (thickness: 3pt, dash: (10pt, 5pt))))
|
|
place(horizon+right, dx: -1em)[
|
|
Collected at Runtime
|
|
|
|
Patched Application
|
|
]
|
|
}
|
|
)[
|
|
// Split schema: observed dyn code loaded / new apk
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
#show image: box.with(width: 58%)
|
|
#get_figure(<fig:th-inserting-dex>)
|
|
]
|
|
|
|
#for i in range(4) {
|
|
// TODO: plutot barrer les lignes au lieux de les remplacer
|
|
if i != 0 { counter("logical-slide").update( n => n - 1 ) }
|
|
|
|
slide(
|
|
title: [Transformation: Reflection],
|
|
//foreground: ghost-6(x: 80%, y: 15%, mirror: true)
|
|
)[
|
|
#show: yes-codly
|
|
#set align(center+horizon)
|
|
|
|
#if i == 1 {
|
|
codly(
|
|
highlighted-lines: (6,),
|
|
..default-codly
|
|
)
|
|
} else if i == 3 {
|
|
codly(
|
|
offset: 5,
|
|
..default-codly
|
|
)
|
|
} else {
|
|
codly(..default-codly)
|
|
}
|
|
|
|
#if i in (0, 1) {
|
|
```java
|
|
ClassLoader cl = MainActivity.class.getClassLoader();
|
|
Class clz = cl.loadClass("Reflectee");
|
|
Object obj = clz.newInstance();
|
|
Method mth = clz.getMethod("myMethod", String.class);
|
|
Object[] args = {(Object)"an argument"};
|
|
String retData = (String) mth.invoke(obj, args);
|
|
```
|
|
} else if i == 2{
|
|
```java
|
|
ClassLoader cl = MainActivity.class.getClassLoader();
|
|
Class clz = cl.loadClass(getFromInternet());
|
|
Object obj = clz.newInstance();
|
|
Method mth = clz.getMethod(getFromInternet(), String.class);
|
|
Object[] args = {(Object)getFromInternet()};
|
|
String retData = (String) mth.invoke(obj, args);
|
|
```
|
|
} else {
|
|
```java
|
|
String retData = (String) mth.invoke(obj, args);
|
|
```
|
|
}
|
|
]
|
|
}
|
|
|
|
#for i in range(5) {
|
|
if i != 0 { counter("logical-slide").update( n => n - 1 ) }
|
|
|
|
slide(
|
|
title: [Reflection Transformation]
|
|
)[
|
|
#show: yes-codly
|
|
#set align(center+horizon)
|
|
#if i == 1 {
|
|
codly(
|
|
offset: 5,
|
|
highlighted-lines: (10,),
|
|
..default-codly
|
|
)
|
|
} else if i == 2 {
|
|
codly(
|
|
offset: 5,
|
|
highlights: (
|
|
(line: 6, start: 0, end: 13, fill: pirat-color.blue),
|
|
(line: 8, start: 3, end: 8, fill: pirat-color.blue),
|
|
(line: 10, start: 3, end: 8, fill: pirat-color.blue),
|
|
(line: 12, start: 18, end: 32, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
} else if i == 3 {
|
|
codly(
|
|
offset: 5,
|
|
highlights: (
|
|
(line: 8, start: 12, end: 19, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
} else if i == 4 {
|
|
codly(
|
|
offset: 5,
|
|
highlights: (
|
|
(line: 7, start: 5, end: 43, fill: pirat-color.blue),
|
|
(line: 8, start: 21, end: 31, fill: pirat-color.blue),
|
|
(line: 8, start: 38, end: 45, fill: pirat-color.blue),
|
|
(line: 8, start: 47, end: 54, fill: pirat-color.blue),
|
|
),
|
|
..default-codly
|
|
)
|
|
} else {
|
|
codly(
|
|
offset: 5,
|
|
..default-codly
|
|
)
|
|
}
|
|
```java
|
|
Object objRet;
|
|
if (T.check_is_reflectee_mymethod_XXXX(mth)) {
|
|
objRet = (Object)((Reflectee) obj).myMethod((String)args[0]);
|
|
} else {
|
|
objRet = mth.invoke(obj, args);
|
|
}
|
|
String retData = (String) objRet;
|
|
```
|
|
]
|
|
}
|
|
|
|
#slide(
|
|
foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[MOCHE]),
|
|
)[
|
|
#set align(center+horizon)
|
|
#theseus-outline()
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Dynamic Analysis],
|
|
foreground: ghost-1(x: 97%, y: 10%, height: 70pt)
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
// TODO: enlever 1er 6iem pass, garder nb failed, remplacer vide par '-' sous '209'
|
|
// enlever nb activity
|
|
#set table(
|
|
fill: (x, y) => {
|
|
if (
|
|
x == 4 and y > 2
|
|
) {
|
|
highlight-color
|
|
} else {
|
|
none
|
|
}
|
|
}
|
|
)
|
|
#scale(100%, reflow: true, get_figure(<tab:th-dyn-visited>))
|
|
]
|
|
|
|
#slide(
|
|
title: [Collected Bytecode],
|
|
foreground: eye-1(x: 5%, y: 70%, height: 70pt)
|
|
)[
|
|
#set align(center+horizon)
|
|
#show link.where(dest: <acr-apk>): it => it.body
|
|
#show link.where(dest: <acr-dex>): it => it.body
|
|
#show figure.caption: none
|
|
#set table(
|
|
fill: (x, y) => {
|
|
if (
|
|
x == 4 and y > 2
|
|
) {
|
|
highlight-color
|
|
} else {
|
|
none
|
|
}
|
|
}
|
|
)
|
|
#scale(90%, reflow: true, get_figure(<tab:th-bytecode-hashes>))
|
|
]
|
|
|
|
#slide(
|
|
foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[MOCHE]),
|
|
)[
|
|
#set align(center+horizon)
|
|
#theseus-outline()
|
|
]
|
|
|
|
#for i in range(3) {
|
|
counter("logical-slide").update( n => n - 1 )
|
|
|
|
slide(
|
|
title: [Added Method Calls],
|
|
)[
|
|
// TODO: remove Before After
|
|
#set align(center+horizon)
|
|
#show link.where(dest: <acr-apk>): it => it.body
|
|
#show link.where(dest: <acr-dex>): it => it.body
|
|
#show figure.caption: none
|
|
#set table(
|
|
fill: (x, y) => {
|
|
if (
|
|
i == 1 and (x == 3 and y > 1)
|
|
) or (
|
|
i == 2 and (x == 4 and y > 1)
|
|
){
|
|
highlight-color
|
|
} else {
|
|
none
|
|
}
|
|
}
|
|
)
|
|
#scale(90%, reflow: true, get_figure(<tab:th-compare-cg>))
|
|
]
|
|
}
|
|
|
|
/*
|
|
#slide(
|
|
title: [Toy Example: New Call Graph],
|
|
foreground: ghost-3(x: 93%, y: 10%)
|
|
)[
|
|
// TODO: Légende des couleurs
|
|
#import "@preview/diagraph:0.3.5": render
|
|
#set align(center+horizon)
|
|
#scale(47%, box(render(
|
|
read("5_theseus/figs/patched_main_main.dot"),
|
|
//width: 100%,
|
|
labels: (name) => { move(dy: -7pt, scale(140%, text(size: 10pt, weight: "bold", name))) }
|
|
)))
|
|
]
|
|
*/
|
|
|
|
#slide(
|
|
title: [Impact on Finishing Rate],
|
|
foreground: {
|
|
let strk = 3pt + pirat-color.blue
|
|
import "slides/icons.typ": arrow
|
|
arrow((360pt, 330pt), (380pt, 310pt), strk: strk)
|
|
arrow((420pt, 330pt), (400pt, 310pt), strk: strk)
|
|
}
|
|
)[
|
|
#set align(center+horizon)
|
|
#show figure.caption: none
|
|
|
|
Original #h(2em) Transformed
|
|
|
|
#box(width: 80%, get_figure(<fig:th-status-npatched-vs-patched>))
|
|
]
|
|
|
|
#slide(
|
|
title: [Conclusion],
|
|
)[
|
|
#item-by-item[
|
|
- We can statically analyse APKs with reflection and dynamic code loading with our method
|
|
- Our dynamic analysis is questionable
|
|
- The dynamically loaded bytecode we intercepted is mainly telemetry and advertisement related
|
|
- We released a tool to instrument APKs
|
|
]
|
|
]
|
|
|
|
#new-section-slide([Conclusion])
|
|
|
|
#slide[
|
|
We showed that:
|
|
|
|
#item-by-item[
|
|
- After five years, more than half the static analysis tools are no longer usable.
|
|
The size of the application seems to be the most significant factor.
|
|
- Android behaviour is complex and not well known.
|
|
In the specific case of class loading, we showed that state-of-the-art tools do not match Android, leading to invalid analyses.
|
|
- APKs can be augmented with instrumentation to improve further analyses with any other tools.
|
|
- Also, dynamic analysis is still very much not trivial.
|
|
]
|
|
]
|
|
|
|
#slide(
|
|
title: [Futur Work],
|
|
foreground: {
|
|
ghost-3(x: 80%, y: 70%)
|
|
ghost-6(x: 20%, y: 30%)
|
|
ghost-7(x: 70%, y: 20%)
|
|
}
|
|
)[
|
|
#set align(center+horizon)
|
|
A lot of engineering, preferably spearheaded by Google.
|
|
]
|
|
|
|
#counter("logical-slide").update( n => n - 1 )
|
|
#slide(
|
|
title: [Future Works]
|
|
)[
|
|
#item-by-item[
|
|
- Benchmark of APKs to evaluate finishing rate
|
|
- Make tools reusing sources from Android Open Source Project
|
|
- Require developpers to provide high coverage tests inputs with the APKs
|
|
]
|
|
]
|
|
|
|
|
|
#empty-slide[
|
|
Questions
|
|
]
|
|
|
|
|
|
/*
|
|
#slide()[
|
|
#get_figure(<fig:th-cg-before-after>))
|
|
]
|
|
|
|
#slide()[
|
|
#pl.toolbox.slide-number
|
|
#context({
|
|
pl.toolbox.all-sections((sections, current) => {
|
|
for i in sections {
|
|
repr(i.at("body").at("text"))
|
|
}
|
|
})
|
|
})
|
|
]
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pagebreak()
|
|
#set page(height: auto, margin: 25mm)
|
|
#bibliography("bibliography.bib")
|
|
|
|
|
|
/*
|
|
* RETOUR 1:
|
|
*
|
|
* Pas de retour en arriere
|
|
* Ne pas se retourner
|
|
*
|
|
* Bon premier jet.
|
|
*
|
|
* - slide text bof
|
|
* - Parti 3: plus dure a comprendre
|
|
* - Expliquer ce qui est fait avant le résultat (surtout parti 3)
|
|
*
|
|
* slite titre problemenatiques: PB1, PB2 PB3
|
|
*
|
|
* Plus d'état de l'art, dans chapitres? redonner contexte au debut des chapitre, en profiter pour l'état de l'art. Pas plus d'un ou deux papiers, si important.
|
|
* Remplacer l'état de l'art dans l'intro par intuition et mettre soa dans chapitre
|
|
*
|
|
* PQ: focu on dcl & refl
|
|
*
|
|
* RQ1: Static, RQ2: Check coherence static / dynamic, RQ3: transformation
|
|
*
|
|
*/
|