include feedbacks
Some checks failed
/ test_checkout (push) Failing after 35s

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2025-11-27 05:31:22 +01:00
parent afe956180f
commit 21c2a58f3c
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
2 changed files with 348 additions and 181 deletions

View file

@ -2,7 +2,9 @@
#import "slides/lib.typ": *
#import "slides/icons.typ" as ico
#import "@preview/codly:1.3.0": *
#import "@local/codly:1.3.1": *
// Require local install, fix needed for highlight-inset
// TMP="$(mktemp -d)" && curl -L https://github.com/Dherse/codly/archive/refs/tags/v1.3.1.zip -o "${TMP}/c.zip" && unzip -d "${TMP}" "${TMP}/c.zip" && mkdir -p ~/.local/share/typst/packages/local/codly && mv "${TMP}/codly-1.3.1" ~/.local/share/typst/packages/local/codly/1.3.1 && rm -rf "${TMP}"
#import "@preview/codly-languages:0.1.1": *
#show: codly-init.with()
#let default-codly = (
@ -14,6 +16,8 @@
inset: (y: 0.15em),
highlighted-default-color: highlight-color,
highlight-fill: it => it.lighten(40%), //highlight-color,
highlight-inset: (x: 0pt, y: 0pt),
highlight-outset: (x: 0.15pt, y: 0.15em),
)
#codly-disable()
@ -84,8 +88,12 @@
)[
#set align(center+horizon)
#grid(
columns: (1fr, 1fr),
image("slides/imgs/google.png", width: 200pt),
columns: (1fr, 1fr), [
#image("slides/imgs/google.png", width: 200pt)
- Smartphones are computers
- Android = linux + Android Runtime
- APK = computer program
],
//image("slides/imgs/phone.png", height: 350pt)
ico.phone(
height: 350pt,
@ -274,7 +282,7 @@
foreground: eye-3(x: 3%, y: 5%)
)[
#set align(center+horizon)
#analyse-apk
#ico.analyse()
]
#counter("logical-slide").update( n => n - 1 )
@ -289,8 +297,8 @@
== Dynamic Analysis
#item-by-item[
- Run the application
- _See_ dynamically loaded bytecode
- _See_ reflection calls
- *See* dynamically loaded bytecode
- *See* reflection calls
- Limited by code coverage
]
],
@ -311,20 +319,18 @@
]
#slide(
title: [Which Tools?],
title: [Which Tools are _really_ Working?],
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
#ico.analyse()
#h(10em)
#ico.machinery()
#place(
center+horizon,
dy: 120pt,
text(size: 400pt, fill: pirat-color.red)[?]
)
]
#slide(
@ -338,15 +344,6 @@
#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],
)[
@ -396,7 +393,7 @@
)[
#item-by-item[
- Used to select classes implementation
- More complexe than it looks
- More complex than it looks
- Doubious documentation
- Not studied in the context of Android Static Analysis
]
@ -498,8 +495,8 @@
Li #etal (2017):
#v(0pt)
#item-by-item[
- Systematic literature review for Android static analysis
- Lists open-sourced tools
- Systematic literature review for Android static analysis (38 tools)
- Lists 31 open-sourced tools
- Does not test the tools
]
#uncover("4-")[Reaves #etal (2016):]
@ -530,7 +527,7 @@
]
#slide(
title: [Methodology],
title: [Methodology: RASTA],
foreground: place(
bottom + left,
dx: 88%,
@ -683,16 +680,17 @@
*/
#slide(
title: [Conclusion],
title: [PB1: Conclusion],
)[
#v(1fr)
//#set align(center)
#item-by-item[
- Over 22 tools, 10 are usable
- Over *22* tools, *10 are usable*
- Newer applications are harder to analyse
- Applications with more bytecode 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
- Confirms and *extends Reaves #etal*
- Docker containers for tool *released*
]
#v(1fr)
#align(center, text(fill: pirat-color.blue.darken(30%))[International Conference on Software and Systems Reuse (ICSR 2024)])
@ -1262,8 +1260,10 @@
)
#place(right+top)[
#set align(left)
#align(center)[Pull Requests:]
#v(-1em)
#link("https://github.com/androguard/androguard/pull/1149")[androguard/pull/1149] \
#link("https://github.com/soot-oss/soot/pull/2211")[soot/pull/2211] \
#link("https://github.com/soot-oss/soot/pull/2211")[soot/pull/2211] (#text(fill: green)[merged])\
#link("https://github.com/skylot/jadx/pull/2702")[jadx/pull/2702]
]
]
@ -1355,15 +1355,15 @@
}
#slide(
title: [Conclusion]
title: [PB2: Conclusion]
)[
#v(1fr)
#item-by-item[
- We modeled the class loading algorithm
- Static Analysis Tools did not
- #h(2em) 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
- #h(2em) Ambiguous cases exists in the wild
]
#v(1fr)
#align(center, text(fill: pirat-color.blue.darken(30%))[Digital Threats: Research and Practice, vol. 6 (3), 2025])
@ -1396,8 +1396,8 @@
title: [Theseus: Overview],
)[
#set align(center+horizon)
#only(1, theseus-outline(stage: "theseus-no-static"))
#only(2, theseus-outline(stage: "theseus"))
#only(1, theseus-outline(stage: "theseus-no-static", labels: true))
#only(2, theseus-outline(stage: "theseus", labels: true))
]
#slide(
@ -1438,6 +1438,7 @@
#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 ) }
@ -1487,9 +1488,9 @@
```
}
]
}
}*/
#for i in range(5) {
#for i in range(7) {
if i != 0 { counter("logical-slide").update( n => n - 1 ) }
slide(
@ -1498,63 +1499,51 @@
#show: yes-codly
#set align(center+horizon)
#if i == 1 {
#scale(90%, reflow: true, grid(
rows: (3em, 2em, 12em),
{
if i == 1 {
codly(
offset: 5,
highlighted-lines: (6,),
offset: 4,
highlighted-lines: (5,),
..default-codly
)
} else if i == 4 {
} else if i == 3 {
codly(
offset: 5,
offset: 4,
highlights: (
(line: 6, start: 0, end: 25, fill: pirat-color.blue),
(line: 6, start: 27, end: 48, fill: pirat-color.blue),
),
..default-codly
)
} else {
codly(
offset: 5,
offset: 4,
..default-codly
)
}
```java
Method mth = getMethod();
String retData = (String) mth.invoke(obj, args);
```
#v(-0.5em)
#align(center+horizon, sym.arrow.b.stroked)
#v(-0.5em)
#if i == 1 {
},
{
v(1fr)
align(center+horizon, sym.arrow.b.stroked)
v(1fr)
},
{
if i == 3 {
codly(
offset: 5,
highlighted-lines: (10,),
..default-codly
)
} else if i == 3 {
codly(
offset: 5,
offset: 4,
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+9, end: 32, fill: pirat-color.blue),
(line: 10, start: 12, end: 33, fill: pirat-color.blue),
),
..default-codly
)
} else if i == 4 {
codly(
offset: 5,
highlights: (
(line: 8, start: 12, end: 19, fill: pirat-color.blue),
(line: 12, start: 0, end: 25, fill: pirat-color.blue),
),
..default-codly
)
} else if i == 2 {
codly(
offset: 5,
offset: 4,
highlights: (
(line: 7, start: 5, end: 43, fill: pirat-color.blue),
(line: 8, start: 21, end: 31, fill: pirat-color.blue),
@ -1563,13 +1552,45 @@
),
..default-codly
)
} else {
} else if i == 5 {
codly(
offset: 4,
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+9, end: 32, fill: pirat-color.blue),
),
..default-codly
)
} else if i == 6 {
codly(
offset: 4,
highlights: (
(line: 8, start: 12, end: 19, fill: pirat-color.blue),
(line: 12, start: 0, end: 25, fill: pirat-color.blue),
),
..default-codly
)
} else if i < 2 {
codly(
offset: 5,
..default-codly
)
} else {
codly(
offset: 4,
..default-codly
)
}
v(1fr)
if i in (0, 1) {
```java
String retData = obj.myMethod((String)args[0]);
```
} else {
```java
Method mth = getMethod();
Object objRet;
if (T.check_is_reflectee_mymethod_XXXX(mth)) {
objRet = (Object)((Reflectee) obj).myMethod((String)args[0]);
@ -1578,72 +1599,148 @@
}
String retData = (String) objRet;
```
}
v(1fr)
}
))
]
}
#slide(
foreground: {
arrow(
stroke: 10pt + pirat-color.red,
}
)[
#set align(center+horizon)
#theseus-outline()
#place(
bottom+left,
dx: -20pt,
dy: -360pt,
box[
#for i in range(3) {
place(
dx: i*10pt,
dy: i*10pt,
ico.apk(height: 60pt, fill: red)
)
}
#place(dy: 85pt)[*RASTA*]
]
)
#arrow(
stroke: 6pt + black,
(
250pt,
-400pt,
4pt,
-245pt
),
(
250pt,
-350pt,
)
)
arrow(
stroke: 10pt + pirat-color.red,
(
130pt,
-400pt,
4pt,
-195pt,
),
(
180pt,
-320pt,
)
)
arrow(
]
#counter("logical-slide").update( n => n - 1 )
#slide(
foreground: {
place(
bottom+left,
dx: 200pt,
dy: -50pt,
ellipse(
width: 100pt,
height: 300pt,
stroke: 10pt + pirat-color.red,
(
370pt,
-400pt,
),
(
320pt,
-320pt,
)
)
place(
bottom+left,
dx: 140pt,
dy: -370pt,
text(weight: "bold", fill: pirat-color.red, size: 30pt)[Dynamic Results]
)
}
)[
#set align(center+horizon)
#theseus-outline()
#place(
bottom+left,
dx: -20pt,
dy: -360pt,
box[
#for i in range(3) {
place(
dx: i*10pt,
dy: i*10pt,
ico.apk(height: 60pt, fill: red)
)
}
#place(dy: 85pt)[*RASTA*]
]
)
#arrow(
stroke: 6pt + black,
(
4pt,
-245pt
),
(
4pt,
-195pt,
),
)
]
#counter("logical-slide").update( n => n - 1 )
#slide(
#for i in range(3) {
let hide-if-not-2(i, body) = if i == 2 { body } else { hide(body) }
slide(
title: [Dynamic Analysis],
foreground: ghost-1(x: 97%, y: 10%, height: 70pt)
)[
#import "5_theseus/X_var.typ": *
#import "lib.typ": num, mypercent
#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(
#let nb_col = 4
#stack(dir: ltr, table(
columns: nb_col,
stroke: none,
fill: (x, y) => {
if (
x == 4 and y > 2
(x == 2 and y > 2 and i == 1) or
((x, y) in ((1, 6), (1, 7)) and i == 2)
) {
highlight-color
} else {
none
}
}
)
#scale(100%, reflow: true, get_figure(<tab:th-dyn-visited>))
},
inset: 7pt,
align: center+horizon,
table.header(
table.hline(),
table.cell(colspan: nb_col, inset: 2pt)[],
table.cell(rowspan: 2)[],
table.cell(rowspan: 2)[nb apk],
table.vline(end: 3),
table.vline(start: 4),
table.cell(colspan: 2, inset: (bottom: 0pt))[activities visited],
[0], [$>= 1$],
),
table.cell(colspan: nb_col, inset: 2pt)[],
table.hline(),
table.cell(colspan: nb_col, inset: 2pt)[],
[All], num(dyn_res.all.nb), num(dyn_res.all.z_act_visited), num(dyn_res.all.nz_act_visited),
[With Reflection], num(dyn_res.reflection.nb), num(dyn_res.reflection.z_act_visited), num(dyn_res.reflection.nz_act_visited),
[With Code Loading], num(dyn_res.code_loading.nb), num(dyn_res.code_loading.z_act_visited), num(dyn_res.code_loading.nz_act_visited),
table.cell(colspan: nb_col, inset: 2pt)[],
table.hline(),
), h(3em), hide-if-not-2(i)[
#set list(spacing: 2em)
- *Reflection* detected on \ #strong(mypercent(dyn_res.reflection.nb, dyn_res.all.nb)) of APKs tested
- *DLC* detected on \ #strong(mypercent(dyn_res.code_loading.nb, dyn_res.all.nb)) of APKs tested
])
]
}
#slide(
title: [Collected Bytecode],
@ -1696,6 +1793,12 @@
-250pt,
)
)
place(
bottom+left,
dx: 680pt,
dy: -350pt,
text(weight: "bold", fill: pirat-color.red, size: 30pt)[#set align(center); Improved \ Results?]
)
}
)[
#set align(center+horizon)
@ -1703,7 +1806,7 @@
]
#for i in range(3) {
counter("logical-slide").update( n => n - 1 )
if i != 0 {counter("logical-slide").update( n => n - 1 )}
slide(
title: [Added Method Calls],
@ -1734,7 +1837,7 @@
table.header(
//[SHA 256], [Original CG edges], [New CG edges], [Edges added], [Reflection edges added],
table.cell(rowspan: 2)[APK SHA 256],
table.cell(colspan: nb_col - 1)[Number of Call Graph edges], [Diff (Total After - Before)], [Added Reflection],
table.cell(colspan: nb_col - 1)[Number of Call Graph edges], [Diff (Total After - Before)], [Replaced Reflection],
),
table.hline(),
..compared_callgraph.map(
@ -1788,13 +1891,18 @@
]
#slide(
title: [Conclusion],
title: [PB3: Conclusion],
)[
#set list(indent: 1em)
#item-by-item[
- We can statically analyse APKs with reflection and dynamic code loading with our method
- 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
- The dynamically loaded bytecode we intercepted is *mainly telemetry and advertisement* related
]
#only("4-", underline[Software Contributions:])
#item-by-item(start: 5)[
- *Androscalpel*: rust crate to *parse, modify and generate bytecode*
- *Theseus*: tool implementing the method presented here
]
]

View file

@ -230,7 +230,8 @@
let height = big_icon_size + small_icon_size /2 + arrow_gap
let width = 6.5 * small_icon_size + 2 * big_icon_size
let app1 = apk(
height: small_icon_size
height: small_icon_size,
fill: red,
)
let app2 = apk(
height: small_icon_size,
@ -305,6 +306,24 @@
dy: patcher_pos.at(1),
patcher,
)
{
set text(weight: "semibold", fill: luma(30%))
place(
left+top,
dx: analyser_pos.at(0) + 0.5em,
dy: analyser_pos.at(1) - 1.5em,
)[Static Analysis]
place(
left+top,
dx: rprt_pos.at(0) - 1em,
dy: rprt_pos.at(1) - 2.5em,
)[#set align(center); Reflection \ Data]
place(
left+top,
dx: patcher_pos.at(0) + 0.5em,
dy: patcher_pos.at(1) - 1.5em,
)[Patching]
}
arrow(
stroke: arrow_width + black,
(
@ -376,6 +395,8 @@
small_icon_size: 60pt,
big_icon_size: 90pt,
stage: "theseus",
labels: false,
rasta: false,
) = context {
let stages = (
"static-only",
@ -515,6 +536,43 @@
height: height,
//stroke: black,
{
if labels {
set text(weight: "semibold", fill: luma(30%))
if stage != "static-only" {
place(
left+bottom,
dx: rprt_pos2.at(0) - 1.4em,
dy: rprt_pos2.at(1) - rprt_size.height - 0.5em,
)[#set align(center); Reflection \ Data]
place(
left+bottom,
dx: dex_pos0.at(0) - 4em,
dy: dex_pos0.at(1) + 0.8em,
)[Dyn Loaded Code]
place(
left+bottom,
dx: patcher_pos.at(0) - 0.5em,
dy: patcher_pos.at(1) - patcher_size.height - 0.5em,
)[Patching]
place(
left+bottom,
dx: phone_pos.at(0) - 1em,
dy: phone_pos.at(1) - phone_size.height - 0.5em,
)[#set align(center); Dynamic \ Analysis]
}
if stage in (
"theseus",
"static-vs-dyn",
"theseus-vs-static",
"static-only"
) {
place(
left+bottom,
dx: analyser_pos.at(0) - 1.5em,
dy: analyser_pos.at(1) + 1em,
)[Static Analysis]
}
}
if stage == "static-only" {
place(
left+bottom,
@ -725,6 +783,7 @@
if stage in (
"theseus",
"theseus-vs-static",
"theseus-no-static"
) {
arrow(
stroke: arrow_width + black,