From 6f7afe73a7f550b5685199bb7d5b2d055fe78f71 Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Tue, 28 Oct 2025 23:18:23 +0100 Subject: [PATCH] feedback --- 1_introduction/main.typ | 2 +- slides.typ | 310 +++-- slides/imgs/call_graph_expected.svg | 1782 +++++++++++++++++++++++++++ slides/imgs/call_graph_obf.svg | 1782 +++++++++++++++++++++++++++ slides/lib.typ | 10 +- slides/outlines.typ | 9 +- 6 files changed, 3814 insertions(+), 81 deletions(-) create mode 100644 slides/imgs/call_graph_expected.svg create mode 100644 slides/imgs/call_graph_obf.svg diff --git a/1_introduction/main.typ b/1_introduction/main.typ index a4831c9..80c16ee 100644 --- a/1_introduction/main.typ +++ b/1_introduction/main.typ @@ -125,7 +125,7 @@ The contributions of this thesis are the following: + We propose an approach to allow static analysis tools to analyse applications that perform dynamic code loading: We collect at runtime the bytecode dynamically loaded and the reflection calls information, and patch the #APK file to perform those operations statically. Finally, we evaluate the impact this transformation has on the tools we containerised previously. -+ We released under the AGPL licence #todo[Still waiting for CS to validate] the software we used in the experiments presented in this thesis. ++ We released under the GPL licence the software we used in the experiments presented in this thesis. For @sec:rasta, this includes the code used to test the output of each tool and the code to analyse the results of the experiment, in addition to the containers to run the tested tools. We also released Androscalpel, a Rust crate to manipulate Dalvik bytecode, that we used to create Theseus, a set of scripts that implement the approach presented in @sec:th. The complete list and location of the software we release are available in @sec:soft. diff --git a/slides.typ b/slides.typ index ff5a6b1..6877ad5 100644 --- a/slides.typ +++ b/slides.typ @@ -453,6 +453,7 @@ "static-vs-dyn", "theseus", ).at(i) + if i != 0 { counter("logical-slide").update( n => n - 1 ) } slide( //foreground: rotate(30deg, smallcaps(text(fill: pirat-color.red, size: 50pt)[#stage])) )[ @@ -921,12 +922,6 @@ 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[ @@ -1036,25 +1031,22 @@ ] ) ] +] - #only(5)[ +#for i in range(3) { + counter("logical-slide").update( n => n - 1 ) + show table.cell: c => { + if c.y >= 1 and ((i < 2 and c.x == 2) or (i < 1 and c.x == 1)) { + [] + } else { + c + } + } + slide( + title: [Self-Shadowing], + )[ #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 - ``` - ], + columns: (2fr, 0.5em, 3fr), yes-codly[ #set list(spacing: 0.5em) #scale(100%, reflow: true, @@ -1065,15 +1057,40 @@ else: return f"classes{index+1}.dex" ```) - - `classes0.dex` ? - - `classes02.dex` ? - - `classes10.dex` ? - ] + #align(bottom, text(size: 0.75em)[#sym.star estimation, non-deterministic]) + ], [], { + set text(size: 24pt) + show table.cell: set align(center+horizon) + let r = text.with(fill: pirat-color.red.darken(10%)) + table( + columns: (1fr, 1fr, 1fr), + //inset: (x,y) => if y == 0 { 10pt } else { 3pt }, + stroke: none, + table.header( + [Android], + table.vline(), + [Soot], + table.vline(), + [Androguard#super[#sym.star]] + ), + table.hline(), + [`classes.dex`], [`classes.dex`], [`classes10.dex`], + ..if (i != 0) {( + [], r[`classes1.dex`], [], + [], r[`classes10.dex`], [], + )}, + [`classes2.dex`], [`classes2.dex`], [`classes9.dex`], + [`classes3.dex`], [`classes3.dex`], [`classes8.dex`], + + table.cell(colspan: 3, inset: -3pt)[...], + + [`classes9.dex`], [`classes9.dex`], [`classes2.dex`], + [`classes10.dex`], [], [`classes1.dex`], + strike[`classes1.dex`], [], [`classes.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( @@ -1084,12 +1101,12 @@ codly( ..default-codly ) - } else if i == 1 { + } else if i == 2 { codly( highlighted-lines: (7, 8), ..default-codly ) - } else if i == 2 { + } else if i == 1 { codly( highlighted-lines: (1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15), ..default-codly @@ -1144,17 +1161,17 @@ #set align(left) #set text(size: 18pt) #partial-hide(i, hidden: (0,), partial: (2,))[ + === Self Shadowing + Trick the tool into using an APK class instead of another APK class + ] + #partial-hide(i, hidden: (0, 1))[ === SDK shadowing Trick the tool into using an APK class instead of an SDK class ] - #partial-hide(i, hidden: (0,), partial: (2,))[ + #partial-hide(i, hidden: (0, 1))[ === 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 - ] ] ) ] @@ -1180,17 +1197,27 @@ ] #slide( - title: [Example: Androguard], + title: [Androguard on Toy Malware], foreground: eye-4(x: 97%, y: 85%, mirror: true) )[ #set align(center+horizon) - #show image: scale.with(250%) - #set figure(gap: 4em) + //#show image: scale.with(250%) + //#set figure(gap: 4em) #v(3em) #grid( columns: (1fr, 1fr), - get_figure(), - get_figure() + //get_figure(), + figure( + image("slides/imgs/call_graph_expected.svg", width: 100%), + caption: [Expected], + supplement: none, + ), + //get_figure() + figure( + image("slides/imgs/call_graph_obf.svg", width: 100%), + caption: [Computed], + supplement: none, + ) ) ] @@ -1267,7 +1294,7 @@ - We did not find deliberate shadow attacks ] #v(1fr) - #align(center, text(fill: pirat-color.blue.darken(30%))[Digital Threats: Research and Practice]) + #align(center, text(fill: pirat-color.blue.darken(30%))[Digital Threats: Research and Practice, vol. 6 (3), 2025]) #v(0.5em) ] @@ -1276,18 +1303,29 @@ // TODO put everywhere Theseus Transformeur #slide( - title: [State of the Art], + title: [Dexhunter: Zang #etal (2015)], )[ - #align(center+horizon, text(fill: pirat-color.red, size: 30pt)[INSERT SoA]) + #align(center+horizon, dexhunter-outline( + small_icon_size: 75pt, + big_icon_size: 200pt, + )) ] #slide( - title: [Overview], - foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[FINIR DESSIN]), + title: [DroidRA: Li #etal (2016)], +)[ + #align(center+horizon, droidra-outline( + small_icon_size: 75pt, + big_icon_size: 200pt, + )) +] + +#slide( + title: [Theseus: Overview], )[ - // TODO: bien tout rappeler l'objectif #set align(center+horizon) - #theseus-outline() + #only(1, theseus-outline(stage: "theseus-no-static")) + #only(2, theseus-outline(stage: "theseus")) ] #slide( @@ -1387,32 +1425,62 @@ )[ #show: yes-codly #set align(center+horizon) + + #if i == 1 { + codly( + offset: 5, + highlighted-lines: (6,), + ..default-codly + ) + } else if i == 4 { + codly( + offset: 5, + highlights: ( + (line: 6, start: 0, end: 25, fill: pirat-color.blue), + ), + ..default-codly + ) + } else { + codly( + offset: 5, + ..default-codly + ) + } + ```java + String retData = (String) mth.invoke(obj, args); + ``` + + #v(-0.5em) + #align(center+horizon, sym.arrow.b.stroked) + #v(-0.5em) + #if i == 1 { codly( offset: 5, highlighted-lines: (10,), ..default-codly ) - } else if i == 2 { + } else if i == 3 { 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), + (line: 12, start: 18+9, end: 32, 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, highlights: ( @@ -1442,7 +1510,41 @@ } #slide( - foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[MOCHE]), + foreground: { + arrow( + stroke: 10pt + pirat-color.red, + ( + 250pt, + -400pt, + ), + ( + 250pt, + -350pt, + ) + ) + arrow( + stroke: 10pt + pirat-color.red, + ( + 130pt, + -400pt, + ), + ( + 180pt, + -320pt, + ) + ) + arrow( + stroke: 10pt + pirat-color.red, + ( + 370pt, + -400pt, + ), + ( + 320pt, + -320pt, + ) + ) + } )[ #set align(center+horizon) #theseus-outline() @@ -1475,6 +1577,11 @@ title: [Collected Bytecode], foreground: eye-1(x: 5%, y: 70%, height: 70pt) )[ + /* + * Explications, give example of Google Services: + * whithout service: does not work + * with service: service recognize the app as malware and block it + */ #set align(center+horizon) #show link.where(dest: ): it => it.body #show link.where(dest: ): it => it.body @@ -1494,10 +1601,33 @@ ] #slide( - foreground: rotate(30deg, text(fill: pirat-color.red, size: 50pt)[MOCHE]), + foreground: { + arrow( + stroke: 10pt + pirat-color.red, + ( + 770pt, + -250pt, + ), + ( + 620pt, + -350pt, + ) + ) + arrow( + stroke: 10pt + pirat-color.red, + ( + 620pt, + -350pt, + ), + ( + 770pt, + -250pt, + ) + ) + } )[ #set align(center+horizon) - #theseus-outline() + #theseus-outline(stage: "theseus-vs-static") ] #for i in range(3) { @@ -1506,25 +1636,45 @@ slide( title: [Added Method Calls], )[ - // TODO: remove Before After #set align(center+horizon) - #show link.where(dest: ): it => it.body - #show link.where(dest: ): it => it.body - #show figure.caption: none - #set table( - fill: (x, y) => { - if ( - i == 1 and (x == 3 and y > 1) + //#show link.where(dest: ): it => it.body + //#show link.where(dest: ): it => it.body + //#show figure.caption: none + + //#scale(90%, reflow: true, get_figure()) + #import "5_theseus/X_var.typ": compared_callgraph + #import "lib.typ": num + #let nb_col = 3 + #table( + columns: (1fr, 1.1fr, 1fr), + align: center+horizon, + stroke: none, + fill: (x, y) => if ( + i == 1 and (x == 1 and y > 1 and y != 9) ) or ( - i == 2 and (x == 4 and y > 1) + i == 2 and (x == 2 and y > 1) ){ highlight-color } else { none - } - } + }, + table.hline(), + 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.hline(), + ..compared_callgraph.map( + (e) => ( + [#lower(e.sha256).slice(0, 10)...], + num(e.added), + num(e.added_ref_only) + )).flatten(), + [#lower("5D2CD1D10ABE9B1E8D93C4C339A6B4E3D75895DE1FC49E248248B5F0B05EF1CE").slice(0, 10)...], table.cell(colspan: nb_col - 1)[_Transformation Crashed_], + table.hline(), ) - #scale(90%, reflow: true, get_figure()) + ] } @@ -1549,14 +1699,18 @@ 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) + arrow((290pt, -335pt), (320pt, -310pt), strk: strk) + arrow((400pt, -335pt), (340pt, -310pt), strk: strk) } )[ #set align(center+horizon) #show figure.caption: none - Original #h(2em) Transformed + #move(dx: -70pt)[Original #h(2em) Transformed] + + /* + * JFL bet on a question about SAAF + */ #box(width: 80%, get_figure()) ] @@ -1578,7 +1732,7 @@ We showed that: #item-by-item[ - - After five years, more than half the static analysis tools are no longer usable. + - Most Static analysis tools are no longer usable after a few years. 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. diff --git a/slides/imgs/call_graph_expected.svg b/slides/imgs/call_graph_expected.svg new file mode 100644 index 0000000..ae6ab23 --- /dev/null +++ b/slides/imgs/call_graph_expected.svg @@ -0,0 +1,1782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/slides/imgs/call_graph_obf.svg b/slides/imgs/call_graph_obf.svg new file mode 100644 index 0000000..96ce950 --- /dev/null +++ b/slides/imgs/call_graph_obf.svg @@ -0,0 +1,1782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/slides/lib.typ b/slides/lib.typ index a1958ee..749d204 100644 --- a/slides/lib.typ +++ b/slides/lib.typ @@ -3,7 +3,7 @@ #import "../lib.typ": pb1-text, pb2-text, pb3-text #import "icons.typ": arrow -#import "outlines.typ": theseus-outline +#import "outlines.typ": theseus-outline, dexhunter-outline, droidra-outline #let pirat-color = ( black: rgb("#000000"), @@ -35,6 +35,14 @@ pirat-color.red, ) } +#let apk-block = block.with( + //fill: green.lighten(50%), + stroke: black, + inset: 10pt, + radius: 12pt, +) + + #let colortest = [ #for th in ( sns-polylux-template_sns-pirat, diff --git a/slides/outlines.typ b/slides/outlines.typ index cf527e1..12c39af 100644 --- a/slides/outlines.typ +++ b/slides/outlines.typ @@ -152,7 +152,7 @@ box( width: width, height: height, - stroke: black, + //stroke: black, { place( left+bottom, @@ -221,6 +221,13 @@ ) } +#let droidra-outline( + small_icon_size: 100pt, + big_icon_size: 200pt, +) = context { + text(fill: red, size: 40pt)[TODO] +} + #let theseus-outline( small_icon_size: 60pt, big_icon_size: 90pt,