Summary
Pegasus is a spyware developed by the NSO group that was repeatedly analyzed by Amnesty International and CitizenLab. In this article, we dissect the Android version that was initially analyzed by Lookout in this paper, and we recommend reading it along with this post. During our research about Pegasus for Android, we’ve found out that vendors wrongly attributed some undocumented APK files to Pegasus, as highlighted by a researcher here. We’ve splitted the analysis into 3 parts because of the code’s complexity and length. We’ve also tried to keep the sections name proposed by Lookout whenever it was possible so that anybody could follow the two approaches more easily. In this part, we’re presenting the initialization of the application (including its configuration), the targeted applications, the commands related to the core functionality, and the methods that Pegasus could use to remove itself from a device. Our contributions consist of dissecting the application deeper than before and explaining additional functionalities that were identified.
Technical analysis
SHA256: ade8bef0ac29fa363fc9afd958af0074478aef650adeb0318517b48bd996d5d5
We’ve performed the analysis using JD-GUI Java Decompiler and Android Studio.
Initial Launch and Configuration
The application must obtain an initial configuration from an URL found in the Browser history or from a file called “/data/myappinfo” or “/system/ttg”. As we’ll see during the entire analysis, the malware is pretty noisy and logs messages using the Log.i method. Interestingly, the author mentions the JigglyPuff character from Pokemon in the logging function:
Firstly, the application tries to parse a config file called “/data/myappinfo” or “/system/ttg” if the first one doesn’t exist:
The malware deletes a file called “/data/cksnb.dat” using a binary called “/system/csk”. According to Lookout, this file is present on devices that were previously rooted. The purpose of this binary is to run a command passed as a parameter (such as “rm”) with root privileges:
Whether the process finds one of the configuration files mentioned above, it reads an URL that will be deleted from the Browser history. Some of the settings are Base64-encoded and will be decoded using an implementation of the Base64 algorithm:
The application reads a token and an “installation” value from the configuration file:
Furthermore, the process reads a configuration value called “local” and another one called “userNetwork”, which represents the mobile country code of the victim’s phone:
The malware reads a configuration value that specifies whether it should communicate with the C2 server while the phone is roaming. The configuration file also contains commands to be executed by Pegasus:
The version of the installed agent (“packageVersion”) and a value called “vulnarbilityIndicator” are also read from the configuration file. The last value is set when requesting an update package, and it would create an mp3 file that exploits the Media Player on the phone, according to our analysis:
The agent copies a file called “/data/cksnb.dat” to “/data/data/com.network.android/output.mp3”. As also highlighted below, the mp3 file would exploit a “vulnarbility” [sic] in Media Player:
A config value called “url address” will be removed from the browser history. The application extracts a table containing both bookmarks and history items from Browser.BOOKMARKS_URI:
As we mentioned before, the application could retrieve the configuration from an URL containing “rU8IPXbn” found in the Browser history, as highlighted in figure 14.
The agent parses the target URL and extracts a token (“t=” parameter), a Base64-encoded command and signature (“&c”), the “installation” value (“&b”), the “userNetwork” configuration option (“&d”), and the “windowYuliyus” value (“&r”):
The malware expects a valid token and a valid target URL; otherwise, it calls the Log.e method with the “getSettingsFromBH no valid settings on getSettingsFromHistory” message:
The agent calls a function that validates the MCC (mobile country code) extracted from the configuration:
The getSubscriberId function is utilized to extract the unique subscriber ID. The first 3 digits represent the mobile country code (MCC), which is compared with the value extracted from the configuration:
The application verifies whether the “did_we_restart_after_upgrade_already” value, which indicates that the device was rebooted after the installation of Pegasus, is true or false. In the case of no reboot, the application restarts the phone using the “reboot” command:
Figure 20 reveals how the “/system/csk” binary is used to run commands with root privileges:
The agent uses a regex to parse the target URL and to extract the IP address and the token, as highlighted below:
The process calls a function that deletes the target URL from the Browser history based on the IP address extracted above:
The malware starts logging some messages before performing the deletion operation:
The application retrieves the bookmarks and history items from “Browser.BOOKMARKS_URI” and “Browser.HISTORY_PROJECTION”:
The URL containing “rU8IPXbn” is deleted from the Browser history by calling the Browser.deleteFromHistory function:
The configuration data is saved in a preference file called “NetworkPreferences” that can be accessed using the Android SharedPreferences APIs.
Targeted Applications
1. Facebook
The database files storing the Facebook messages are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.facebook.katana
- chmod 0777 /data/data/com.facebook.katana/databases
- chmod 0777 /data/data/com.facebook.katana/databases/threads_db2
- chmod 0777 /data/data/com.facebook.katana/databases/threads_db2-journal
The following SQL query is executed:
- SELECT messages.msg_id, messages.thread_id, messages.timestamp_ms, messages.text, messages.sender, threads.participants from messages INNER JOIN threads ON messages.thread_id=threads.thread_id
2. Kakao
The database files storing the KakaoTalk chat logs are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.kakao.talk
- chmod 0777 /data/data/com.kakao.talk/databases
- chmod 0777 /data/data/com.kakao.talk/databases/KakaoTalk.db
- chmod 0777 /data/data/com.kakao.talk/databases/KakaoTalk.db-journal
The following SQL query is executed:
- SELECT chat_logs.id, chat_logs.chat_id, chat_logs.created_at, chat_logs.message, chat_logs.user_id, chat_logs.type, c.members FROM chat_logs JOIN chat_rooms c ON chat_logs.chat_id=c.id
3. Skype
The database files storing the Skype chat messages are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.skype.raider/files/<Directories>
- chmod 0777 /data/data/com.skype.raider/files/main.db
- chmod 0777 /data/data/com.skype.raider/files/main.db-journal
The following SQL query is executed:
- SELECT Messages.id as msg_id, messages.convo_id, from_dispname, messages.author, messages.timestamp, messages.body_xml, conversations.displayname, Messages.dialog_partner FROM Messages LEFT JOIN Conversations ON messages.convo_id = conversations.id
4. Twitter
The database files storing the Twitter messages are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.twitter.android
- chmod 0777 /data/data/com.twitter.android/databases/*.db
The following SQL query is executed:
- SELECT messages._id, messages.type, messages.msg_id, messages.content, messages.created, messages.sender_id, messages.recipient_id, messages.thread, s.name, s.username, r.name, r.username FROM messages JOIN users s ON messages.sender_id = s.user_id JOIN users r ON messages.recipient_id = r.user_id
5. Viber
The database files storing the Viber messages are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.viber.voip/
- chmod 0777 /data/data/com.viber.voip/databases/viber_messages
- chmod 0777 /data/data/com.viber.voip/databases/viber_messages-journal
The agent executes the SQL query displayed in the figure below.
6. WhatsApp
The database files storing the WhatsApp messages are made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.whatsapp
- chmod 0777 /data/data/com.whatsapp/databases
- chmod 0777 /data/data/com.whatsapp/shared_prefs
- chmod 0777 /data/data/com.whatsapp/shared_prefs/com.whatsapp_preferences.xml
- chmod 0777 /data/data/com.whatsapp/databases/msgstore.db
- chmod 0777 /data/data/com.whatsapp/databases/wa.db
The following SQL queries are executed:
- select * from messages
- select timestamp from messages order by _id desc limit 1
7. Gmail
The following SQL queries are executed (“/data/data/com.google.android.gm/databases/EmailProvider.db” database):
- select * from messages
- select * from Message
- select _id from messages order by _id desc limit 1
- select _id from Message order by _id desc limit 1
8. Android Native Email
The database file storing the Android Native emails and attachments is made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.android.email
- chmod 0777 /data/data/com.android.email/databases/EmailProvider.db
The following SQL queries are executed:
- select * from Message where _id = <Id>
- select * from Attachment where _id = <Id>
9. Android Native Browser
The database file storing the user name and password entered in the WebView is made accessible to everyone by running the following commands:
- chmod 0777 /data/data/com.android.browser
- chmod 0777 /data/data/com.android.browser/databases
- chmod 0777 /data/data/com.android.browser/databases/webview.db
The following SQL query is executed:
- select * from password
The agent also extracts the bookmarks and history items from Browser.BOOKMARKS_URI and Browser.HISTORY_PROJECTION.
10. Default Calendar
The agent extracts the Android version string from the “Build.VERSION.RELEASE” property:
Depending on the Android version, the calendar’s events can be found at “content://com.android.calendar/events” or “content://calendar/events”, as shown in figure 43:
The application extracts the events title, summary, description, and other properties (see figure 44). The calendar entries are added to an XmlSerializer object that has multiple attributes:
Suicide Functionality
1st method
The agent will kill itself if it finds a file called “/sdcard/MemosForNotes” on the device:
The malware starts the removal operation by logging the “removeAppalication start” message, as shown in the figure below:
The application removes all files that are located in the “/data/local/tmp/ktmu” directory:
The SharedPreferences.Editor.clear function is utilized to remove the following preference files containing configuration data: “NetworkPreferences”, “NetworkWindowAddresess”, and “NetworkDataList” (see figure 48).
The following commands are run by the malware:
- export LD_LIBRARY_PATH=/vendor/lib:/system/lib – set the LD_LIBRARY_PATH environment variable
- mount -o remount,rw /dev/null /system – remount the system directory
- force-stop com.network.android – stop the malicious application
- disable com.network.android – disable the malicious application
- rm /system/app/com.media.sync.apk – remove this file
- pm uninstall com.network.android – uninstall the malicious application
- rm /system/ttg – remove the configuration file
- chmod 0777 /system/csk; rm /system/csk – delete the binary used to run commands with root privileges (“superuser binary”)
2nd method
The malware will also remove itself if it didn’t communicate with the C2 server in the last 60 days:
3rd method
The suicide functionality is also used when no subscriber ID is identified (see figure 18).
4th method
The Pegasus’ C2 server can issue a command to the agent in order to remove itself.
Pegasus implements 4 main commands that can be executed: dumpCmd, upgradeCmd, camCmd, and emailAttCmd (figure 51).
dumpCmd command
The agent can activate/deactivate some actions depending on the dumpSms, dumpWhatsApp, dumpEmails, dumpContacts, dumpCalander [sic], dumpCall boolean values:
The agent extracts the SMS messages sent and received from “content://sms/sent” and “content://sms/inbox”. Every SMS is stored in a new XmlSerializer object, as highlighted below:
The malware extracts the Phone call logs from “CallLog.Calls.CONTENT_URI”. Each log is stored in a new XmlSerializer object that contains attributes such as “recordId”, “timestamp”, “type”, “number”, “duration”, “isStart”, and “direction”:
The application retrieves the phone contacts from the “ContactsContract.Contacts.CONTENT_VCARD_URI” entry. Every contact is stored in an XmlSerializer object:
The agent obtains a list of application processes running on the device via a call to getRunningAppProcesses:
This command is also responsible for retrieving the information already described in the “Targeted applications” section.
upgradeCmd command
The process creates a file called “/data/data/com.network.android/upgrade/uglmt.dat” that will store the upgraded application that is downloaded from the C2 server. It computes the MD5 hash of the file and then compares the result with a value that comes with the package:
The agent loads uglmt.dat as a dex file using DexClassLoader and then calls the “com.media.provapp.DrivenObjClass.perfU” method with the “/data/data/com.network.android/upgrade/intro.mp3” argument:
After successfully upgrading the agent, the following files are deleted by calling the File.delete function:
- /data/data/com.network.android/upgrade/uglmt.dat
- /data/data/com.network.android/upgrade/cuvmnr.dat
- /data/data/com.network.android/upgrade/zero.mp3
- /data/data/com.network.android/upgrade/*com.media.sync*
camCmd command
Firstly, the process relies on a binary that should exist on Android called “/system/bin/screencap” in order to take a screenshot of the screen. The result is saved as a PNG image at “/data/data/com.network.android/bqul4.dat”:
Secondly, if the above binary doesn’t exist then the malware will use a resource (found in res/raw/ folder) called “take_screen_shot” that will handle the operation. The result is stored at “/data/data/com.network.android/tss64.dat”:
In any case, the screenshots’ information will be stored in an XmlSerializer object described below:
As we can see in the assembly code of take_screen_shot, the binary captures the Android screen content by reading the “/dev/graphics/fb0” framebuffer that is processed and stored as a PNG image:
The captured PNG images are compressed to JPG and saved as “ScreenShot-res<Integer>-<Current Time in seconds>.jpg”:
The process can take photos with the front/back camera. It calls the getParameters function in order to obtain the current settings for the Camera service and then calls getPreviewFormat:
Depending on the front/back camera, the taken photo is saved as “Front-res<Integer>-<Current Time in seconds>.jpg” or “Back-res<Integer>-<Current Time in seconds>.jpg”
emailAttCmd command
The application creates a database containing a table called “NetworkData” that stores the email attachments’ name and path, as displayed in figure 74.
The command’s purpose is to extract a specific email attachment mentioned by the C2 server:
We were surprised to find out that during the initialization routine, the threat actor mentioned the “Pegasus” string in a log message: