A technical analysis of Pegasus for Android – Part 1

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:

Figure 1
Figure 2

Firstly, the application tries to parse a config file called “/data/myappinfo” or “/system/ttg” if the first one doesn’t exist:

Figure 3
Figure 4

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:

Figure 5

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:

Figure 6

The application reads a token and an “installation” value from the configuration file:

Figure 7

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:

Figure 8

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:

Figure 9

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:

Figure 10

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:

Figure 11
Figure 12

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:

Figure 13

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.

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”):

Figure 15

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:

Figure 16

The agent calls a function that validates the MCC (mobile country code) extracted from the configuration:

Figure 17

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:

Figure 18

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 19

Figure 20 reveals how the “/system/csk” binary is used to run commands with root privileges:

Figure 20

The agent uses a regex to parse the target URL and to extract the IP address and the token, as highlighted below:

Figure 21
Figure 22

The process calls a function that deletes the target URL from the Browser history based on the IP address extracted above:

Figure 23

The malware starts logging some messages before performing the deletion operation:

Figure 24

The application retrieves the bookmarks and history items from “Browser.BOOKMARKS_URI” and “Browser.HISTORY_PROJECTION”:

Figure 25

The URL containing “rU8IPXbn” is deleted from the Browser history by calling the Browser.deleteFromHistory function:

Figure 26
Figure 27

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
Figure 28

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
Figure 29

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
Figure 30

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
Figure 31

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.

Figure 32

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
Figure 33
Figure 34

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
Figure 35
Figure 36

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>
Figure 37
Figure 38

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.

Figure 39
Figure 40
Figure 41

10. Default Calendar

The agent extracts the Android version string from the “Build.VERSION.RELEASE” property:

Figure 42

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:

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:

Figure 44

Suicide Functionality

1st method

The agent will kill itself if it finds a file called “/sdcard/MemosForNotes” on the device:

Figure 45

The malware starts the removal operation by logging the “removeAppalication start” message, as shown in the figure below:

Figure 46

The application removes all files that are located in the “/data/local/tmp/ktmu” directory:

Figure 47

The SharedPreferences.Editor.clear function is utilized to remove the following preference files containing configuration data: “NetworkPreferences”, “NetworkWindowAddresess”, and “NetworkDataList” (see figure 48).

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”)
Figure 49

2nd method

The malware will also remove itself if it didn’t communicate with the C2 server in the last 60 days:

Figure 50

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).

Figure 51

dumpCmd command

The agent can activate/deactivate some actions depending on the dumpSms, dumpWhatsApp, dumpEmails, dumpContacts, dumpCalander [sic], dumpCall boolean values:

Figure 52

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:

Figure 53
Figure 54

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”:

Figure 55
Figure 56

The application retrieves the phone contacts from the “ContactsContract.Contacts.CONTENT_VCARD_URI” entry. Every contact is stored in an XmlSerializer object:

Figure 57
Figure 58
Figure 59

The agent obtains a list of application processes running on the device via a call to getRunningAppProcesses:

Figure 60

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:

Figure 61
Figure 62

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:

Figure 63
Figure 64

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*
Figure 65

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”:

Figure 66

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”:

Figure 67

In any case, the screenshots’ information will be stored in an XmlSerializer object described below:

Figure 68

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:

Figure 69
Figure 70

The captured PNG images are compressed to JPG and saved as “ScreenShot-res<Integer>-<Current Time in seconds>.jpg”:

Figure 71

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:

Figure 72

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”

Figure 73

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.

Figure 74

The command’s purpose is to extract a specific email attachment mentioned by the C2 server:

Figure 75
Figure 76

We were surprised to find out that during the initialization routine, the threat actor mentioned the “Pegasus” string in a log message:

Figure 77