I declare this manuscript finished
All checks were successful
/ test_checkout (push) Successful in 1m48s
All checks were successful
/ test_checkout (push) Successful in 1m48s
This commit is contained in:
parent
9f39ded209
commit
5c3a6955bd
14 changed files with 162 additions and 131 deletions
|
@ -73,6 +73,15 @@ This behaviour implements a priority and avoids redefining by error a core class
|
|||
This behaviour is useful for overriding specific classes of a class loader while keeping the other classes.
|
||||
A normal class loader would prioritise the classes of its delegate over its own.
|
||||
|
||||
At runtime, Android instantiates for each application three instances of class loaders described previously: `bootClassLoader`, the unique instance of `BootClassLoader`, and two instances of `PathClassLoader`: `systemClassLoader` and `appClassLoader`.
|
||||
`bootClassLoader` is responsible for loading Android *#platc*.
|
||||
It is the direct delegate of the two other class loaders instantiated by Android.
|
||||
`appClassLoader` points to the application `.apk` file, and is used to load the classes inside the application
|
||||
`systemClassLoader` is a `PathClassLoader` pointing to `'.'`, the working directory of the application, which is `'/'` by default.
|
||||
The documentation of `ClassLoader.getSystemClassLoader` reports that this class loader is the default context class loader for the main application thread.
|
||||
In reality, the #platc are loaded by `bootClassLoader` and the classes from the application are loaded from `appClassLoader`.
|
||||
`systemClassLoader` is never used in production according to our careful reading of the #AOSP sources.
|
||||
|
||||
#figure(
|
||||
```python
|
||||
def get_mutli_dex_classses_dex_name(index: int):
|
||||
|
@ -98,15 +107,6 @@ A normal class loader would prioritise the classes of its delegate over its own.
|
|||
caption: [Default Class Loading Algorithm for Android Applications],
|
||||
) <lst:cl-loading-alg>
|
||||
|
||||
At runtime, Android instantiates for each application three instances of class loaders described previously: `bootClassLoader`, the unique instance of `BootClassLoader`, and two instances of `PathClassLoader`: `systemClassLoader` and `appClassLoader`.
|
||||
`bootClassLoader` is responsible for loading Android *#platc*.
|
||||
It is the direct delegate of the two other class loaders instantiated by Android.
|
||||
`appClassLoader` points to the application `.apk` file, and is used to load the classes inside the application
|
||||
`systemClassLoader` is a `PathClassLoader` pointing to `'.'`, the working directory of the application, which is `'/'` by default.
|
||||
The documentation of `ClassLoader.getSystemClassLoader` reports that this class loader is the default context class loader for the main application thread.
|
||||
In reality, the #platc are loaded by `bootClassLoader` and the classes from the application are loaded from `appClassLoader`.
|
||||
`systemClassLoader` is never used in production according to our careful reading of the #AOSP sources.
|
||||
|
||||
In addition to the class loaders instantiated by ART when starting an application, the developer of an application can use class loaders explicitly by calling ones from the #Asdk, or by recoding custom class loaders that inherit from the `ClassLoader` class.
|
||||
At this point, accurately modelling the complete class loading algorithm becomes impossible: the developer can program any algorithm of their choice.
|
||||
For this reason, this case is excluded from this chapter, and we focus on the default behaviour where the context class loader is the one pointing to the `.apk` file and where its delegate is `BootClassLoader`.
|
||||
|
|
|
@ -107,14 +107,6 @@ We used 4 versions of this application:
|
|||
Like for the third one, we similarly store data in `com.android.okhttp.Request` and then retrieve it.
|
||||
Again, the shadowing implementation discards the data.
|
||||
|
||||
We used the 4 selected tools on the 4 versions of the application and compared the results on the control application to the results on the other application implementing the different obfuscation techniques.
|
||||
We found that these static analysis tools do not consider the class loading mechanism, either because the tools only look at the content of the application file (#eg a disassembler) or because they consider class loading to be a dynamic feature and thus out of their scope.
|
||||
In @tab:cl-results, we report on the types of shadowing that can trick each tool.
|
||||
A plain circle is a shadow attack that leads to a wrong result.
|
||||
A white circle indicates a tool emitting warnings or that displays the two versions of the class.
|
||||
A cross is a tool not impacted by a shadow attack.
|
||||
//We explain in more detail in the following the results for each considered tool.
|
||||
|
||||
#figure({
|
||||
table(
|
||||
columns: 5,
|
||||
|
@ -147,6 +139,14 @@ A cross is a tool not impacted by a shadow attack.
|
|||
caption: [Working attacks against static analysis tools]
|
||||
) <tab:cl-results>
|
||||
|
||||
We used the 4 selected tools on the 4 versions of the application and compared the results on the control application to the results on the other application implementing the different obfuscation techniques.
|
||||
We found that these static analysis tools do not consider the class loading mechanism, either because the tools only look at the content of the application file (#eg a disassembler) or because they consider class loading to be a dynamic feature and thus out of their scope.
|
||||
In @tab:cl-results, we report on the types of shadowing that can trick each tool.
|
||||
A plain circle is a shadow attack that leads to a wrong result.
|
||||
A white circle indicates a tool emitting warnings or that displays the two versions of the class.
|
||||
A cross is a tool not impacted by a shadow attack.
|
||||
//We explain in more detail in the following the results for each considered tool.
|
||||
|
||||
==== Jadx
|
||||
|
||||
//Jadx is a reverse engineering tool that regenerates the Java source code of an application.
|
||||
|
|
|
@ -143,14 +143,6 @@ Manual inspection of some applications revealed that the two main reasons are:
|
|||
- Instead of checking if the method's attributes are null inline, like Android does, applications use the method `org.apache.http.util.Args.notNull()`. According to comments in the source code of Android#footnote[https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/org/apache/http/params/HttpConnectionParams.java;drc=3bdd327f8532a79b83f575cc62e8eb09a1f93f3d?], the class was forked in 2007 from the Apache 'httpcomponents' project. Looking at the history of the project, the use of `Args.notNull()` was introduced in 2012#footnote[https://github.com/apache/httpcomponents-core/commit/9104a92ea79e338d876b1b60f5cd2b243ba7069f?]. This shows that applications are embedding code from more recent versions of this library without realising their version will not be the one used.
|
||||
- Very small changes that we found can be attributed to the compilation process (e.g. swapping registers: `v0` is used instead of `v1` and `v1` instead of `v0`), but even if we consider them different, they are very similar.
|
||||
|
||||
The remaining 4.99% of classes that are identical to the Android version are classes where the body of the methods is replaced by stubs that throw `RuntimeException("Stub!")`.
|
||||
This code corresponds to what we found in `android.jar`, but not the code we found in the emulator, which is surprising.
|
||||
Nevertheless, we decided to count them as identical, because `android.jar` is the official jar file for developers, and stubs are replaced in the emulator: it is intended by Google developers.
|
||||
|
||||
Other results of @tab:cl-topsdk can be similarly discussed: either they are identical with a high ratio, or they are different because of small variations.
|
||||
When substantial differences appear, it is mainly because different versions of the same library have been used or an #SDK class is embedded for retro-compatibility.
|
||||
]
|
||||
|
||||
#figure({
|
||||
show table: set text(size: 0.80em)
|
||||
table(
|
||||
|
@ -202,6 +194,14 @@ When substantial differences appear, it is mainly because different versions of
|
|||
caption: [Shadow classes compared to #SDK 34 for a dataset of #nbapk applications]
|
||||
) <tab:cl-topsdk>
|
||||
|
||||
The remaining 4.99% of classes that are identical to the Android version are classes where the body of the methods is replaced by stubs that throw `RuntimeException("Stub!")`.
|
||||
This code corresponds to what we found in `android.jar`, but not the code we found in the emulator, which is surprising.
|
||||
Nevertheless, we decided to count them as identical, because `android.jar` is the official jar file for developers, and stubs are replaced in the emulator: it is intended by Google developers.
|
||||
|
||||
Other results of @tab:cl-topsdk can be similarly discussed: either they are identical with a high ratio, or they are different because of small variations.
|
||||
When substantial differences appear, it is mainly because different versions of the same library have been used or an #SDK class is embedded for retro-compatibility.
|
||||
]
|
||||
|
||||
#paragraph([Hidden shadowing])[
|
||||
For applications redefining hidden classes, on average, 16.1 classes are redefined (cf bottom part of @tab:cl-shadow).
|
||||
The top 3 packages whose code actually differs from the ones found in Android are `java.util.stream`, `org.ccil.cowan.tagsoup` and `org.json`:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue