Android Malware Analysis
1. Preparing the Lab
We’ve chosen to use the first configuration:
Android Studio and an emulator that needs a virtualization backend (needs more resources)
We started with option 3, but encountered issues with the VirtualBox image, particularly the smartphone emulator, which kept loading and timing out. Option 2 is terrible because installing malware on the phone doesn’t sound like a great idea.
The computer is running Windows 11 with WSL enabled. WSL uses a subset of Hyper-V. The quickest way to disable Hyper-V is to run the reversible command (auto
instead of off
) in PowerShell and then reboot the computer.
bcdedit /set hypervisorlaunchtype off
More details about bcedit
command here.
Now, since we deactivated Hyper-V and can no longer use WSL, we’re going to use Powershell 💀. Also we’ll use Ghidra instead of radare2.
This is the only configuration/compromise we had to do.
- HAXM is running
- Intel-VT is enabled
- AndroidStudio is installed
- Java is installed. we’ll keep using 19.0.1 until we have issues.
Everything seems good, it’s time to start working.
2. Lab Exercices
2.1 Labs from Teaching Android Mobile Security
A. Programming an antidote for a ransomware
We used the emulated smartphone’s camera to take a selfie, this is what we got:
Upon opening the the app, we get the following screen:
We find that the images we’ve taken are now encrypted:
After decompiling with JadX, we find this important function in MainService
.
The antidote is simple, we have to copy the source of the application while changing var.encrypt()
by var.decrypt()
.
And of course it works !
B. Packers
Upon giving PackLab the permission to access the contacts, they were deleted. In Jadx we can see that when permissions are given, beEvilSetup
is called. The details of this method are:
public native void decodeMethod(String paramString1, String paramString2);
decodeMethod
is a native method that will load the code of the beEvil
method which is the malicious method. Let’s look at the content of native-lib
to understand how it does it.
The loaded asset butterfly.png
is indeed not an image, it’s probably just raw data:
In native-lib, this data is xored with the word register w11
which remains a constant in the loop’s body block. To find the value of life w11 lies in previous block: It’s 0x42.
The next step is to download the data in butterfly.png
, write a python script to emulate the xoring
done by decodeMethod
. The result is a new file that we’ll name unpacked_malware.dex
. Indeed it’s a Dalvik dex file:
We can now ran Jadx again to decompile it and see the content of the beEvil
method:
Unfortunately, there is no remedy to this malware.
C. Hacking a spyware
The used permissions are:
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
The only permissions that immediately jump out to me are INTERNET
, ACCESS_FINE_LOCATION
which should not be needed for a kitchen timer.
KitchenTimerService
is a service used to schedule tasks that fire KitchenTimerService.ACTION ("Kitchen Timer Service")
intents. The receiver of this intent is registered in onCreate
method of the Main
class.
When this intent is received, user data containing device identifier
, phone number
and geographic address
of the user is sent out to an external server as GET query parameters.
I’ve customized the provided gist to create a python server listening on 8080. We think the Java 8 part was necessary because the jar
throws an exception. we decided to do the address translation manually:
- Run the emulator with a writable file system
emulator -avd Pixel_6_Pro_API_24 -partition-size 512 -writable-system
- Acquire root privileges in the emulator with
adb root
and remount the/system
partition in writable mode withadb remount
. Finally runadb shell
. - Run
echo "10.0.2.2 14243444.com" >> /etc/hosts
. In essense,10.0.2.2
should point to the host machine. - The only remaining task is to redirect outgoing packets from
10.0.2.2:80
to10.0.2.2:8080
iptables -t nat -A OUTPUT -p tcp -d 10.0.2.2 --dport 80 -j DNAT --to-destination 10.0.2.2:8080
Actually nevermind the last step if you can run your python server on the port 80 directly.
Let’s finally see what this malware does:
The spyware crashes before it can figure out the geocoordinates. We imagine this is because our Python server sends an empty reply. We changed that, and now it successfully gets the geocoordinates. It sometimes randomly opens up Japanese google, we guess this is a form of diversion ? Not sure. but anyways, we confirmed our suspicions about this user tracking spyware.
3. The challenge begins
1. The easy one
This malware is a ransomware that encrypts files on the victim’s smartphone.
When the malware is launched for the first time (detection via preferences), it launches the newone activity. This activity encrypts files starting with the SD Card, but we observed that the images we took are also encrypted. we guess this is because listFiles()
returns the path ../
.
The encryption function:
The second time this application is launched, the lock
activity is started. This shows the classic ransomware screen above. Reading more code, this malware encrypts files using DES (Data Encryption Standard). This is a symmetric encryption algorithm whose key is present in the code:
But it is easier to solve challenge that ransomware and decrypt the file system:
You can get this.val$xx
by clicking Copy
:
Then we sha_1 . md5
this value:
And of course it works.
2. The easy one #2
Using some quality OCR to dechipher the program:
It doesn’t tell much except the existence of a password and/or a timer to exit the program. Oh, it seems we can’t exit the program because the malware forces the focus back on the app. This is the case even if the phone is rebooted.
Clicking the back button few times shows this prompt:
Looking at JadX, the solution to the prompt challenge is easy to spot:
And of course it works.
3. The hard one
Upon installing the app, Nothing happened.
We thought that adb didn’t install the app correctly, so we went on to install it again. Of course, it doesn’t work. It is also impossible to delete the app. It seems that our malware is installed. Using JadX, we get a hardly readable code, the few thing that we can notice right away are:
- loading an external file
- decrypting it algorithm is DES, looks like ECB mode
- loading classes from the decrypted jar file and doing shady stuff with them
Looking at the ressources, we find our first clues:
Indeed when visiting the accessibility settings we find:
Looking at the devtools Package summary
we found this:
The malware is installed as a privileged app, which explains why it can’t be uninstalled. But how can it be installed on a read-only file system ?
ProxyService
also runs some services:
Let’s try to gain control of the external file.
a. Getting the secret key
Which gives the output:
b. decrypting the file using python
And it actually works.
We find the code behind the services run by ProxyService
. This code is hard to read and we give up 😞.