diff --git a/slides.typ b/slides.typ index 16af394..5a4fa1e 100644 --- a/slides.typ +++ b/slides.typ @@ -27,8 +27,7 @@ aspect-ratio : "16-9", title : [From Large Scale Analysis to Dynamic Deobfuscation], subtitle : [The Woes of Android Reverse Engineering], - event : [], //[PhD Defense], - short-title : [], //[PhD Defense], + footer-text : [Jean-Marie Mineau PhD Defense], //short-event : [Rennes, 2025/12/9], title-size : 32pt, section-size : 18pt, @@ -113,36 +112,6 @@ ) ] -#slide( - title: [Analysing Applications: Which Tools?], - foreground: eye-3(x: 3%, y: 5%) -)[ - #set align(center+horizon) - #move(dx: -50pt, image("slides/imgs/apk-analysis.svg", width: 300pt)) -] - -// something is broken, so hack to keep the page number at the same -#counter("logical-slide").update( n => n - 1 ) - -#slide( - title: [Analysing Applications: Which Tools?], -)[ - #set list(spacing: 3em) - #item-by-item[ - - #cite(, form: "prose"): systematic literature review for Android static analysis, lists open-sourced tools - - #cite(, form: "prose"): tests analysis tools, raises concerns about reusability and analysis of - real-world applications - ] -] - -// something is broken, so hack to keep the page number at the same -#counter("logical-slide").update( n => n - 1 ) -#slide( - title: [Analysing Applications: Which Tools?], -)[ - #highlight-block(pb1-text) -] - #slide( title: [Obfuscation], //foreground: eye-1(x: 95%, y: 85%, mirror: true) @@ -225,21 +194,100 @@ #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 - #codly( - skips: ((3, 10), (5, 10), (6, 10)), - ..default-codly - ) - #scale(100%)[ - ```java - public class Foo { - public static String bar(String arg) { - } - } + #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( + 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: [Analysing Applications: Which Tools?], + foreground: eye-3(x: 3%, y: 5%) +)[ + #set align(center+horizon) + #move(dx: -50pt, image("slides/imgs/apk-analysis.svg", width: 300pt)) +] + +#slide( + title: [Problem Statement 1], +)[ + #highlight-block(pb1-text) ] #slide( @@ -299,13 +347,13 @@ #counter("logical-slide").update( n => n - 1 ) #slide( - title: [Class Loading], + title: [Problem Statement 3], )[ #highlight-block(pb2-text) ] #slide( - foreground: ghost-5(x: 10%, y: 7%) + title: [Deobuscation], )[ #set align(center+horizon) #grid( @@ -313,47 +361,55 @@ gutter: 2em, [ == Dynamic Analysis - #item-by-item[ - - Run the application - - _See_ dynamically loaded bytecode - - _See_ reflection calls - - Limited by code coverage - ] + + Easier to solve Dynamic Code Loading and Reflection Calls ], [ == 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 - ] + Better code coverage ], - grid.cell(colspan: 2, uncover(8)[ + grid.cell(colspan: 2, uncover(2)[ #text(size: 30pt)[Can we combine both?] ]), ) ] -#slide[ +#counter("logical-slide").update( n => n - 1 ) +#slide( + title: [Problem Statement 3], +)[ #highlight-block(pb3-text) ] -#slide[ - #highlight-block(pb1-text) - - - - #highlight-block(pb2-text) - - - - #highlight-block(pb3-text) +#slide( + foreground: rotate(30deg, smallcaps(text(fill: pirat-color.red, size: 50pt)[Faire un dessin])) +)[ + // TODO Outline / problematics / drawing ] #new-section-slide([Tool Reusability]) +#slide( + title: [State of the Art], +)[ + #set list(spacing: 0.5em) + Li #etal: + #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:] + #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] )[ @@ -398,8 +454,6 @@ #set align(center+horizon) #show figure.caption: none #scale(100%, get_figure()) - - //#text(size: 25pt)[We check if the results *exist* after running a tool] ] #counter("logical-slide").update( n => n - 1 ) @@ -445,6 +499,7 @@ #scale(100%, get_figure()) ] +/* #counter("logical-slide").update( n => n - 1 ) #slide( title: [Results], @@ -505,34 +560,22 @@ #text(size: 22pt)[Finishing rate as a function of the bytecode size, for APKs discovered in 2022] ] +*/ #slide( title: [Conclusion], - foreground: { - place( - bottom + left, - text(fill: pirat-color.blue)[International Conference on Software and Systems Reuse (ICSR 2024)] - ) - } )[ - #set align(center) + #v(1fr) + //#set align(center) #item-by-item[ - - Over 22 tools, 10 are usable (*less than half*) + - 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 ] -] - -#slide[ - #set align(center) - // Sous titre dans la conclusion - #text(size: 22pt)[21st International Conference on Software and Systems Reuse (ICSR 2024)] - - #v(2em) - - #show regex("\[\d+\]"): none - #cite(, form: "full") + #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]) @@ -579,35 +622,107 @@ ] #slide( - title: [Android Ecosystem] + title: [State of the Art], + //foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[State of the Art]) )[ - #set align(center+horizon) - #show figure.caption: none - #grid( - columns: (3fr, 1fr), - scale(reflow: true, get_figure()), - [ - #set align(left) - #set text(size: 20pt) - #set list(marker: [-]) - - === Types of classes: - - - APK Classes - - Platform Classes - - SDK Classes - - Hidden APIs - ] - ) - // TODO: hightlight + #set list(spacing: 3em) + #item-by-item[ + - Previous contributions focus on Java runtime + - Android related contributions focus on Dynamic Code Loading + ] ] +#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()), + [ + #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] + title: [Android ClassLoaders], // TODO CHANGE DRAWING + foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[DESSIN RUNTIME CL \ \ WITH DELEGATION]) )[ + /* #set align(center+horizon) #show figure.caption: none #scale(60%, reflow: true, get_figure()) + */ ] #slide( @@ -704,6 +819,9 @@ === `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 @@ -755,9 +873,7 @@ else: return f"classes{index+1}.dex" ```) - // Donner example - `classes0.dex` ? - - `classes1.dex` ? - `classes02.dex` ? - `classes10.dex` ? ] @@ -808,7 +924,7 @@ columns: (1fr, 1fr), column-gutter: 2em, yes-codly[ - #scale(60%, reflow: true, + #scale(55%, reflow: true, ```python def get_dex_name(index: int): if index == 0: @@ -829,7 +945,9 @@ return load_from_file(dex_file, class_name) else: raise ClassNotFoundError() - ```) // TODO: nomer And Cl Alg + ```) + #v(-1em) + #smallcaps(text(size: 15pt)[Android Class Loading Algorithm]) ], [ #set align(left) #set text(size: 18pt) @@ -852,6 +970,8 @@ #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 @@ -861,11 +981,10 @@ show table: set align(center+horizon) it } - #show "not working": "attack not successfull" - #show "working": "attack successfull" - #show "works": "successfull" + #show "not working": "attack failed" + #show "working": "attack sucessful" + #show "works": "sucessful" #scale(100%, reflow: true, get_figure()) - // TODO: IF PR: Add REF ] #slide( @@ -887,33 +1006,67 @@ if i != 0 { counter("logical-slide").update( n => n - 1 ) } slide( title: [In the Wild: 49 975 APKs], - foreground: eye-2(x: 8%, y: 67%, height: 70pt) )[ #set align(center+horizon) - #show figure.caption: none - #show link.where(dest: ): it => it.body - #set table( + // TODO: Simplifier table, mettre nb apk dans titre + // enlever SDK et 1ere partie 100% + //#scale(90%, reflow: true, get_figure()) + #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, 13), (2, 13), (4, 13), (8, 13)) + i == 1 and (x, y) in ((1, 4), (2, 4), (4, 4), (6, 4)) ) or ( - i == 2 and (x, y) in ((1, 14), (2, 14)) + i == 2 and (x, y) in ((1, 5), (2, 5)) ) { highlight-color } else { none } - } - ) - // TODO: Simplifier table, mettre nb apk dans titre - // enlever SDK et 1ere partie 100% - #scale(90%, reflow: true, get_figure()) + }, + 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 @@ -921,28 +1074,18 @@ - 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) ] -#slide[ - #set align(center) - // Faire apparaitre a chaque étape - #text(size: 22pt)[Digital Threats: Research and Practice]) - - #v(2em) - - #show regex("\[\d+\]"): none - #cite(, form: "full") -] - - #new-section-slide([The Application of Theseus]) +// TODO put everywhere Theseus Transformeur + #slide( title: [Overview], - foreground: { - set align(center+horizon) - rotate(30deg, text(fill: pirat-color.red, size: 30pt)[Moche faire un dessin]) - } + foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[Moche faire un dessin]), )[ // TODO: bien tout rappeler l'objectif // TODO: SOA @@ -986,7 +1129,7 @@ if i != 0 { counter("logical-slide").update( n => n - 1 ) } slide( - title: [Reflection], + title: [Transformation: Reflection], //foreground: ghost-6(x: 80%, y: 15%, mirror: true) )[ #show: yes-codly @@ -1189,10 +1332,9 @@ #set align(center+horizon) #show figure.caption: none #scale(90%, reflow: true, get_figure()) - // Fleche original - // Fleche theseus + // TODO: Fleche original + // TODO: Fleche theseus // - // Theseus Transformeur ] #slide( @@ -1235,10 +1377,10 @@ #counter("logical-slide").update( n => n - 1 ) #slide( - title: [Futur Work] + title: [Future Works] )[ #item-by-item[ - - Benchmark to evaluate finishing rate + - 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 ] @@ -1278,6 +1420,9 @@ /* * RETOUR 1: * +* Pas de retour en arriere +* Ne pas se retourner +* * Bon premier jet. * * - slide text bof @@ -1295,15 +1440,8 @@ * 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 * -* Pb Statement: lisibilité! -* * PQ: focu on dcl & refl * -* Obfuscation: fleche vers deobfuscation -* -* Intro, dessin pas a pas dans l'intro en fonction de ce qui se passe dans l'intro * RQ1: Static, RQ2: Check coherence static / dynamic, RQ3: transformation * -* Mettre Theseus Tranformeur un peu partout! -* */ diff --git a/slides/lib.typ b/slides/lib.typ index 4316e7e..76d951d 100644 --- a/slides/lib.typ +++ b/slides/lib.typ @@ -19,6 +19,8 @@ rgb("#E69426"), pirat-color.red, ) +#let etal = [_et al._] + #let highlight-block(body) = { set text(fill: white) block( @@ -73,22 +75,8 @@ pirat-color.red, } */ -#let ghost( - img, x: 0pt, - y: 0pt, - mirror: false, - rot: 0deg, - height: 100pt -) = context { - let img = image(img, height: height) - if mirror { - img = scale(x: -100%, img) - } - if rot != 0deg { - img = rotate(rot, img) - } - - let s = measure(img) +#let place-fg(x: 0pt, y: 0pt, body) = context { + let s = measure(body) let hx = s.width / 2 let hy = s.height / 2 @@ -96,10 +84,27 @@ pirat-color.red, bottom + left, dx: x - hx, dy: -y + hy, - img + body ) } +#let ghost( + img, x: 0pt, + y: 0pt, + mirror: false, + rot: 0deg, + height: 100pt +) = { + let img = image(img, height: height) + if mirror { + img = scale(x: -100%, img) + } + if rot != 0deg { + img = rotate(rot, img) + } + place-fg(x: x, y: y, img) +} + #let ghost-1 = ghost.with("imgs/ghosts/ghost-1.png") #let ghost-2 = ghost.with("imgs/ghosts/ghost-2.png") #let ghost-3 = ghost.with("imgs/ghosts/ghost-3.png") @@ -111,3 +116,30 @@ pirat-color.red, #let eye-2 = ghost.with("imgs/ghosts/eye-2.png") #let eye-3 = ghost.with("imgs/ghosts/eye-3.png") #let eye-4 = ghost.with("imgs/ghosts/eye-4.png") + +#let arrow(start, end, strk: 3pt + black) = { + let strk = stroke(strk) + start.at(1) = -start.at(1) + end.at(1) = -end.at(1) + let (xe, ye) = end + let (xs, ys) = start + let w = xe.pt() - xs.pt() + let h = ye.pt() - ys.pt() + let len = if w == 0pt and h == 0pt { + 1pt + } else { + calc.sqrt(w*w + h*h) + } + let cos = w / len + let sin = h / len + + place(bottom + left, line(start: start, end: end, stroke: strk)) + place(bottom + left, polygon( + fill: strk.paint, + stroke: strk, + end, + (xe + strk.thickness * (sin - cos), ye - strk.thickness * (sin + cos )), + (xe - strk.thickness * (sin + cos), ye - strk.thickness * (sin - cos )), + )) +} + diff --git a/slides/sns_polylux_template.typ b/slides/sns_polylux_template.typ index 2e5a121..2ef1398 100644 --- a/slides/sns_polylux_template.typ +++ b/slides/sns_polylux_template.typ @@ -43,9 +43,8 @@ cmyk(25%,7%,0%,0%), // Data #let sns-polylux-template_title = state("title", none) -#let sns-polylux-template_short-title = state("short-title", none) #let sns-polylux-template_subtitle = state("subtitle", none) -#let sns-polylux-template_event = state("event", none) +#let sns-polylux-template_footer-text = state("footer-text", none) #let sns-polylux-template_short-event = state("short-event", none) #let sns-polylux-template_authors = state("authors", none) @@ -77,8 +76,7 @@ cmyk(25%,7%,0%,0%), // Data title : none, subtitle : none, - short-title : none, - event : none, + footer-text : none, short-event : none, logo-2 : none, logo-1 : none, @@ -115,11 +113,7 @@ cmyk(25%,7%,0%,0%), ) sns-polylux-template_title.update(title) sns-polylux-template_subtitle.update(subtitle) - if short-title != none { sns-polylux-template_short-title.update(short-title) } - else { sns-polylux-template_short-title.update(title) } - sns-polylux-template_event.update(event) - if short-event != none { sns-polylux-template_short-event.update(short-event) } - else { sns-polylux-template_short-event.update(event) } + if footer-text != none { sns-polylux-template_footer-text.update(footer-text) } sns-polylux-template_logo-2.update(logo-2) sns-polylux-template_logo-1.update(logo-1) sns-polylux-template_authors.update(authors) @@ -171,7 +165,7 @@ cmyk(25%,7%,0%,0%), let content = align(top + center, context( { let title = sns-polylux-template_title.at(here()) let subtitle = sns-polylux-template_subtitle.at(here()) - let event = sns-polylux-template_event.at(here()) + let footer-text = sns-polylux-template_footer-text.at(here()) let authors = sns-polylux-template_authors.at(here()) let title-size = sns-polylux-template_title-size.at(here()) let logo = { @@ -224,7 +218,7 @@ cmyk(25%,7%,0%,0%), place( bottom + center, dy: -1cm, - text(fill: sns-polylux-template_background-color.at(here()), size: 22pt, event) + text(fill: sns-polylux-template_background-color.at(here()), size: 22pt, footer-text) ) if logo != none { place( @@ -454,8 +448,7 @@ cmyk(25%,7%,0%,0%), // FOOTER let footer = align(top + center, context( { - let short-title = sns-polylux-template_short-title.at(here()) - let short-event = sns-polylux-template_short-event.at(here()) + let footer-text = sns-polylux-template_footer-text.at(here()) place(top + center, line(length: 100%-2cm, stroke: (paint: sns-polylux-template_colormap.at(here()).at(1), thickness: 2pt))) @@ -468,9 +461,8 @@ cmyk(25%,7%,0%,0%), align(horizon,text(fill: sns-polylux-template_colormap.at(here()).at(2), size: 16pt, grid( gutter: 0.8cm, - columns: (0.7fr, 1fr, 0.7fr), - align(left, short-title), - align(center, smallcaps(short-event)), + columns: (1fr, 5em), + align(center, smallcaps(footer-text)), align(right, if page-number [#toolbox.slide-number/#toolbox.last-slide-number]), )) ))