Today in the issue: changes in the protection of private data of users in Android 12, research into the problems of incorrect configuration of cloud services in applications, an article on the rules for parsing and analyzing malware code using the example of FluBot, as well as a funny vulnerability in the Medium application. As a bonus: optimization of the application launch and further tips for developers.
READ
Android 12 and privacy
What's new in Android Privacy - the official announcement of changes in the protection of user data in Android 12.
Problems of incorrect configuration of cloud services
Mobile app developers' misconfiguration of third party services leave personal data of over 100 million exposed - an article about such application vulnerabilities that are caused by misconfiguration of cloud services. There are no practical examples of hacking in the article, but the general statistics are quite interesting.
An example of a message retrieved from the T'Leva application database.
Another vulnerability in the Medium app
Exploiting Activity in medium android app - a short note about another stupid vulnerability in the mobile application of the Medium blog platform.
The essence of the article is as follows. There is activity in the application SaveToMediumActivity. All she does is save the article to her favorites list. It turned out that the activity is not only available from the outside to any other application (exported), but also allows you to save any URL to the list, not just articles published on Medium itself.
As a result, you can easily add anything to your favorites list using a simple application or the following command:
Oh yes. For all this Medium paid a bug bounty.
Disassembly and analysis of malware
How to analyze mobile malware: a Cabassous / FluBot Case study - an article on the stages of analyzing malicious applications using the Cabassous / FluBot Trojan as an example.
APKiD is powerless
Static initializers are easy to find with grep
DEVELOPER
Optimizing application launch speed
From zero to hero: Optimizing Android app startup time is another article on optimizing the launch speed of Android applications. She does not tell anything new, but the author gives some very interesting observations.
Another collection of tips
Top Put_your_number Kotlin utils we use all over our project - five Android development practices that can help you write cleaner, more testable code. The most interesting tricks:
Proxy for accessing resources. Android has a class Resourcesfor accessing application resources. The standard way to get an object of this class is through Context. However, this is not always convenient. For example, when binding a ViewHolder, you will have to access resources like this:
A very long line. Also, we won't be able to clearly test this code (without using dirty hacks like Robolectric).
The solution to both problems is to create a wrapper for the Resources class:
The interface makes the class easy to mock for testing. In addition, all calls of the type getColorin the same ViewHolder can be delegated to it:
Simple and convenient, and thanks to the use of the word inline - in most cases the class will not even be created - the method code will be inlined in the caller.
Extension functions for changing indents. During development, it is often necessary to change the indentation of an interface element. The popular Android KTX extension library suggests doing it like this:
And this is a rather strange and not at all descriptive way. Instead, we would like to do it something like this:
The code to do this:
READ
Android 12 and privacy
What's new in Android Privacy - the official announcement of changes in the protection of user data in Android 12.
- Privacy screen. Android 12 will have a dedicated settings screen showing how often installed apps have accessed the microphone, camera, location, and other sensors and data.
- Camera and microphone indicators. Following Apple, Google engineers added camera and microphone access indicators to Android 12. If an application is currently using one or the other, a corresponding icon will appear at the top of the screen. Moreover, after opening the shutter, you can see which specific applications have access to the camera and microphone, and immediately deny access.
- Approximate location. The location request dialog will allow you to choose what type of location information to share with the application: exact location or approximate location. The second is well suited, for example, for weather services.
- Clipboard read notification. Android 12 will show a message every time an application reads the contents of the clipboard. The only exception when this does not happen is if the clipboard is being read by the application currently on the screen.
- Authorization to discover devices. Detecting Bluetooth devices in current Android 11 and below requires location permission (yes, that's right). In Android 12, this operation will have its own special permission.
- Lulling applications. Android 11 can revoke permissions from apps that have not been used for a long time. Android 12 goes even further and completely "lulls" such applications, taking away their disk space. To wake an application out of sleep, just start it.
Problems of incorrect configuration of cloud services
Mobile app developers' misconfiguration of third party services leave personal data of over 100 million exposed - an article about such application vulnerabilities that are caused by misconfiguration of cloud services. There are no practical examples of hacking in the article, but the general statistics are quite interesting.
- Incorrect configuration of the cloud database. Everything is simple here, databases open to the public are still often found, including in applications. As an example, the Astro Guru horoscope application saves the user's email, name, gender, location and date of birth to the database. And the application for ordering a taxi T'Leva stores full correspondence between passengers and drivers in an open database.
- Push notifications. Most push notification services require a cryptographic key associated with it to send a notification on behalf of a specific application. But what if this key is embedded in the code of the application itself in cleartext? In this case, the key can be retrieved and used to send notifications on behalf of this application.
- Network storages. With network storage, the problem is usually the same as with cloud databases. If you do not configure authentication or embed access keys directly into the application code, the data will be at risk. For example, the Screen Recorder app suffers from this problem with 10 million installations.
An example of a message retrieved from the T'Leva application database.
Another vulnerability in the Medium app
Exploiting Activity in medium android app - a short note about another stupid vulnerability in the mobile application of the Medium blog platform.
The essence of the article is as follows. There is activity in the application SaveToMediumActivity. All she does is save the article to her favorites list. It turned out that the activity is not only available from the outside to any other application (exported), but also allows you to save any URL to the list, not just articles published on Medium itself.
As a result, you can easily add anything to your favorites list using a simple application or the following command:
Code:
$ adb shell am start -n com.medium.reader/com.medium.android.donkey.save.SaveToMediumActivity -e android.intent.extra.TEXT "https://attacker.com"
Oh yes. For all this Medium paid a bug bounty.
Disassembly and analysis of malware
How to analyze mobile malware: a Cabassous / FluBot Case study - an article on the stages of analyzing malicious applications using the Cabassous / FluBot Trojan as an example.
- First, unpack the APK using apktool or any other similar tool.
- Open the file AndroidManifest.xmland find the main activity of the application. It has the following intent filter:
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- In the case of FluBot, the activity has a name com.tencent.mobileqq.MainActivity. But there is no such activity in the package.
- Let's see what other interesting files and classes are in the package. In the case of FluBot, the package also contained the following files: classes-v1.binin the dex directory (possibly encrypted malware code), a package com.whatsappin decompiled application code, packages n, npand obfuse(obviously obfuscated) and a library libreactnativeblob.so(it can also be found in the WhatsApp application).
- It is obvious that the malware authors simply repackaged WhatsApp, including malicious functionality. Therefore, the next thing to do is to find out how the original WhatsApp package differs from the sample we got. This can be done using the apkdiff utility :
- $ python3 apkdiff.py ../com.whatsapp_2.21.3.19-210319006_minAPI16\(x86\)\(nodpi\)_apkmirror.com.apk ../Cabassous.apk
- In this case, the author compares the malware with WhatsApp version 2.21.3.19 because the version name was found in the disassembled listings of the malware (in the file AbstractAppShell): 2.21.3.19-play-release.
- It turned out that the authors of the malware modified only four files of the original WhatsApp and, in general, there is nothing interesting in them. Therefore, the next step is to try to figure out where the main activity of the application is. Obviously, it's in the file classes-v1.bin, but what is it packed with? First, let's try using the APKiD utility .
APKiD is powerless
- It doesn't work. In this case, you should try to understand the code of the classes of the very packages n, npand obfuse. However, they are heavily obfuscated using unicode class names and reflection. You can figure it out, but it's easier to use dynamic analysis.
- To perform dynamic analysis, we need to understand how the malware actually launches its malicious functionality. As we have already seen, the activity specified in the manifest does not exist at all in the code. This means that it is somewhere in the packed (and encrypted) code and therefore the unpacking code must exist somewhere. Malware authors often insert such code into Java static initialization blocks, which are controlled immediately after the class is loaded and before the main activity of the application is started.
Static initializers are easy to find with grep
- Dexcalibur is one of the most convenient dynamic analysis tools. In fact, this is a graphical wrapper for Frida with pre-configured hooks and the ability to quickly install your own hooks. In the case of FluBot, Dexcalibur shows all uses of reflection, but the decompression function is not among them. This is because static initialization blocks are executed even before Frida starts working.
- Now we have three ways: try to understand the obfuscated loader code and remove the code for deleting the unpacked DEX file from it (usually the malware deletes it immediately after loading it into memory); find all static initializers, turn them into regular static functions and write the code to call them; copy the disassembled application code into Android Studio and run it under the control of the debugger.
- It turned out, however, that all this is unnecessary, since the malware for some reason forgets to delete the unpacked code after unpacking it. Therefore, it is enough to pull the already unpacked DEX file from the application's private directory:
- $ adb shell
- hammerhead:/ $ su
- hammerhead:/ # cp /data/data/com.tencent.mobileqq/app_apkprotector_dex /data/local/tmp/classes-v1.bin
- hammerhead:/ # chmod 666 /data/local/tmp/classes-v1.bin
- hammerhead:/ # exit
- hammerhead:/ $ exit
- $ adb pull /data/local/tmp/classes-v1.bin payload.dex
- /data/local/tmp/classes-v1.bin: 1 file pulled. 18.0 MB/s (3229988 bytes in 0.171s)
- Now you can safely start analyzing the malware code. Everything is pretty standard here, and you can read about it in the original article.
DEVELOPER
Optimizing application launch speed
From zero to hero: Optimizing Android app startup time is another article on optimizing the launch speed of Android applications. She does not tell anything new, but the author gives some very interesting observations.
- Koin is no slower than Dagger. It is generally accepted that the so-called service locator, which is Koin, is slower than a "real" DI framework like Dagger. The author's measurements show that after transferring the application from Koin to Dagger, the launch speed of the application does not change at all. Koin is fast.
- Object creation is a cheap operation. In the old days, it was considered good practice to use object pools instead of creating objects from scratch. Modern versions of Android allow objects to be created so quickly that object pools have ceased to play a role in application performance.
- Cleaning up the Application class doesn't help. Often, developers come up with the idea to remove all heavy operations from the Application class or to move them to background threads. Oddly enough, it doesn’t work.
- Firebase lazy initialization helps. About 60 milliseconds can be won on Firebase lazy initialization using androidx.startup.
- The android: useEmbeddedDex = true option might help. By default, Android runs application code not from the application package itself, but from a specially prepared odex file containing optimized and partially compiled code into machine instructions. This code works faster, but, as it turned out, takes longer to run. If you use the android: useEmbeddedDex = true option , you can achieve faster application launch, but lose in performance. To whom is more important.
- onCreate is where the problem usually lies. It is logical that most of the startup time is consumed by the method of the onCreatemain activity of the application. This is where the effort is worth.
- Obfuscation with ProGuard dramatically improves performance. ProGuard reduces the size of the application code so its impact is expected. On the other hand, the author does not specify whether he just turned on ProGuard or tested the release build of the application. After all, debug builds always work slower due to logging and disabled optimizations in libraries (in one of the previous releases of the digest, it was shown that debug build slows down the initialization of the coroutine library by about ten times - up to 100 milliseconds).
Another collection of tips
Top Put_your_number Kotlin utils we use all over our project - five Android development practices that can help you write cleaner, more testable code. The most interesting tricks:
Proxy for accessing resources. Android has a class Resourcesfor accessing application resources. The standard way to get an object of this class is through Context. However, this is not always convenient. For example, when binding a ViewHolder, you will have to access resources like this:
Code:
viewHolder.itemView.context.resources.getDimensionPixelSize(R.dimen.my_dimen)
A very long line. Also, we won't be able to clearly test this code (without using dirty hacks like Robolectric).
The solution to both problems is to create a wrapper for the Resources class:
Code:
interface ResourcesProvider {
val isRtl: Boolean
@ColorInt
fun getColor(@ColorRes resId: Int): Int
fun getString(@StringRes resId: Int): String
fun getString(@StringRes resId: Int, vararg args: Any): String
fun getDimen(@DimenRes resId: Int): Float
fun getDimenInt(@DimenRes resId: Int): Int
// Other methods
}
@Suppress("TooManyFunctions")
inline class AppResourcesProvider(
private val context: Context
) : ResourcesProvider {
override val isRtl: Boolean get() = context.isRtl
@ColorInt
override fun getColor(resId: Int) = context.getColorCompat(resId)
override fun getColorStateList(resId: Int): ColorStateList? = context.getColorStateListCompat(resId)
override fun getString(resId: Int) = context.getString(resId)
override fun getString(resId: Int, vararg args: Any) = context.getString(resId, *args)
override fun getDimen(resId: Int): Float = context.resources.getDimension(resId)
override fun getDimenInt(resId: Int) = context.resources.getDimensionPixelSize(resId)
// Other methods
}
The interface makes the class easy to mock for testing. In addition, all calls of the type getColorin the same ViewHolder can be delegated to it:
Code:
abstract class ResViewHolder(
itemView: View,
) : RecyclerView.ViewHolder(itemView), ResourcesProvider by AppResourcesProvider(itemView.context)
Simple and convenient, and thanks to the use of the word inline - in most cases the class will not even be created - the method code will be inlined in the caller.
Extension functions for changing indents. During development, it is often necessary to change the indentation of an interface element. The popular Android KTX extension library suggests doing it like this:
Code:
view.updateLayoutParams {
updateMarginsRelative(start = newMargin)
}
And this is a rather strange and not at all descriptive way. Instead, we would like to do it something like this:
Code:
view.margin.start = newMargin
The code to do this:
Code:
val View.margin get() = ViewMargin(this)
inline class ViewMargin(private val view: View) {
var start: Int
get() = view.marginStart
set(value) = applyMargin { marginStart = value }
var top: Int
get() = view.marginTop
set(value) = applyMargin { topMargin = value }
var end: Int
get() = view.marginEnd
set(value) = applyMargin { marginEnd = value }
var bottom: Int
get() = view.marginBottom
set(value) = applyMargin { bottomMargin = value }
var horizontal: Int
get() = start + end
set(value) {
start = value
end = value
}
var vertical: Int
get() = top + bottom
set(value) {
top = value
bottom = value
}
var total: Int
@Deprecated("No getter for that field", level = DeprecationLevel.HIDDEN)
get() = throw UnsupportedOperationException("No getter for such field")
set(value) {
horizontal = value
vertical = value
}
private inline fun applyMargin(body: ViewGroup.MarginLayoutParams.() -> Unit) {
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
view.updateLayoutParams(body)
} else {
throw IllegalStateException("Parent layout doesn't support margins")
}
}
}