Merge branch 'main' of git.mineau.eu:these-ammii/thesis
Some checks failed
/ test_checkout (push) Failing after 1s

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2025-07-09 16:45:54 +02:00
commit 00f2e3da28
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
60 changed files with 335 additions and 116 deletions

View file

@ -4,4 +4,4 @@
#todo[Acknowledge people] #todo[Acknowledge people]
#lorem(400) #text(fill: luma(75%), lorem(400))

View file

@ -9,7 +9,7 @@
Write a "Substantial Summary" in french, at least 4 pages: https://ed-matisse.doctorat-bretagne.fr/fr/soutenance-de-these#p-151 Write a "Substantial Summary" in french, at least 4 pages: https://ed-matisse.doctorat-bretagne.fr/fr/soutenance-de-these#p-151
] ]
#lorem(200) #text(fill: luma(75%), lorem(200))
/* /*
* Vocabulaire: * Vocabulaire:

View file

@ -1,7 +1,13 @@
#let ADB = link(<acr-adb>)[ADB]
#let APK = link(<acr-apk>)[APK] #let APK = link(<acr-apk>)[APK]
#let ART = link(<acr-art>)[ART]
#let AXML = link(<acr-axml>)[AXML]
#let DEX = link(<acr-dex>)[DEX] #let DEX = link(<acr-dex>)[DEX]
#let OAT = link(<acr-oat>)[OAT] #let OAT = link(<acr-oat>)[OAT]
#let JAR = link(<acr-jar>)[JAR] #let JAR = link(<acr-jar>)[JAR]
#let IDE = link(<acr-ide>)[IDE]
#let SDK = link(<acr-sdk>)[SDK]
#let XML = link(<acr-xml>)[XML]
#let notation_table = align(center, table( #let notation_table = align(center, table(
columns: 2, columns: 2,
@ -9,8 +15,14 @@
table.header( table.header(
[Acronyms], [Meanings], [Acronyms], [Meanings],
), ),
ADB, [Android Debug Bridge, a tool to connect to an Android emulator of smartphone to run commands, start applications, send events and perform other operations for testing and debuging purpose <acr-adb>],
APK, [Android Package, the file format used to install application on Android. The APK format is an extention of the #JAR format <acr-apk>], APK, [Android Package, the file format used to install application on Android. The APK format is an extention of the #JAR format <acr-apk>],
ART, [Android RunTime, the runtime environement that execute an Android application. The ART is the successor of the older Dalvik Virtual Machine <acr-art>],
AXML, [Android #XML. The specific flavor of #XML used by Android. The main specificity of AXML is that it can be compile in a binary version inside an APK <acr-axml>],
DEX, [Dalvik Executable, the file format for the bytecode used for applicatiobs by Android <acr-dex>], DEX, [Dalvik Executable, the file format for the bytecode used for applicatiobs by Android <acr-dex>],
IDE, [Integrated Development Environment, a software providing tools for software development <acr-ide>],
JAR, [Java ARchive file, the file format used to store several java class files. Sometimes used by Android to store #DEX files instead of java classes <acr-jar>], JAR, [Java ARchive file, the file format used to store several java class files. Sometimes used by Android to store #DEX files instead of java classes <acr-jar>],
OAT, [Of Ahead Time, an ahead of time compiled format for #DEX files <acr-oat>] OAT, [Of Ahead Time, an ahead of time compiled format for #DEX files <acr-oat>],
SDK, [Software Development Kit, a set of tools for developing software targeting a specific platform. In the context of Android, the version of the SDK can be associated to a version of Android, and application compatibility is defined in term of compatible SDK version <acr-sdk>],
XML, [eXtensible Markup Language, a language to store data <acr-xml>],
)) ))

View file

@ -4,3 +4,16 @@
#todo[Write an introduction] #todo[Write an introduction]
/*
*
* De tout temps les hommes on fait des apps android ...
*
* Introduire la notion de reverseur qui veux analyser une app
*
* Les outils d'analyses android sont problématique:
* - résulats trop bons sur des datasets faciles
* - facile a pieger: shadow attacks
* - savent pas gerer le chargement dyn et reflection
*
* Problématique: todo
*/

View file

@ -0,0 +1,5 @@
#import "../lib.typ": todo
== Android <sec:bg-android>
#todo[Present the android environnement]

74
2_background/X_tools.typ Normal file
View file

@ -0,0 +1,74 @@
#import "../lib.typ": todo, APK, IDE, SDK, DEX, ADB, ART, eg, XML, AXML
== Android Reverse Engineering Tools <sec:bg-tools>
Due to the specificities of Android, the usual tools for reverse engineering are not enough.
#todo[blabla intro in @sec:bg-tools]
=== Android Studio <sec:bg-android-studio>
The whole Android developement ecosystem is packaged by Google in the #IDE Android Studio#footnote[https://developer.android.com/studio].
In practice, Android Studio is a source-code editor that wrap arround the different tools of the android #SDK.
The #SDK tools and packages can be installed manually with the `sdkmanager` tool.
Among the notable tools in the #SDK, they are:
- `emulator`: an Android emulator.
This tools allow to run an emulated Android phone on a computer.
Although very usefull, Android emulator has several limitation.
For once, it cannot emulate another achitecture.
An x86_64 computer cannot emulate an ARM smartphone.
This can be an issue because a majority of smartphone run on ARM processor.
Also, for certain version of Android, the proprietary GooglePlay libraries are not available on rooted emulators.
Lastly, emulators are not designed to be stealthy and can easily be detected by an application.
Malware will avoid detection by not running their payload on emulators.
- #ADB: a tool to send commands to Android smartphone or emulator.
It can be used to install applications, send instructions, events, and generally perform debuging operations.
- Platform Packages: Those packages contains data associated to a version of android needed to compile an application.
Especially, they contains the so call `android.jar` files.
- `d8`: The main use of `d8` is to convert java bytecode files (`.class`) to Android #DEX format.
It can also be used to perform different level of optimization of the bytecode generated.
- `aapt`/`aapt2` (Android Asset Packaging Tool): This tools is used to build the #APK file.
Behind the scene, it we convert #XML to binary #AXML and ensure the right files have the right compression and alignment. (#eg some ressource files are mapped in memory by the #ART, and thus need to be aligned and not compressed).
- `apksigner`: the tool used to sign an #APK file.
=== Apktool <sec:bg-apktool>
Apktool#footnote[https://apktool.org/] is a _reengineering tool_ for Android #APK files.
It can be used to disassemble an application: it will extract the files from the #APK file, convert the binary #AXML to text #XML, and use smali/backsmali#footnote[https://github.com/JesusFreke/smali] to convert the #DEX files to smali, an assembler-like langage that match the Dalvik bytecode instructions.
The main strenght of Apktool is that after having disassemble an application, the content of the application can be edited and reassemble into a new #APK.
=== Androguard <sec:bg-androguard>
#todo[ref to androguard paper]
Androguard#footnote[https://github.com/androguard/androguard] is a python library for parsing and analysing #APK files.
Its main feature is disassembling #APK files.
It can be used to automatically read Android manifests, ressources, and bytecode.
Contrary to Apktool, it can be used programatically, whithout parsing text files, to analyse the application, but it cannot repackage a modified application.
In addition, it can perform additionnal analysis, like computing a call graph or control flow graph.
=== Jadx <sec:bg-jadx>
Jadx#footnote[https://github.com/skylot/jadx] is an application decompiler.
It convert #DEX files to Java source code.
It is not always capable of decompiling all classes of an application, so it cannot be used to recompile a new application, but the code generated can be verry helpfull to reverse an application.
In addition to decompilling #DEX files, Jadx can also decode Android manifests and application ressources.
=== Soot <sec:bg-soot>
#todo[soot ref]
Soot#footnote[https://github.com/soot-oss/soot] is a Java optimization framework.
It can leaft java bytecode to other intermediate representations that can be used to perform optimization then converted back to bytecode.
Because Dalvik bytecode and Java bytecode are equivalent, support for Android was added to Soot, and Soot features are now leveraged to analyse Android applications.
One of the best known example of Soot usage for Android analysis is Flowdroid #todo[ref], a tool that compute data flow in an application.
A new version of Soot, SootUp#footnote[https://github.com/soot-oss/SootUp], is currently beeing worked on.
Compared to Soot, it has a modernize interface and architecture, but it is not yet feature complete and some tools like Flowdroid are still using Soot.
=== Frida <sec:bg-frida>
Fidra#footnote[https://frida.re/] is a dynamic intrumentation toolki.

View file

@ -1,7 +1,25 @@
#import "../lib.typ": todo #import "../lib.typ": todo, epigraph
= Background <sec:bg> = Background <sec:bg>
#todo[Present your field background] #epigraph("Alexis \"Lex\" Murphy, Jurassic Park")[This is a Unix system. I know this.]
#lorem(200) #todo[Present field background and related work]
#include("X_android.typ")
#include("X_tools.typ")
/*
* Cours generique sur android
* présenter apk tool, jadx, androguard et flowdroid
* analyse statique
* outils avec des datasets un peu trop gentils
*
* analyse dynamique
*
* process du reverseur
*
* Garder les détails du class loading et de la reflection pour les chapitres associés?
*
* Analyse dynamique
*/

View file

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 568 KiB

After

Width:  |  Height:  |  Size: 568 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 355 KiB

After

Width:  |  Height:  |  Size: 355 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 207 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Before After
Before After

View file

@ -1,7 +0,0 @@
#import "../lib.typ": todo
= Related Work
#todo[Do the State of the Art]
#lorem(200)

View file

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 398 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Before After
Before After

View file

@ -0,0 +1,175 @@
#import "../lib.typ": todo, APK, DEX, JAR, OAT, eg
/*
* Parler de dex lego et du papier qui encode les resultats d'anger en jimple
*
*
*/
== Code Transformation <sec:th-trans>
#todo[Define code loading and reflection somewhere]
#todo[This is a draft, clean this up]
#todo[Reflectif call? Reflection call?]
In this section, we will see how we can transform the application code to make dynamic codeloading and reflexif calls analysable by static analysis tools.
=== Reflection <sec:th-trans-ref>
In Android, reflection can be used to do two things: instanciate a class, or call a method.
Either way, reflection starts by retreiving the `Class` object representing the class to use.
This class is usually retrived using a `ClassLoader` object, but can also be retrieved directly from the classloader of the class defining the calling method.
// elaborate? const-class dalvik instruction / MyClass.class in java?
One the class is retrieve, it can be instanciated using the deprecated method `Class.newInstance()`, like shown in @lst:-th-expl-cl-new-instance, or a specific method can be retrieved.
The current approche to instanciate a class is to retrieve the specific `Constructor` object, then calling `Constructor.newInstance(..)` like in @lst:-th-expl-cl-cnstr.
Similarly, to call a method, the `Method` object must be retrieved, then called using `Method.invoke(..)`, like shown in @lst:-th-expl-cl-call.
Although the process seems to differ between class instanciation and method call from the Java stand point, the runtime opperations are very similar.
When instanciating an object with `Object obj = cst.newInstance("Hello Void")`, the constructor method `<init>(Ljava/lang/String;)V`, represented by the `Constructor` `cst`, is called on the object `obj`.
#figure(
```java
ClassLoader cl = MainActivity.class.getClassLoader();
Class clz = cl.loadClass("com.example.Reflectee");
Object obj = clz.newInstance();
```,
caption: [Instanciating a class using `Class.newInstance()`]
) <lst:-th-expl-cl-new-instance>
#figure(
```java
Constructor cst = clz.getDeclaredConstructor(String.class);
Object obj = cst.newInstance("Hello Void");
```,
caption: [Instanciating a class using `Constructor.newInstance(..)`]
) <lst:-th-expl-cl-cnstr>
#figure(
```java
Method mth = clz.getMethod("myMethod", String.class);
Object[] args = {(Object)"an argument"}
String retData = (String) mth.invoke(obj, args);
```,
caption: [Calling a method using reflection]
) <lst:-th-expl-cl-call>
To allow static analysis tools to analyse an application that use reflection, we want to replace the reflection call by the bytecode that does the actual calls.
One of the main reason to use reflection is to access classes not from the application.
Although allows the use classes that do not exist in the application in bytecode, at runtime, if the classes are not found in the current classloader, the application will crash.
Similarly, some analysis tools might have trouble analysis application calling non existing classes.
@sec:th-trans-cl deals with the issue of adding dynamically loaded bytecode to the application.
A notable issue is that a specific reflection call can call different methods.
@lst:th-worst-case-ref illustrate a worst case scenario where any method can be call at the same reflection call.
In those situation, we cannot garanty that we know all the methods that can be called (#eg the name of the method called could be retrieved from a remote server).
#figure(
```java
Object myInvoke(Object obj, Method mth, Object[] args) throws .. {
return mth.invoke(obj, args);
}
```,
caption: [A reflection call that can call any method]
) <lst:th-worst-case-ref>
To handle those situation, instead of entirely removing the reflection call, we can modify the application code to test if the `Method` (or `Constructor`) object match any expected method, and if yes, directly call the method.
If the object does not match any expected method, the code can fallback to the original reflection call.
@lst:-th-expl-cl-call-trans demonstrate this transformation on @lst:-th-expl-cl-call.
It should be noted that we do the transformation at the bytecode level, the code in the listing correspond to the output of JADX #todo[Ref to list of common tools?] reformated for readability.
The method check is done in a separate method injected inside the application to avoid clutering the application too much.
Because Java (and thus Android) uses polymorphic methods, we cannot just check the method name and its class, but also the whole method signature.
We chose to limit the transformation to the specific instruction that call `Method.invoke(..)`.
This drastically reduce the risks of breaking the application, but leads to a lot of type casting.
Indeed, the reflection call uses the generic `Object` class, but actual methods usually use specific classes (#eg `String`, `Context`, `Reflectee`) or scalar types (#eg `int`, `long`, `boolean`).
This means that the method parameters and object on which the method is called must be downcast to their actual type before calling the method, then the returned value must be upcasted back to an `Object`.
Scalar types especially require special attention.
Java (and Android) distinguish between scalar type and classes, and they cannot be mixed: a scalar cannot be cast into an `Object`.
However, each scalar type has an associated class that can be use when doing reflection.
For example, the scalar type `int` is associated with the class `Integer`, the method `Integer.valueOf()` can convert an `int` scalar to an `Integer` object, and the method `Integer.intValue()` convert back an `Integer` object to an `int` scalar.
Each time the method called by reflection used scalars, the scalar-object convertion must be made before calling it.
And finally, because the instruction following the reflection call expect an `Object`, the return value of the method must be cast into an `Object`.
This back and forth between types might confuse some analysis tools.
This could be improved in futur works by analysing the code around the reflection call.
For example, if the result of the reflection call is imediatly cast into the expected type (#eg in @lst:-th-expl-cl-call, the result is cast to a `String`), they should not be any need to cast it to Object in between.
Similarly, it is common to have the method parameter arrays generated just before the reflection call never be used again (This is due to `Method.invoke(..)` beeing a varargs method: the array can be generated by the compiler at compile time).
In those cases, the parameters could be used directly whithout the detour inside an array.
#figure(
```java
class T {
static boolean check_is_reflectee_mymethod_e398(Method mth) {
Class<?>[] paramTys = mth.getParameterTypes();
return (
meth.getName().equals("myMethod") &&
paramTys.length == 1 &&
paramTys[0].descriptorString().equals(
String.class.descriptorString()
) &&
mth.getReturnType().descriptorString().equals(
String.class.descriptorString()
) &&
mth.getDeclaringClass().descriptorString().equals(
Reflectee.class.descriptorString()
)
)
}
}
...
Method mth = clz.getMethod("myMethod", String.class);
Object[] args = {(Object)"an argument"}
Object objRet;
if (T.check_is_reflectee_mymethod_e398abf7d3ce6ede(mth)) {
objRet = (Object) ((Reflectee) obj).myMethod((String)args[0]);
} else {
objRet = mth.invoke(obj, args);
}
String retData = (String) objRet;
```,
caption: [@lst:-th-expl-cl-call after the de-reflection transformation]
) <lst:-th-expl-cl-call-trans>
=== Code loading <sec:th-trans-cl>
An application can dynamically import code from several format like #DEX, #APK, #JAR or #OAT, either stored in memory or in a file.
Because it is an internal, platform dependant format, we elected to ignore the #OAT format.
Practically, #JAR and #APK files are zip files containing #DEX files.
This means that we only need to find a way to integrate #DEX files to the application.
We elected to simply add the dex files to the application, using the multi-dex feature introduced by the SDK 21 now used by all applications.
This gives access to the dynamically loaded code to static analysis tool.
#todo[add drawing of dex insertion]
We decided to leave untouched the original code that load the bytecode.
At runtime, although the bytecode is already present in the application, the application will still dynamically load the code.
This ensure that the application keep working as intended even if the transformation we applied are incomplete.
Specifically, to call dynamically loaded code, an application needs to use reflection, and we saw in @sec:th-trans-ref that we need to keep reflecton calls, and in order to keep reflection calls, we need the classloader created when loading bytecode.
=== Class Collisions <sec:th-class-collision>
We saw in @sec:cl-obfuscation that having several classes with the same name in the same application can be problematic.
In @sec:th-trans-cl, we are adding code from another source.
By doing so, we augment the probability of having class collisions.
When loaded dynamically, the classes are in a different classloader, and the class resolution is resolved at runtime like we saw in @sec:cl-loading.
We decided to restrain our scope to the use of class loader from the Android SDK.
In the abscence of class collision, those class loader behave seamlessly and adding the classes to application maintains the behavior.
When we detect a collision, we rename one of the classes colliding before injecting it to the application.
To avoid breaking the application, we then need to rename all references to this specific class, an be carefull not to modify references to the other class.
To do so, we regroup each classes by the classloaders defining them, then, for each colliding class name and each classloader, we check the actual class used by the classloader.
If the class has been renamed, we rename all reference to this class in the classes defined by this classloader.
To find the class used by a classloader, we reproduce the behavior of the different classloaders of the Android SDK.
This is an important step: remember that the delegation process can lead to situation where the class defined by a classloader is not the class that will be loaded when querying the classloader.
#todo[renamin algo]
=== Pitfalls
#todo[interupting try blocks: catch block might expect temporary registers to still stored the saved value]
#todo[diferenciating the classloaders]
#todo[changing classloader with class collision]

View file

@ -1,6 +1,7 @@
#import "../lib.typ": todo #import "../lib.typ": todo
== Results #todo[better section name] <sec:th-res> == Result <sec:th-res>
#todo[better section name for @sec:th-res]
=== Bytecode Loaded by Application <sec:th-code-collected> === Bytecode Loaded by Application <sec:th-code-collected>

View file

@ -1,6 +1,8 @@
#import "../lib.typ": todo #import "../lib.typ": todo
= #todo[theseus chapter title] = Theseus <sec:th>
#todo[theseus chapter title for @sec:th]
#include("1_static_transformation.typ") #include("1_static_transformation.typ")
#include("3_results.typ") #include("3_results.typ")

View file

@ -1,93 +0,0 @@
#import "../lib.typ": todo, APK, DEX, JAR, OAT, eg
== Code Transformation <sec:th-trans>
#todo[Define code loading and reflection somewhere]
#todo[This is a draft, clean this up]
#todo[Reflectif call? Reflection call?]
In this section, we will see how we can transform the application code to make dynamic codeloading and reflexif calls analysable by static analysis tools.
=== Reflection <sec:th-trans-ref>
In Android, reflection can be used to do two things: instanciate a class, or call a method.
Either way, reflection starts by retreiving the `Class` object representing the class to use.
This class is usually retrived using a `ClassLoader` object, but can also be retrieved directly from the classloader of the class defining the calling method.
// elaborate? const-class dalvik instruction / MyClass.class in java?
One the class is retrieve, it can be instanciated using the deprecated method `Class.newInstance()`, like shown in @lst:-th-expl-cl-new-instance, or a specific method can be retrieved.
The current approche to instanciate a class is to retrieve the specific `Constructor` object, then calling `Constructor.newInstance(..)` like in @lst:-th-expl-cl-cnstr.
Similarly, to call a method, the `Method` object must be retrieved, then called using `Method.invoke(..)`, like shown in @lst:-th-expl-cl-call.
Although the process seems to differ between class instanciation and method call from the Java stand point, the runtime opperations are very similar.
When instanciating an object with `Object obj = cst.newInstance("Hello Void")`, the constructor method `<init>(Ljava/lang/String;)V`, represented by the `Constructor` `cst`, is called on the object `obj`.
#figure(
```java
ClassLoader cl = MainActivity.class.getClassLoader();
Class clz = cl.loadClass("com.example.Reflectee");
Object obj = clz.newInstance();
```,
caption: [Instanciating a class using `Class.newInstance()`]
) <lst:-th-expl-cl-new-instance>
#figure(
```java
Constructor cst = clz.getDeclaredConstructor(String.class);
Object obj = cst.newInstance("Hello Void");
```,
caption: [Instanciating a class using `Constructor.newInstance(..)`]
) <lst:-th-expl-cl-cnstr>
#figure(
```java
Method mth = clz.getMethod("myMethod", String.class);
String retData = (String) mth.invoke(obj, "an argument");
```,
caption: [Calling a method using reflection]
) <lst:-th-expl-cl-call>
To allow static analysis tools to analyse an application that use reflection, we want to replace the reflection call by the bytecode that does the actual calls.
One of the main reason to use reflection is to access classes not from the application.
Although allows the use classes that do not exist in the application in bytecode, at runtime, if the classes are not found in the current classloader, the application will crash.
Similarly, some analysis tools might have trouble analysis application calling non existing classes.
@sec:th-trans-cl deals with the issue of adding dynamically loaded bytecode to the application.
A notable issue is that a specific reflection call can call different methods.
@lst:th-worst-case-ref illustrate a worst case scenario where any method can be call at the same reflection call.
In those situation, we cannot garanty that we know all the methodes that can be called (#eg the name of the method called could be retrieved from a remote server).
#figure(
```java
Object myInvoke(Object obj, Method mth, Object[] args) throws .. {
return mth.invoke(obj, args);
}
```,
caption: [A reflection call that can call any method]
) <lst:th-worst-case-ref>
=== Code loading <sec:th-trans-cl>
#todo[custom class loaders]
An application can dynamically import code from several format like #DEX, #APK, #JAR or #OAT, either stored in memory or in a file.
Because it is an internal, platform dependant format, we elected to ignore the #OAT format.
Practically, #JAR and #APK files are zip files containing #DEX files.
This means that we only need to find a way to integrate #DEX files to the application.
We elected to simply add the dex files to the application, using the multi-dex feature introduced by the SDK 21 now used by all applications.
This gives access to the dynamically loaded code to static analysis tool.
#todo[add drawing of dex insertion]
We decided to leave untouched the original code that load the bytecode.
At runtime, although the bytecode is already present in the application, the application will still dynamically load the code.
This ensure that the application keep working as intended even if the transformation we applied are incomplete.
Specifically, to call dynamically loaded code, an application needs to use reflection, and we saw in @sec:th-trans-ref that we need to keep reflecton calls, and in order to keep reflection calls, we need the classloader created when loading bytecode.
=== Class Collisions <sec:th-class-collision>
=== Pitfalls
#todo[interupting try blocks: catch block might expect temporary registers to still stored the saved value]

View file

@ -1,9 +1,9 @@
#import "@local/template-thesis-matisse:0.0.1": todo #import "@local/template-thesis-matisse:0.0.1": todo
#let keywords-en = ("Android", "malware analysis", "static analysis", "class loading", "code obfuscation", todo[More Keywords]) #let keywords-en = ("Android", "malware analysis", "static analysis", "class loading", "code obfuscation", todo[Keywords])
#let keywords-fr = ("Android", "analyse de maliciels", "analyse statique", "chargement de classe", "brouillage de code") #let keywords-fr = ("Android", "analyse de maliciels", "analyse statique", "chargement de classe", "brouillage de code")
#let abstract-en = lorem(175) #let abstract-en = text(fill: luma(75%), lorem(175))
#let abstract-fr = lorem(175) #let abstract-fr = text(fill: luma(75%), lorem(175))

View file

@ -13,6 +13,19 @@
} else { } else {
true true
} }
#let paper_draft = if "paper" in sys.inputs {
assert(
sys.inputs.paper == "true" or sys.inputs.paper == "false",
message: "If --input paper=<val> is set, <val> must be 'true', or 'false'"
)
assert(
draft,
message: "paper can only be set if --input draft=true is set"
)
sys.inputs.draft == "true"
} else {
false
}
#show: matisse-thesis.with( #show: matisse-thesis.with(
title-fr: todo[Find a title], title-fr: todo[Find a title],
@ -69,17 +82,23 @@
#counter(page).update(1) #counter(page).update(1)
// Augment interline when compiling to paper draft
#show par: set par(leading: 1.5em) if paper_draft
#show par: set par(spacing: 1.5em) if paper_draft
// Keep interline in table
#show table: set par(leading: 0.65em) if paper_draft
#include("1_introduction/main.typ") #include("1_introduction/main.typ")
#include("2_background/main.typ") #include("2_background/main.typ")
#include("3_related_work/main.typ") #include("3_rasta/main.typ")
#include("4_rasta/main.typ") #include("4_class_loader/main.typ")
#include("5_class_loader/main.typ") #include("5_theseus/main.typ")
#include("6_theseus/main.typ")
= Conclusion <sec:conclusion> = Conclusion <sec:conclusion>
#todo[Conclude] #todo[Conclude]
#lorem(500) #text(fill: luma(75%), lorem(500))
#bibliography("bibliography.bib") #bibliography("bibliography.bib")