Android.HeHe: Malware Now Disconnects Phone Calls

FireEye Labs has recently discovered six variants of a new Android threat that steals text messages and intercepts phone calls. We named this sample set “Android.HeHe” after the name of the activity that is used consistently across all samples.

Here is a list of known bot variants:

MD5 VirusTotal Detection Ratio
1caa31272daabb43180e079bca5e23c1 1caa31272daabb43180e079bca5e23c1 2/48 2/48
8265041aca378d37006799975fa471d9 8265041aca378d37006799975fa471d9 1/47 1/47
2af4de1df7587fa0035dcefededaedae 2af4de1df7587fa0035dcefededaedae 2/45 2/45
2b41fbfb5087f521be193d8c1f5efb4c 2b41fbfb5087f521be193d8c1f5efb4c 2/46 2/46
aa0ed04426562df25916ff70258daf6c aa0ed04426562df25916ff70258daf6c 1/46 1/46
9507f93d9a64d718682c0871bf354e6f 9507f93d9a64d718682c0871bf354e6f 1/47 1/47


The app disguises itself as “android security” (Figure 1), attempting to provide the users what is advertised as an OS Update. It contacts the command-and-control (CnC) server to register itself then goes on to monitor incoming SMS messages. The CnC is expected to respond with a list of phone numbers that are of interest to the malware author. If one of these numbers sends an SMS or makes a call to an infected device, the malware intercepts the message or call, suppresses device notifications from the device, and removes any trace of the message or call from device logs. Any SMS messages from one of these numbers are logged into an internal database and sent to the CnC server. Any phone calls from these numbers are silenced and rejected.

[caption id="attachment_4369" align="aligncenter" width="302"]App installs itself Figure 1[/caption]


This app starts the main HeHe activity at startup. The constructor of the HeHeActivity registers a handler using the android.os.Handle, which acts as a thread waiting for an object of type android.os.Message to perform different actions, which are outlined below.

Because the HeHeActivity implements the standard DailogInterfaceOnClickListener, the start of the app causes the showAlterDailog message to be displayed (Figure 2).

[caption id="attachment_4373" align="aligncenter" width="404"]Fake OS Update in progress Figure 2: The above messages make the user believe that an OS update check is under progress[/caption]

The app then sends an intent to start three services in the background. These services are explained below.

Sandbox-evasion tactic

This app checks for the presence of an emulator by calling the isEmulator function, which does the following:

  1. It checks the value of the MODEL of the device (emulators with the Google ADT bundle have the string “sdk” as a part of the MODEL variable).
  2. It also checks to see if the IMSI code is “null” — emulators do not have an IMSI code associated with them.

Here is the isEmulator code:

String v0 = TelephonyUtils.getImsi(((Context)this));
if(v0 == null) {
public static boolean isEmulator() {
boolean v0;
if((Build.MODEL.equalsIgnoreCase("sdk")) || (Build.MODEL.equalsIgnoreCase("google_sdk"))) {
v0 = true;
else {
v0 = false;
return v0;

The code checks whether the the app is being run in the Android QEMU emulator. It also checks whether the value of IMSI is equal to null


This service runs in the background. Once started the app calls the setComponentEnabledSetting method as follows:

this.getPackageManager().setComponentEnabledSetting(new ComponentName(((Context)this), HeheActivity.class), 2, 1);

This removes the app from the main menu of the phone leading the user to believe that the app is no longer installed on the phone. It then goes on to check the network status of the phone as shown below

public void checkNetwork() { 
if(!this.isNetworkAvailable()) {

After the service has been created. The onStart method is called, which checks the message provided as a part of the intent. The message types are START and LOGIN


If the message in the intent is START, The app calls the sendReigsterRequest() function. The sendRegisterRequest function first checks for the presence of an emulator as explained in the "Sandbox-evasion tactic" section

It then collects the IMSI IMEI, phone number, SMS address and channel ID. It packs all this information into a JSON object. Once the JSON object is created. It is converted to a string, which is sent to the CnC server. The CnC communication is explained below.


If the message in the intent is LOGIN, the app calls the sendLoginRequest method, which in turn collects the following:

  • Version number of the app (hard-coded as "1.0.0")
  • The model of the phone
  • The version of the operating system
  • The type of network associated with the device (GSM/CDMA)

This information is also packed into a JSON object, converted into a string, and sent to the CnC server.

RegisterBroadcastReceiver service

This service is invoked at the start of the app as the RegisterService. It in turn registers the IncomeCallAndSmsReceiver(), which is set to respond to these three intents:

  • android.provider.Telephony.SMS_RECEIVED, which notifies once a SMS has been received on the device
  • android.intent.action.PHONE_STATE, which notifies once the cellular state of the device has changed. Examples include RINGING and OFF_HOOK.
  • android.intent.action.SCREEN_ON, which notifies once the screen has been turned on or turned off.

Additionally, it also sets observers over Android content URIs as follows:

  • The SmsObserver is set to observe the content://sms, which enables it to access all SMS messages that are present on the device.
  • The CallObserver is set to observe the content://call_log/calls, which allows it to access the call log of all incoming, outgoing and missed calls on the device.


The main HeHe activity mentioned at the start issues the ACTION_START intent to the ConnectionService class as follows:

Intent v2 = new Intent(((Context)this), ConnectionService.class);


v2.setFlags(268435456); this.startService(v2); LogUtils.debug("heheActivity", "start connectionService service"); The app then starts a timer task that is scheduled to be invoked every 5000 seconds. This timed task does the following:
  • Creates an object instance of the android.os.Message class
  • Sets the value of "what" in the Message object to 1
  • The handler of this message that was initiated in the constructor then gets called which, in turn calls the showFinishBar function that displays the message “현재 OS에서 최신 소프트웨어버전을 사용하고있습니다,” which translates to “The current OS you are using the latest version of the software.”



The RegisterBroadcastReceiver registers this receiver once the app gets started. When an SMS is received on the device. The IncomeCallAndSmsReceiver gets the intent. Because this receiver listens for one of three intents, any intents received by this receiver are checked for their type.

If the received intent is of type android.provider.telephony.SMS_RECEIVED, the app extracts the contents of the SMS and the phone number of the sender. If the first three characters of the phone number matches the first three characters from phone numbers in a table named tbl_intercept_info, then the SMS intent is aborted and the SMS is deleted from the devices SMS inbox so that the user never sees it. After the SMS notification is suppressed, the app bundles the SMS as follows:

"createTime":"2014-01-10 16:21:36",

From there, it sends the to the CnC server (

It also records the SMS in the tbl_message_info table in its internal database.

If the received intent is of type android.intent.action.PHONE_STATE, the app checks the tbl_intercept_info table in the local database. If the number of the caller appears in this table, then the ringer mode of the phone is set to silent to suppress the notification of the incoming call and the phone call is disconnected. Its corresponding entry from the call logs is also removed, removing all traces of the phone call from the device.

No actions have been defined for the intent, even though the IncomeCallAndSmsReceiver receiver is the recipient.


This app uses two hard-coded IP address to locate its CnC servers: and The app performs all communications through HTTP POST requests. The contents of the HTTP POST are encrypted using AES with a 128-bit key that is hardcoded into the app. The app sends its lastVersion value —to, to address is where is used to check for , in which the app sends its version of the app. The address is used to report incoming SMS messages

Because the IP address is no longer reachable, responses from the server could not be analyzed. What is clear is that the server sends a JSON object in response, which contains a "token" field.

Although the CnC server is currently unavailable, we can infer how the app works by examining the how it processes the received responses.

The app consists of different data structures that are converted into their equivalent JSON representations when they are sent to the CnC. Also, All JSON object responses are converted into their equivalent internal data structures. We have also observed the mechanism used to populate the internal database which includes tables (tbl_intercept_info) which contain the phone numbers to be blocked.

The app uses hxxp:// and hxxp:// to send information to the CnC server.

The mapping of URLs to their internal class data structures is as follows:

GetLastVersionRequest /getLastVersion
RegisterRequest /register
LoginRequest /login
ReportRequest /report
GetTaskRequest /getTask
ReportMessage Request /reportMessage

The meaning and structures of these are explained in the following sections.


This request is sent when the app is first installed on the device. The bot sends the version code of the device (currently set to 1.0.0) to the CnC. The CnC response shall contain the URL to an update if available. The availability of an update is signified through an ‘update’ field in the response

[caption id="attachment_4377" align="alignnone" width="816"]Request to CnC to check for version Request to CnC to check for version[/caption]


This request is sent when the app sends an intent with a “LOGIN” option to the RegisterService as explained  above. The request contains the IMSI, IMEI, Phone number, SMS address (Phone number), Channel ID, a token and the IP address being used by the app as its CnC. This causes the infected device to be registered with the CnC.


This request is sent to further authenticate the device to the CnC, It contains the token previously received, the version of the Bot, the model of the phone, the version of the OS, the type of network and the other active network parameters such as signal strength. In response, It only gets a result value.


The report request sends the information present in tbl_report_info to the CnC. This table contains information about other requests that were sent but failed.


This requests asks for tasks from the CnC server. The response contains a retry interval and a sendSmsActionNotify value. It is sent when the response to the LoginRequest is 401 instead of 200.


This request to the CnC sends the contents of the SMS messages that are received on the device. It consists of the contents of the SMS message, the time of the message and the sender of the SMS. This has been observed in the logcat output as follows:



Android malware variants are mushrooming. Threats such as Android.HeHe and Android.MisoSMS reveal attackers' growing interest in monitoring SMS messages and phone call logs. They also serve as a stark reminder of just how dangerous apps from non-trusted marketplaces can be.