Click here to Skip to main content
15,867,568 members
Articles / Mobile Apps / Android

A way to create "deathless" Android applications

,
Rate me:
Please Sign up or sign in to vote.
3.61/5 (11 votes)
5 Mar 2015CPOL6 min read 27.3K   889   21   11
An interesting approach to create Android applications, which user cannot remove or stop (only admin can do this applying specific password), without using ROOT permissions.

Downloads

Download deathlessandroid-ProtectedService.zip

Download deathlessandroid-ApkWithAdb.zip

1. Introduction

Some types of applications require that the end users can not be able to remove or at least stop the application. For example, all types of Parental Controls, Data Leak Prevention, and applications with similar concepts should work on devices regardless of the user’s intentions. On the other hand, when trying to search proven solutions for implementing such applications, we cannot find some comprehensive answers in the Internet.

Though, there are individual solutions for the "Disable force stop and uninstall button on Android" tasks, but in order to activate these buttons, you simply need to perform the user’s actions in reverse order.

As for the task of creation of an unkillable application, there are opinions that it cannot be supported by the concept of Android (1, 2, 3), because the basic idea of this OS is to give the user permission to work with his device as he wishes.

However, we are going to consider one of the ways to create an application that can be stopped or removed only by the user (Admin), who installed it.

2. The task

2.1 Appearance of the application

Task: Create the TryStopOrUninstallMe application.

After the application start and security policy acceptance, within a 10 seconds timeout, application displays the information that it successfully works (Toast  with the “Ooops! Try to kill me :)” text).

If you stop the service, it will be restarted no later than in 2 seconds (by timeout).

The ForceStop and Uninstall buttons are inactive in the application menu. When you try to activate these buttons by disabling DeviceAdministrator for the application, phone is locked. At the same time the previous user password is deleted and further calls can be made only after unlocking the phone by administrator, who knows the password.  

2.2 Used technologies

Programming language: Java.

Used libraries and technologies: Android SDK.

Minimum supported version of Android: 2.2

Maximum supported version of Android: 5.0.2 (the newest one for today)

ROOT-permissions requirements on the device: not required

Testing: the application was tested on Nexus 5 with Android 5.0.1.

2.3 Pending issues

In order to keep this article short and because of the triviality of the problem, we do not consider:

  1. Creation of start Activity, in which the administrator would set a master password. Instead, we have simply hardcoded it (e.g., "12345");
  2. Application startup at system startup.

3. The general principles of the mechanism

The following approaches will be used to implement this idea:

  1. Disabling the application forced stop and uninstall will be implemented using Device Administration API. Although it is designed for a little bit different purposes (some of which will be shown later), we’ll use it as a "deactivator" of the ForceStop and Uninstall buttons for our application (a side effect is actually what we need):

To uninstall an existing device admin application, users need to first unregister the application as an administrator.

  1. There is no standard mechanism to disable the DeviceAdmin mode unlocking for user. However, we can sign up to receive event alerts on removing our application from the list of administered ones. And in this case we can:
    1. Reset the current password for device locking (one of the DeviceAdmin API purposes);
    2. Lock the phone (another great DeviceAdmin API feature).
  2. Our application will use the service to run in the background. For the cases when user tries to stop our service (Settings -> Application -> RunningServices) we will implement auto-start using the AlarmManager system mechanism.
  3. If user stop the service and have enough time to go to the application menu until the system restarts the service, then the application (not the service) stop button will be available for him.

Image 1

After application is stopped, nothing can be restarted by itself. Thus, to deprive user of this chance, we will redirect him to his desktop and lock the device. While user is returning to the target Activity, system has enough time to restart the service (during my testing, it always takes 1-2 seconds).

3. The general principles of the mechanism

3.1 Graphical representation

Image 2

Pic. 3.1 – Scheme that demonstrates the activation of mechanism for self-protection against application stop or uninstall

Image 3

Pic. 3.2 – Device behavior while user tries to disable self-protection against application stop or uninstall

Image 4

Pic. 3.3 – Device behavior while user tries to stop the service manually

4. Implementation of the mechanism

4.1 Activation of the mechanism for self-protection against the application stop and uninstall, and the service launch (MainActivity.java)

Java
public class MainActivity extends Activity {
	private static final int REQUEST_CODE = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		try {
			// Initiate DevicePolicyManager.
			DevicePolicyManager policyMgr = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

			// Set DeviceAdminDemo Receiver for active the component with different option
			ComponentName componentName = new ComponentName(this, DeviceAdminDemo.class);

			if (!policyMgr.isAdminActive(componentName)) {
				// try to become active
				Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
				intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
				intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
						"Click on Activate button to protect your application from uninstalling!");
				startActivity(intent);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		startService(new Intent(this, BackgroundService.class));
	}
}

Everything that is done in the main (and only one) Activity is DeviceAdmin activation and service launch. It is expected that the device administrator activates the protection by pressing Activate.

Image 5

Otherwise, the user can stop or remove the application in a standard way.

4.2 The service launch and its running (BackgroundService.java)

Java
public class BackgroundService extends Service {

	private static final int FIRST_RUN_TIMEOUT_MILISEC = 5 * 1000;
	private static final int SERVICE_STARTER_INTERVAL_MILISEC = 1 * 1000;
	private static final int SERVICE_TASK_TIMEOUT_SEC = 10;
	private final int REQUEST_CODE = 1;

	private AlarmManager serviceStarterAlarmManager = null;
	private MyTask asyncTask = null;
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();

		// Start of timeout-autostarter for our service (watchdog)
		startServiceStarter();
		
		// Start performing service task
		serviceTask();

		Toast.makeText(this, "Service Started!", Toast.LENGTH_LONG).show();
	}
	
	private void StopPerformingServiceTask() {
		asyncTask.cancel(true);
	}
	
	private void GoToDesktop() {
        Intent homeIntent= new Intent(Intent.ACTION_MAIN);
        homeIntent.addCategory(Intent.CATEGORY_HOME);
        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(homeIntent);
	}
	
	private void LockTheScreen() {
        ComponentName localComponentName = new ComponentName(this, DeviceAdminDemo.class);

        DevicePolicyManager localDevicePolicyManager = (DevicePolicyManager)this.getSystemService(Context.DEVICE_POLICY_SERVICE );
        if (localDevicePolicyManager.isAdminActive(localComponentName))
        {
            localDevicePolicyManager.setPasswordQuality(localComponentName, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
        }
        
        // locking the device
        localDevicePolicyManager.lockNow();
	}

	@Override
	public void onDestroy() {
		// performs when user or system kills our service
		StopPerformingServiceTask();
		GoToDesktop();
		LockTheScreen();
	}
	
	private void serviceTask() {
		asyncTask = new MyTask();
		asyncTask.execute();
	}
	
	class MyTask extends AsyncTask<Void, Void, Void> {
	    @Override
	    protected Void doInBackground(Void... params) {
	      try {
	        for (;;) {
	          TimeUnit.SECONDS.sleep(SERVICE_TASK_TIMEOUT_SEC);
	          
	        	// check if performing of the task is needed
	        	if(isCancelled()) {
	        		break;
	        		}
	          
	          // Initiating of onProgressUpdate callback that has access to UI
	          publishProgress();
	        }

	      } catch (InterruptedException e) {
	        e.printStackTrace();
	      }
	      return null;
	    }

	    @Override
	    protected void onProgressUpdate(Void... progress) {
	      super.onProgressUpdate(progress);
	      Toast.makeText(getApplicationContext(), "Ooops!!! Try to kill me :)", Toast.LENGTH_LONG).show();
	    }
	  }

	// We should register our service in the AlarmManager service
	// for performing periodical starting of our service by the system
	private void startServiceStarter() {
		Intent intent = new Intent(this, ServiceStarter.class);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(this, this.REQUEST_CODE, intent, 0);

		if (pendingIntent == null) {
			Toast.makeText(this, "Some problems with creating of PendingIntent", Toast.LENGTH_LONG).show();
		} else {
			if (serviceStarterAlarmManager == null) {
				serviceStarterAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
				serviceStarterAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
				SystemClock.elapsedRealtime() + FIRST_RUN_TIMEOUT_MILISEC,
				SERVICE_STARTER_INTERVAL_MILISEC, pendingIntent);
			}
		}
	}
}

Everything here is also relatively simple.

At the start, service activates reset mechanism. If for some reason it is stopped, PendingIntent with information about our service will be created and transferred to the AlarmManager system service indicating restart timeout.

As a task, service creates a thread, which uses an infinite loop to periodically display the "Ooops !!! Try to kill me :)" message on the user’s desktop.

4.3 The service “autostarter” code (ServiceStarter.java)

"Autostarter" is presented by a standard BroadcastReceiver, in which the attempt to start the service is performed.

Receiver triggers according to timeout due to the AlarmManager service, because receiver was registered at the start of the service.

If the service is already running, then the second onCreate for it will not be called. And that is exactly what we need.

Java
public class ServiceStarter extends BroadcastReceiver {	
	@Override
	public void onReceive(Context context, Intent intent) {
		Intent serviceLauncher = new Intent(context, BackgroundService.class);
		context.startService(serviceLauncher);
	}
}

4.4 The DeviceAdmin component code (DeviceAdminComponent.java)

We need DeviceAdmin  in order to:

  • prohibit user to stop or uninstall the application;
  • have the possibility to change the password and lock the device if user attempts to disable the DeviceAdmin component.

Also note that the administrator password is hardcoded as the "12345" string.

The onDisableRequested code works out after the confirmation of the DeviceAdmin deactivation, but before the deactivation itself.

Java
public class DeviceAdminComponent extends DeviceAdminReceiver {
	
	private static final String OUR_SECURE_ADMIN_PASSWORD = "12345";

	public CharSequence onDisableRequested(Context context, Intent intent) {
		
        ComponentName localComponentName = new ComponentName(context, DeviceAdminComponent.class);

        DevicePolicyManager localDevicePolicyManager = (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE );
        if (localDevicePolicyManager.isAdminActive(localComponentName))
        {
            localDevicePolicyManager.setPasswordQuality(localComponentName, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
        }

        // resetting user password
        localDevicePolicyManager.resetPassword(OUR_SECURE_ADMIN_PASSWORD, DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);

        // locking the device
        localDevicePolicyManager.lockNow();
        
        return super.onDisableRequested(context, intent);}}

5. Results

Thus, without using ROOT-permissions, incidents, or undocumented system features, we have managed to create the application that is practically impossible to be stopped or removed without knowing the administrator password. Although in some cases you can try to do it.

After studying this technique, we once again come to the conclusion that:

  • it is almost always possible to find loopholes to circumvent any restrictions;
  • it is strongly not recommended to install applications from untrusted sources. Especially if it requires the acceptance of the DeviceAdmin policies…

And what about you? Do you know a way to create a similar system? ;)

6. Sources

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Apriorit Inc.
United States United States
ApriorIT is a software research and development company specializing in cybersecurity and data management technology engineering. We work for a broad range of clients from Fortune 500 technology leaders to small innovative startups building unique solutions.

As Apriorit offers integrated research&development services for the software projects in such areas as endpoint security, network security, data security, embedded Systems, and virtualization, we have strong kernel and driver development skills, huge system programming expertise, and are reals fans of research projects.

Our specialty is reverse engineering, we apply it for security testing and security-related projects.

A separate department of Apriorit works on large-scale business SaaS solutions, handling tasks from business analysis, data architecture design, and web development to performance optimization and DevOps.

Official site: https://www.apriorit.com
Clutch profile: https://clutch.co/profile/apriorit
This is a Organisation

33 members

Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseThe Best Interesting article about android application Pin
Member 1320708517-May-17 10:39
Member 1320708517-May-17 10:39 
QuestionThis is not good! Pin
aleantonello7-Mar-15 8:09
aleantonello7-Mar-15 8:09 
AnswerRe: This is not good! Pin
Petrov Andrey7-Mar-15 11:12
Petrov Andrey7-Mar-15 11:12 
AnswerRe: This is not good! Pin
Member 1079733925-Aug-15 4:27
Member 1079733925-Aug-15 4:27 
QuestionReally? Pin
MoPHL5-Mar-15 3:59
professionalMoPHL5-Mar-15 3:59 
AnswerRe: Really? Pin
Petrov Andrey5-Mar-15 4:06
Petrov Andrey5-Mar-15 4:06 
QuestionNexus 7 complete sludge: all my apps seem to live forever Pin
newton.saber5-Mar-15 3:53
newton.saber5-Mar-15 3:53 
AnswerRe: Nexus 7 complete sludge: all my apps seem to live forever Pin
Petrov Andrey5-Mar-15 4:10
Petrov Andrey5-Mar-15 4:10 
QuestionI am lucky, I use Windows Phone Pin
snoopy0015-Mar-15 2:28
snoopy0015-Mar-15 2:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.