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/lib.typ": *
#import "slides/icons.typ" as ico #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": * #import "@preview/codly-languages:0.1.1": *
#show: codly-init.with() #show: codly-init.with()
#let default-codly = ( #let default-codly = (
@ -14,6 +16,8 @@
inset: (y: 0.15em), inset: (y: 0.15em),
highlighted-default-color: highlight-color, highlighted-default-color: highlight-color,
highlight-fill: it => it.lighten(40%), //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() #codly-disable()
@ -84,8 +88,12 @@
)[ )[
#set align(center+horizon) #set align(center+horizon)
#grid( #grid(
columns: (1fr, 1fr), columns: (1fr, 1fr), [
image("slides/imgs/google.png", width: 200pt), #image("slides/imgs/google.png", width: 200pt)
- Smartphones are computers
- Android = linux + Android Runtime
- APK = computer program
],
//image("slides/imgs/phone.png", height: 350pt) //image("slides/imgs/phone.png", height: 350pt)
ico.phone( ico.phone(
height: 350pt, height: 350pt,
@ -274,7 +282,7 @@
foreground: eye-3(x: 3%, y: 5%) foreground: eye-3(x: 3%, y: 5%)
)[ )[
#set align(center+horizon) #set align(center+horizon)
#analyse-apk #ico.analyse()
] ]
#counter("logical-slide").update( n => n - 1 ) #counter("logical-slide").update( n => n - 1 )
@ -289,8 +297,8 @@
== Dynamic Analysis == Dynamic Analysis
#item-by-item[ #item-by-item[
- Run the application - Run the application
- _See_ dynamically loaded bytecode - *See* dynamically loaded bytecode
- _See_ reflection calls - *See* reflection calls
- Limited by code coverage - Limited by code coverage
] ]
], ],
@ -311,20 +319,18 @@
] ]
#slide( #slide(
title: [Which Tools?], title: [Which Tools are _really_ Working?],
foreground: eye-3(x: 3%, y: 5%) foreground: eye-3(x: 3%, y: 5%)
)[ )[
#set align(center+horizon) #set align(center+horizon)
#analyse-apk #ico.analyse()
] #h(10em)
#ico.machinery()
#counter("logical-slide").update( n => n - 1 ) #place(
#slide( center+horizon,
title: [Which Tools are Working?], dy: 120pt,
foreground: eye-3(x: 3%, y: 5%) text(size: 400pt, fill: pirat-color.red)[?]
)[ )
#set align(center+horizon)
#analyse-apk
] ]
#slide( #slide(
@ -338,15 +344,6 @@
#highlight-block(pb1-text) #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( #slide(
title: [Class Loading], title: [Class Loading],
)[ )[
@ -396,7 +393,7 @@
)[ )[
#item-by-item[ #item-by-item[
- Used to select classes implementation - Used to select classes implementation
- More complexe than it looks - More complex than it looks
- Doubious documentation - Doubious documentation
- Not studied in the context of Android Static Analysis - Not studied in the context of Android Static Analysis
] ]
@ -498,8 +495,8 @@
Li #etal (2017): Li #etal (2017):
#v(0pt) #v(0pt)
#item-by-item[ #item-by-item[
- Systematic literature review for Android static analysis - Systematic literature review for Android static analysis (38 tools)
- Lists open-sourced tools - Lists 31 open-sourced tools
- Does not test the tools - Does not test the tools
] ]
#uncover("4-")[Reaves #etal (2016):] #uncover("4-")[Reaves #etal (2016):]
@ -530,7 +527,7 @@
] ]
#slide( #slide(
title: [Methodology], title: [Methodology: RASTA],
foreground: place( foreground: place(
bottom + left, bottom + left,
dx: 88%, dx: 88%,
@ -683,16 +680,17 @@
*/ */
#slide( #slide(
title: [Conclusion], title: [PB1: Conclusion],
)[ )[
#v(1fr) #v(1fr)
//#set align(center) //#set align(center)
#item-by-item[ #item-by-item[
- Over 22 tools, 10 are usable - Over *22* tools, *10 are usable*
- Newer applications are harder to analyse - 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 - 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) #v(1fr)
#align(center, text(fill: pirat-color.blue.darken(30%))[International Conference on Software and Systems Reuse (ICSR 2024)]) #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)[ #place(right+top)[
#set align(left) #set align(left)
#align(center)[Pull Requests:]
#v(-1em)
#link("https://github.com/androguard/androguard/pull/1149")[androguard/pull/1149] \ #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] #link("https://github.com/skylot/jadx/pull/2702")[jadx/pull/2702]
] ]
] ]
@ -1355,15 +1355,15 @@
} }
#slide( #slide(
title: [Conclusion] title: [PB2: Conclusion]
)[ )[
#v(1fr) #v(1fr)
#item-by-item[ #item-by-item[
- We modeled the class loading algorithm - 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 - We introduced obfuscation techniques based on this model
- Ambiguous cases exists in the wild
- We did not find deliberate shadow attacks - We did not find deliberate shadow attacks
- #h(2em) Ambiguous cases exists in the wild
] ]
#v(1fr) #v(1fr)
#align(center, text(fill: pirat-color.blue.darken(30%))[Digital Threats: Research and Practice, vol. 6 (3), 2025]) #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], title: [Theseus: Overview],
)[ )[
#set align(center+horizon) #set align(center+horizon)
#only(1, theseus-outline(stage: "theseus-no-static")) #only(1, theseus-outline(stage: "theseus-no-static", labels: true))
#only(2, theseus-outline(stage: "theseus")) #only(2, theseus-outline(stage: "theseus", labels: true))
] ]
#slide( #slide(
@ -1438,6 +1438,7 @@
#get_figure(<fig:th-inserting-dex>) #get_figure(<fig:th-inserting-dex>)
] ]
/*
#for i in range(4) { #for i in range(4) {
// TODO: plutot barrer les lignes au lieux de les remplacer // TODO: plutot barrer les lignes au lieux de les remplacer
if i != 0 { counter("logical-slide").update( n => n - 1 ) } 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 ) } if i != 0 { counter("logical-slide").update( n => n - 1 ) }
slide( slide(
@ -1498,152 +1499,248 @@
#show: yes-codly #show: yes-codly
#set align(center+horizon) #set align(center+horizon)
#if i == 1 { #scale(90%, reflow: true, grid(
codly( rows: (3em, 2em, 12em),
offset: 5, {
highlighted-lines: (6,), if i == 1 {
..default-codly codly(
) offset: 4,
} else if i == 4 { highlighted-lines: (5,),
codly( ..default-codly
offset: 5, )
highlights: ( } else if i == 3 {
(line: 6, start: 0, end: 25, fill: pirat-color.blue), codly(
), offset: 4,
..default-codly highlights: (
) (line: 6, start: 27, end: 48, fill: pirat-color.blue),
} else { ),
codly( ..default-codly
offset: 5, )
..default-codly } else {
) codly(
} offset: 4,
```java ..default-codly
String retData = (String) mth.invoke(obj, args); )
``` }
```java
#v(-0.5em) Method mth = getMethod();
#align(center+horizon, sym.arrow.b.stroked) String retData = (String) mth.invoke(obj, args);
#v(-0.5em) ```
},
#if i == 1 { {
codly( v(1fr)
offset: 5, align(center+horizon, sym.arrow.b.stroked)
highlighted-lines: (10,), v(1fr)
..default-codly },
) {
} else if i == 3 { if i == 3 {
codly( codly(
offset: 5, offset: 4,
highlights: ( highlights: (
(line: 6, start: 0, end: 13, fill: pirat-color.blue), (line: 10, start: 12, end: 33, fill: pirat-color.blue),
(line: 8, start: 3, end: 8, fill: pirat-color.blue), ),
(line: 10, start: 3, end: 8, fill: pirat-color.blue), ..default-codly
(line: 12, start: 18+9, end: 32, fill: pirat-color.blue), )
), } else if i == 4 {
..default-codly codly(
) offset: 4,
} else if i == 4 { highlights: (
codly( (line: 7, start: 5, end: 43, fill: pirat-color.blue),
offset: 5, (line: 8, start: 21, end: 31, fill: pirat-color.blue),
highlights: ( (line: 8, start: 38, end: 45, fill: pirat-color.blue),
(line: 8, start: 12, end: 19, fill: pirat-color.blue), (line: 8, start: 47, end: 54, fill: pirat-color.blue),
(line: 12, start: 0, end: 25, fill: pirat-color.blue), ),
), ..default-codly
..default-codly )
) } else if i == 5 {
} else if i == 2 { codly(
codly( offset: 4,
offset: 5, highlights: (
highlights: ( (line: 6, start: 0, end: 13, fill: pirat-color.blue),
(line: 7, start: 5, end: 43, fill: pirat-color.blue), (line: 8, start: 3, end: 8, fill: pirat-color.blue),
(line: 8, start: 21, end: 31, fill: pirat-color.blue), (line: 10, start: 3, end: 8, fill: pirat-color.blue),
(line: 8, start: 38, end: 45, fill: pirat-color.blue), (line: 12, start: 18+9, end: 32, fill: pirat-color.blue),
(line: 8, start: 47, end: 54, fill: pirat-color.blue), ),
), ..default-codly
..default-codly )
) } else if i == 6 {
} else { codly(
codly( offset: 4,
offset: 5, highlights: (
..default-codly (line: 8, start: 12, end: 19, fill: pirat-color.blue),
) (line: 12, start: 0, end: 25, fill: pirat-color.blue),
} ),
```java ..default-codly
Object objRet; )
if (T.check_is_reflectee_mymethod_XXXX(mth)) { } else if i < 2 {
objRet = (Object)((Reflectee) obj).myMethod((String)args[0]); codly(
} else { offset: 5,
objRet = mth.invoke(obj, args); ..default-codly
} )
String retData = (String) objRet; } 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]);
} else {
objRet = mth.invoke(obj, args);
}
String retData = (String) objRet;
```
}
v(1fr)
}
))
] ]
} }
#slide( #slide(
foreground: { foreground: {
arrow( }
stroke: 10pt + pirat-color.red, )[
( #set align(center+horizon)
250pt, #theseus-outline()
-400pt, #place(
), bottom+left,
( dx: -20pt,
250pt, dy: -360pt,
-350pt, 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(
foreground: {
place(
bottom+left,
dx: 200pt,
dy: -50pt,
ellipse(
width: 100pt,
height: 300pt,
stroke: 10pt + pirat-color.red,
) )
) )
arrow( place(
stroke: 10pt + pirat-color.red, bottom+left,
( dx: 140pt,
130pt, dy: -370pt,
-400pt, text(weight: "bold", fill: pirat-color.red, size: 30pt)[Dynamic Results]
),
(
180pt,
-320pt,
)
)
arrow(
stroke: 10pt + pirat-color.red,
(
370pt,
-400pt,
),
(
320pt,
-320pt,
)
) )
} }
)[ )[
#set align(center+horizon) #set align(center+horizon)
#theseus-outline() #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 ) #for i in range(3) {
#slide( let hide-if-not-2(i, body) = if i == 2 { body } else { hide(body) }
title: [Dynamic Analysis], slide(
foreground: ghost-1(x: 97%, y: 10%, height: 70pt) title: [Dynamic Analysis],
)[ foreground: ghost-1(x: 97%, y: 10%, height: 70pt)
#set align(center+horizon) )[
#show figure.caption: none #import "5_theseus/X_var.typ": *
// TODO: enlever 1er 6iem pass, garder nb failed, remplacer vide par '-' sous '209' #import "lib.typ": num, mypercent
// enlever nb activity #set align(center+horizon)
#set table( #let nb_col = 4
fill: (x, y) => { #stack(dir: ltr, table(
if ( columns: nb_col,
x == 4 and y > 2 stroke: none,
) { fill: (x, y) => {
highlight-color if (
} else { (x == 2 and y > 2 and i == 1) or
none ((x, y) in ((1, 6), (1, 7)) and i == 2)
} ) {
} highlight-color
) } else {
#scale(100%, reflow: true, get_figure(<tab:th-dyn-visited>)) none
] }
},
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( #slide(
title: [Collected Bytecode], title: [Collected Bytecode],
@ -1696,6 +1793,12 @@
-250pt, -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) #set align(center+horizon)
@ -1703,7 +1806,7 @@
] ]
#for i in range(3) { #for i in range(3) {
counter("logical-slide").update( n => n - 1 ) if i != 0 {counter("logical-slide").update( n => n - 1 )}
slide( slide(
title: [Added Method Calls], title: [Added Method Calls],
@ -1734,7 +1837,7 @@
table.header( table.header(
//[SHA 256], [Original CG edges], [New CG edges], [Edges added], [Reflection edges added], //[SHA 256], [Original CG edges], [New CG edges], [Edges added], [Reflection edges added],
table.cell(rowspan: 2)[APK SHA 256], 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(), table.hline(),
..compared_callgraph.map( ..compared_callgraph.map(
@ -1788,13 +1891,18 @@
] ]
#slide( #slide(
title: [Conclusion], title: [PB3: Conclusion],
)[ )[
#set list(indent: 1em)
#item-by-item[ #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 - Our dynamic analysis is questionable
- The dynamically loaded bytecode we intercepted is mainly telemetry and advertisement related - The dynamically loaded bytecode we intercepted is *mainly telemetry and advertisement* related
- We released a tool to instrument APKs ]
#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 height = big_icon_size + small_icon_size /2 + arrow_gap
let width = 6.5 * small_icon_size + 2 * big_icon_size let width = 6.5 * small_icon_size + 2 * big_icon_size
let app1 = apk( let app1 = apk(
height: small_icon_size height: small_icon_size,
fill: red,
) )
let app2 = apk( let app2 = apk(
height: small_icon_size, height: small_icon_size,
@ -305,6 +306,24 @@
dy: patcher_pos.at(1), dy: patcher_pos.at(1),
patcher, 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( arrow(
stroke: arrow_width + black, stroke: arrow_width + black,
( (
@ -376,6 +395,8 @@
small_icon_size: 60pt, small_icon_size: 60pt,
big_icon_size: 90pt, big_icon_size: 90pt,
stage: "theseus", stage: "theseus",
labels: false,
rasta: false,
) = context { ) = context {
let stages = ( let stages = (
"static-only", "static-only",
@ -515,6 +536,43 @@
height: height, height: height,
//stroke: black, //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" { if stage == "static-only" {
place( place(
left+bottom, left+bottom,
@ -725,6 +783,7 @@
if stage in ( if stage in (
"theseus", "theseus",
"theseus-vs-static", "theseus-vs-static",
"theseus-no-static"
) { ) {
arrow( arrow(
stroke: arrow_width + black, stroke: arrow_width + black,