This commit is contained in:
parent
afe956180f
commit
21c2a58f3c
2 changed files with 348 additions and 181 deletions
348
slides.typ
348
slides.typ
|
|
@ -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
|
||||
]
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue