normalization and move french to the end
All checks were successful
/ test_checkout (push) Successful in 1m51s
All checks were successful
/ test_checkout (push) Successful in 1m51s
This commit is contained in:
parent
4e38131df5
commit
c3a27f8711
7 changed files with 57 additions and 53 deletions
|
@ -45,7 +45,7 @@ When instantiating an object with `Object obj = cst.newInstance("Hello Void")`,
|
|||
) <lst:-th-expl-cl-call>
|
||||
|
||||
One of the main reasons to use reflection is to access classes that are not present in the application bytecode, nor are platform classes.
|
||||
Indeed, the application will crash if the #ART encounters references to a class that cannot be found by the current classloader.
|
||||
Indeed, the application will crash if the #ART encounters references to a class that cannot be found by the current class loader.
|
||||
This is often the case when dealing with classes from bytecode loaded dynamically.
|
||||
|
||||
To allow static analysis tools to analyse an application that uses reflection, we want to replace the reflection call with the bytecode that actually calls the method.
|
||||
|
@ -149,9 +149,9 @@ This means that we only need to find a way to integrate #DEX files into the appl
|
|||
|
||||
We saw in @sec:cl the class loading model of Android.
|
||||
When doing dynamic code loading, an application defines a new `ClassLoader` that handles the new bytecode, and starts accessing its classes using reflection.
|
||||
We also saw in @sec:cl that Android now use the multi-dex format, allowing it to handle any number of #DEX files in one classloader.
|
||||
We also saw in @sec:cl that Android now use the multi-dex format, allowing it to handle any number of #DEX files in one class loader.
|
||||
Therefore, the simpler way to give access to the dynamically loaded code to static analysis tools is to add the dex files to the application.
|
||||
This should not impact the classloading model as long as there is no class collision (we will explore this in @sec:th-class-collision) and as long as the original application did not try to access inaccessible classes (we will develop this issue in @sec:th-limits).
|
||||
This should not impact the class loading model as long as there is no class collision (we will explore this in @sec:th-class-collision) and as long as the original application did not try to access inaccessible classes (we will develop this issue in @sec:th-limits).
|
||||
|
||||
#figure(
|
||||
image(
|
||||
|
@ -166,7 +166,7 @@ In the end, we decided to *not* modify the original code that loads the bytecode
|
|||
We already added the bytecode loaded dynamically, and most tools already ignore dynamic code loading.
|
||||
At runtime, although the bytecode is already present in the application, the application will still dynamically load the code.
|
||||
This ensures that the application keeps working as intended, even if the transformation we applied is 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 reflection calls, and in order to keep reflection calls, we need the classloader created when loading bytecode.
|
||||
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 reflection calls, and in order to keep reflection calls, we need the class loader created when loading bytecode.
|
||||
|
||||
=== Class Collisions <sec:th-class-collision>
|
||||
|
||||
|
@ -174,17 +174,17 @@ We saw in @sec:cl/*-obfuscation*/ that having several classes with the same name
|
|||
In @sec:th-trans-cl, we are adding new code.
|
||||
By doing so, we increase the probability of having class collisions:
|
||||
The developer may have reused a helper class in both the dynamically loaded bytecode and the application, or an obfuscation process may have renamed classes without checking for intersection between the two sources of bytecode.
|
||||
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.
|
||||
When loaded dynamically, the classes are in a different class loader, 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 loaders from the Android #SDK.
|
||||
In the absence of class collision, those class loaders behave seamlessly and adding the classes to the application maintains the behaviour.
|
||||
|
||||
When we detect a collision, we rename one of the colliding classes in order to be able to differentiate between classes.
|
||||
To avoid breaking the application, we then need to rename all references to this specific class and be careful not to modify references to the other class.
|
||||
To do so, we regroup each class 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 references to this class in the classes defined by this classloader.
|
||||
To find the class used by a classloader, we reproduce the behaviour of the different classloaders of the Android #SDK.
|
||||
This is an important step: remember that the delegation process can lead to situations where the class defined by a classloader is not the class that will be loaded when querying the classloader.
|
||||
To do so, we regroup each class by the class loaders defining them.
|
||||
Then, for each colliding class name and each class loader, we check the actual class used by the class loader.
|
||||
If the class has been renamed, we rename all references to this class in the classes defined by this class loader.
|
||||
To find the class used by a class loader, we reproduce the behaviour of the different class loaders of the Android #SDK.
|
||||
This is an important step: remember that the delegation process can lead to situations where the class defined by a class loader is not the class that will be loaded when querying the class loader.
|
||||
The pseudo-code in @lst:renaming-algo shows the three steps of this algorithm:
|
||||
- First, we detect collisions and rename class definitions to remove the collisions.
|
||||
- Then we rename the reference to the colliding classes to make sure the right classes are called.
|
||||
|
@ -208,7 +208,7 @@ The pseudo-code in @lst:renaming-algo shows the three steps of this algorithm:
|
|||
defining_cl = cl.resolve_class(clz).class_loader
|
||||
cl.rename_reference(clz, defining_cl.new_name(clz))
|
||||
|
||||
# Merge the classloader into a flat APK
|
||||
# Merge the class loader into a flat APK
|
||||
new_apk = Apk()
|
||||
for cl in class_loaders:
|
||||
for dex in cl.get_dex():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue