【技术分享】全球知名移动间谍软件FlexiSpy的分析(part2)

http://p6.qhimg.com/t011d078d7998c1f808.png

翻译:myswsun

预估稿费:120RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿

传送门:全球知名移动间谍软件FlexiSpy的分析(part1)

0x00 前言

这是FlexiSpy分析的第二部分。反病毒的同行注意了,新的IOC和我的jeb数据库文件在本文底部。这个应用很大,因此我需要将它分割为多个部分。在主apk文件中有几个组件。我们先看下assets(注意这些zip文件是apk和dex文件)。

5002:                          data
Camera.apk:                    Zip archive data, at least v2.0 to extract
Xposed-Disabler-Recovery.zip:  Zip archive data, at least v2.0 to extract
Xposed-Installer-Recovery.zip: Zip archive data, at least v2.0 to extract
XposedBridge.jar:              Zip archive data, at least v1.0 to extract
arm64-v8a:                     directory
arm_app_process_xposed_sdk15:  ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
arm_app_process_xposed_sdk16:  ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
arm_xposedtest_sdk15:          ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
arm_xposedtest_sdk16:          ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
aud.zip:                       Zip archive data, at least v2.0 to extract
bugd.zip:                      Zip archive data, at least v2.0 to extract
busybox:                       ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, stripped
callmgr.zip:                   Zip archive data, at least v2.0 to extract
callmon.zip:                   Zip archive data, at least v2.0 to extract
dwebp:                         ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
dwebp64:                       ELF 64-bit LSB shared object, version 1 (SYSV), dynamically linked (uses shared libs), stripped
ffmpeg:                        ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
gesture_hash.zip:              Zip archive data, at least v2.0 to extract
libaac.so:                     ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libamr.so:                     ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libasound.so:                  ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libcrypto_32bit.so:            ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libflasusconfig.so:            ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libflhtcconfig.so:             ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libfllgconfig.so:              ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libflmotoconfig.so:            ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libflsamsungconfig.so:         ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libflsonyconfig.so:            ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
libfxexec.so:                  ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libfxril.so:                   ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libfxtmessages.8.so:           ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libfxwebp.so:                  ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libkma.so:                     ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libkmb.so:                     ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
liblame.so:                    ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libmp3lame.so:                 ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libsqliteX.so:                 ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
libvcap.so:                    ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
maind:                         directory
maind.zip:                     Zip archive data, at least v2.0 to extract
mixer:                         directory
panzer:                        ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
pmond.zip:                     Zip archive data, at least v2.0 to extract
psysd.zip:                     Zip archive data, at least v2.0 to extract
ticket.apk:                    Zip archive data, at least v2.0 to extract
vdaemon:                       ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
x86_app_process_xposed_sdk15:  ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
x86_app_process_xposed_sdk16:  ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
x86_xposedtest_sdk15:          ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
x86_xposedtest_sdk16:          ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
ben@bens-MacBook:~/Downloads/bin/5002_2.24.3_green.APK.out/assets/product$

0x01 方法

监控软件有3个版本。这个非常棒,因为它包含了完整的代码注释。

l  泄漏的源码版本是1.00.1。虽然有文档,但是它只有2.x版本以下的一小部分功能。

l  2.24.3 APK文件:这是编译好的代码,不包含任何注释。这比泄漏的源代码版本新。有更多功能。有混淆,且有大量的额外的Modules/assets.

l  2.25.1 APK:编译代码。没有注释。转储中最新版本。我们看出来和2.24.3的区别

有两个Windows可执行程序和一个mac可执行文件。我还没有看它们。

计划从应用的入口点开始(当用户点击图标时发生),并且检查intent接受器。


0x02 AndroidManifest.xml信息

在这有一些有趣的东西。首先包的名字是com.android.systemupdate。这个可能是命名欺骗用户,认为这个应用是一个官方的安卓应用。

<?xml version="1.0" encoding="utf-8"?>
<manifest android:versionCode="1446" android:versionName="2.24.3" package="com.android.systemupdate" platformBuildVersionCode="15" platformBuildVersionName="4.0.4-1406430" xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />

大量的权限覆盖了对于侵犯隐私需要的一切。下面是全部列表。

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.RESTART_PACKAGES" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_SMS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
    <uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="com.wefeelsecure.feelsecure.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.sec.android.provider.logsprovider.permission.READ_LOGS" />
    <uses-permission android:name="com.sec.android.provider.logsprovider.permission.WRITE_LOGS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.BATTERY_STATS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
    <uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.BLUETOOTH" />

0x03 入口点onCreate

用户安装应用程序时运行的第一个activity是com.phoenix.client.PrerequisitesSetupActivity。让我们看下它的功能。

对于大部分的android activities,onCreate方法通常首先运行。在一个GUI初始化后,应用检查手机是否root。

public void onCreate(Bundle arg6) {
        super.onCreate(arg6);  // ignore
        this.setContentView(2130903047);  // ignore
        StrictMode.setThreadPolicy(new StrictMode$ThreadPolicy$Builder().permitAll().build());
        this.o_Button = this.findViewById(2131165209);  // ignore
        this.o_Button2 = this.findViewById(2131165210);  // ignore
        this.o_TextView = this.findViewById(2131165207);  // ignore
        this.k = this.findViewById(2131165208);  // ignore
        this.k.setVisibility(4);  // ignore
        this.o_TextView.setText(String.format(this.getString(2130968605), cz.m_superUserCheck(((Context)this)), this.getString(2130968601)));  // can return SuperSU or Superuser

0x04 root检查 cz.m_superUserCheck

实际的root检查如下。检查是否安装了4个root包中的任何一个。来表明设备是否被root。注意这是代码库中众多root/package检查中的第一个。

public static SuBinaryProvider d(Context arg1) {
        SuBinaryProvider v0;
        if(e.m_LooksForInstalledPackages(arg1, "com.noshufou.android.su")) {
            v0 = SuBinaryProvider.NOSHUFOU_SUPERUSER;
        }
        else if(e.m_LooksForInstalledPackages(arg1, "eu.chainfire.supersu")) {
            v0 = SuBinaryProvider.CHAINFIRE_SUPERSU;
        }
        else if(e.m_LooksForInstalledPackages(arg1, "com.m0narx.su")) {
            v0 = SuBinaryProvider.M0NARX_SUPERUSER;
        }
        else if(e.m_LooksForInstalledPackages(arg1, "com.koushikdutta.superuser")) {
            v0 = SuBinaryProvider.KOUSHIKDUTTA_SUPERUSER;
        }
        else {
            v0 = SuBinaryProvider.CHAINFIRE_SUPERSU;
        }
 
        return v0;

根据是否检测到root包,设置值为SuperUser或者SuperSU。

public static String m_superUserCheck(Context arg3) {
        SuBinaryProvider SuCheck = cz.ChecksforSuPackages(arg3);  // checks for 4 packages
        String str_returnValSuperSu = "SuperSU";  // default return val
        if(SuCheck == SuBinaryProvider.CHAINFIRE_SUPERSU) {
            str_returnValSuperSu = "SuperSU";
        }
        else {
            if(SuCheck != SuBinaryProvider.NOSHUFOU_SUPERUSER && SuCheck != SuBinaryProvider.KOUSHIKDUTTA_SUPERUSER && SuCheck != SuBinaryProvider.M0NARX_SUPERUSER) {
                return str_returnValSuperSu;
            }
 
            str_returnValSuperSu = "Superuser";
        }
 
        return str_returnValSuperSu;  // can return SuperSU or Superuser


0x05 回到onCreate

在root检查后,应用检测SD卡中的一个文件。这个可能是检查应用程序是否之前安装过。根据ac.txt文件是否存在,两种执行将发生:一个启动AutoInstallerActivity,另一个启动CoreService。

 this.o_TextView.setText(String.format(this.getString(2130968605), cz.m_superUserCheck(((Context)this)), this.getString(2130968601)));  // can return SuperSU or Superuser
        this.o_Button.setOnClickListener(new cp(this));
        this.o_Button2.setOnClickListener(new cq(this));
        if(cz.m_acTextCHeck()) {  // checks for ac.txt value on SDcard
            Intent o_intentObj = new Intent(((Context)this), AutoInstallerActivity.class);  // if the txt file IS present
            o_intentObj.setFlags(335544320);
            this.startActivity(o_intentObj);  // starts theAutoInstallerActivity class
            this.finish();
        }
        else {
            this.g = new SetupFlagsManager(o.a(this.getApplicationContext()));  // if the txt file is NOT present
            this.f = ak.a(((Context)this));
            if(this.c == null) {
                this.bindService(new Intent(((Context)this), CoreService.class), this.l, 1);
            }
            else {
                this.b();
            }
        }

不管执行什么路径,coreService都会启动。AutoInstallerActivity有一些安装步骤,写一些日志文件,创建一些自定义安装对象和启动CoreService类。此时应用等待用户交互。细节如下。

0x06 com.phoenix.client.receiver.CommonReceiver

Receivers监听android上来的intents。当屏幕解锁,手机重启或者新的SMS消息到达时代码得到响应。

<intent-filter android:priority="2147483647">
                <action android:name="android.intent.action.USER_PRESENT" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>


0x07 接收SMS

当接收SMS被检测到。应用在SMS消息中查找指定值<*#。这好像是发送给受害者的一个指定的命令控制值。

while(o_Iterator.hasNext()) {
                    str_intentAction = o_Iterator.next().getMessageBody();
                    if(str_intentAction != null && (str_intentAction.trim().startsWith("<*#"))) {  // look for a "special value" in sms
                        i_specialCommandFound = 1;
                        continue;
                    }
 
                    i_specialCommandFound = 0;

在泄漏的源代码文件中的交叉引用中1.00.1/_build/source/daemon_remote_command_manager/src/com/vvt/remotecommandmanager/SmsCommandPattern.java表明SMS消息中的这个<**是用于远程命令。1.00.1版本的命令如下。

//Monitor call
    public static final String ENABLE_SPY_CALL = "<*#9>";
    public static final String ENABLE_SPY_CALL_WITH_MONITOR = "<*#10>";
    public static final String ADD_MONITORS = "<*#160>";
    public static final String RESET_MONITORS = "<*#163>";
    public static final String CLEAR_MONITORS = "<*#161>";
    public static final String QUERY_MONITORS = "<*#162>";
    public static final String ADD_CIS_NUMBERS = "<*#130>";
    public static final String RESET_CIS_NUMBERS = "<*#131>";
    public static final String CLEAR_CIS_NUMBERS = "<*#132>";
    public static final String QUERY_CIS_NUMBERS = "<*#133>";
    
    //Miscellaneous
    public static final String REQUEST_HEART_BEAT = "<*#2>";
    public static final String REQUEST_EVENTS = "<*#64>";
    public static final String SET_SETTINGS = "<*#92>";
    public static final String ENABLE_SIM_CHANGE = "<*#56>";
    public static final String ENABLE_CAPTURE = "<*#60>";
    public static final String SET_VISIBILITY = "<*#14214>";
    public static final String ENABLE_COMMUNICATION_RESTRICTIONS = "<*#204>";
    
    //Activation and installation
    public static final String ACTIVATE_WITH_ACTIVATION_CODE_AND_URL = "<*#14140>";
    public static final String ACTIVATE_WITH_URL = "<*#14141>";
    public static final String DEACTIVATE = "<*#14142>";
    public static final String SET_ACTIVATION_PHONE_NUMBER = "<*#14258>";
    public static final String SYNC_UPDATE_CONFIGURATION = "<*#300>";
    public static final String UNINSTALL_APPLICATION = "<*#200>";
    public static final String SYNC_SOFTWARE_UPDATE = "<*#306>";
    public static final String ENABLE_PRODUCT = "<*#14000>";
    public static final String REQUEST_MOBILE_NUMBER = "<*#199>";
    
    //Address Book
    public static final String REQUEST_ADDRESSBOOK = "<*#120>";
    public static final String SET_ADDRESSBOOK_FOR_APPROVAL = "<*#121>";
    public static final String SET_ADDRESSBOOK_MANAGEMENT = "<*#122>";
    public static final String SYNC_ADDRESSBOOK = "<*#301>";
    
    //Media
//  public static final String UPLOAD_ACTUAL_MEDIA = "";
//  public static final String DELETE_ACTUAL_MEDIA = "";
    public static final String ON_DEMAND_RECORD = "<*#84>";
    
    //GPS
    public static final String ENABLE_LOCATION = "<*#52>";
    public static final String UPDATE_GPS_INTERVAL = "<*#53>";
    public static final String ON_DEMAND_LOCATION = "<*#101>";
    
    //Communication
    public static final String SPOOF_SMS = "<*#85>";
    public static final String SPOOF_CALL = "<*#86>";
    
    //Call watch
    public static final String ENABLE_WATCH_NOTIFICATION = "<*#49>";
    public static final String SET_WATCH_FLAGS = "<*#50>";
    public static final String ADD_WATCH_NUMBER = "<*#45>";
    public static final String RESET_WATCH_NUMBER = "<*#46>";
    public static final String CLEAR_WATCH_NUMBER = "<*#47>";
    public static final String QUERY_WATCH_NUMBER = "<*#48>";
    
    //Keyword list
    public static final String ADD_KEYWORD = "<*#73>";
    public static final String RESET_KEYWORD = "<*#74>";
    public static final String CLEAR_KEYWORD = "<*#75>";
    public static final String QUERY_KEYWORD = "<*#76>";
    
    //URL list
    public static final String ADD_URL = "<*#396>";
    public static final String RESET_URL = "<*#397>";
    public static final String CLEAR_URL = "<*#398>";
    public static final String QUERY_URL = "<*#399>";
    
    //Security and protection
    public static final String SET_PANIC_MODE = "<*#31>";
    public static final String SET_WIPE_OUT = "<*#201>";
    public static final String SET_LOCK_DEVICE = "<*#202>";
    public static final String SET_UNLOCK_DEVICE = "<*#203>";
    public static final String ADD_EMERGENCY_NUMBER = "<*#164>";
    public static final String RESET_EMERGENCY_NUMBER = "<*#165>";
    public static final String QUERY_EMERGENCY_NUMBER = "<*#167>";
    public static final String CLEAR_EMERGENCY_NUMBER = "<*#166>";
    
    //Troubleshoot
    public static final String REQUEST_SETTINGS = "<*#67>";
    public static final String REQUEST_DIAGNOSTIC = "<*#62>";
    public static final String REQUEST_START_UP_TIME = "<*#5>";
    public static final String RESTART_DEVICE = "<*#147>";
    public static final String RETRIEVE_RUNNING_PROCESSES = "<*#14852>";
    public static final String TERMINATE_RUNNING_PROCESSES = "<*#14853>";
    public static final String SET_DEBUG_MODE = "<*#170>";
    public static final String REQUEST_CURRENT_URL = "<*#14143>";
    public static final String ENABLE_CONFERENCING_DEBUGING = "<*#12>";
    public static final String INTERCEPTION_TONE = "<*#21>";
    public static final String RESET_LOG_DURATION = "<*#65>";
    public static final String FORCE_APN_DISCOVERY = "<*#71>";
    
    //Notification Numbers
    public static final String ADD_NOTIFICATION_NUMBERS = "<*#171>";
    public static final String RESET_NOTIFICATION_NUMBERS = "<*#172>";
    public static final String CLEAR_NOTIFICATION_NUMBERS = "<*#173>";
    public static final String QUERY_NOTIFICATION_NUMBERS = "<*#174>";
    
    //Home numbers
    public static final String ADD_HOMES = "<*#150>";
    public static final String RESET_HOMES = "<*#151>";
    public static final String CLEAR_HOMES = "<*#152>";
    public static final String QUERY_HOMES = "<*#153>";
    
    //Sync
    public static final String SYNC_COMMUNICATION_DIRECTIVES = "<*#302>";
    public static final String SYNC_TIME = "<*#303>";
    public static final String SYNC_PROCESS_PROFILE = "<*#304>";
    public static final String SYNC_INCOMPATIBLE_APPLICATION_DEFINITION = "<*#307>";

在2.x版本中的命令变了。发送给受害者设备的2.x的远程命令的列表如下。

RemoteFunction.ACTIVATE_PRODUCT = new RemoteFunction("ACTIVATE_PRODUCT", 0);
        RemoteFunction.DEACTIVATE_PRODUCT = new RemoteFunction("DEACTIVATE_PRODUCT", 1);
        RemoteFunction.IS_PRODUCT_ACTIVATED = new RemoteFunction("IS_PRODUCT_ACTIVATED", 2);
        RemoteFunction.UNINSTALL_PRODUCT = new RemoteFunction("UNINSTALL_PRODUCT", 3);
        RemoteFunction.GET_LICENSE_STATUS = new RemoteFunction("GET_LICENSE_STATUS", 4);
        RemoteFunction.GET_ACTIVATION_CODE = new RemoteFunction("GET_ACTIVATION_CODE", 5);
        RemoteFunction.AUTO_ACTIVATE_PRODUCT = new RemoteFunction("AUTO_ACTIVATE_PRODUCT", 6);
        RemoteFunction.MANAGE_COMMON_DATA = new RemoteFunction("MANAGE_COMMON_DATA", 7);
        RemoteFunction.ENABLE_EVENT_DELIVERY = new RemoteFunction("ENABLE_EVENT_DELIVERY", 8);
        RemoteFunction.SET_EVENT_MAX_NUMBER = new RemoteFunction("SET_EVENT_MAX_NUMBER", 9);
        RemoteFunction.SET_EVENT_TIMER = new RemoteFunction("SET_EVENT_TIMER", 10);
        RemoteFunction.SET_DELIVERY_METHOD = new RemoteFunction("SET_DELIVERY_METHOD", 11);
        RemoteFunction.ADD_URL = new RemoteFunction("ADD_URL", 12);
        RemoteFunction.RESET_URL = new RemoteFunction("RESET_URL", 13);
        RemoteFunction.CLEAR_URL = new RemoteFunction("CLEAR_URL", 14);
        RemoteFunction.QUERY_URL = new RemoteFunction("QUERY_URL", 15);
        RemoteFunction.ENABLE_EVENT_CAPTURE = new RemoteFunction("ENABLE_EVENT_CAPTURE", 16);
        RemoteFunction.ENABLE_CAPTURE_CALL = new RemoteFunction("ENABLE_CAPTURE_CALL", 17);
        RemoteFunction.ENABLE_CAPTURE_SMS = new RemoteFunction("ENABLE_CAPTURE_SMS", 18);
        RemoteFunction.ENABLE_CAPTURE_EMAIL = new RemoteFunction("ENABLE_CAPTURE_EMAIL", 19);
        RemoteFunction.ENABLE_CAPTURE_MMS = new RemoteFunction("ENABLE_CAPTURE_MMS", 20);
        RemoteFunction.ENABLE_CAPTURE_IM = new RemoteFunction("ENABLE_CAPTURE_IM", 21);
        RemoteFunction.ENABLE_CAPTURE_IMAGE = new RemoteFunction("ENABLE_CAPTURE_IMAGE", 22);
        RemoteFunction.ENABLE_CAPTURE_AUDIO = new RemoteFunction("ENABLE_CAPTURE_AUDIO", 23);
        RemoteFunction.ENABLE_CAPTURE_VIDEO = new RemoteFunction("ENABLE_CAPTURE_VIDEO", 24);
        RemoteFunction.ENABLE_CAPTURE_WALLPAPER = new RemoteFunction("ENABLE_CAPTURE_WALLPAPER", 25);
        RemoteFunction.ENABLE_CAPTURE_APP = new RemoteFunction("ENABLE_CAPTURE_APP", 26);
        RemoteFunction.ENABLE_CAPTURE_URL = new RemoteFunction("ENABLE_CAPTURE_URL", 27);
        RemoteFunction.ENABLE_CAPTURE_CALL_RECORD = new RemoteFunction("ENABLE_CAPTURE_CALL_RECORD", 28);
        RemoteFunction.ENABLE_CAPTURE_CALENDAR = new RemoteFunction("ENABLE_CAPTURE_CALENDAR", 29);
        RemoteFunction.ENABLE_CAPTURE_PASSWORD = new RemoteFunction("ENABLE_CAPTURE_PASSWORD", 30);
        RemoteFunction.ENABLE_TEMPORAL_CONTROL_RECORD_AMBIENT = new RemoteFunction("ENABLE_TEMPORAL_CONTROL_RECORD_AMBIENT", 31);
        RemoteFunction.ENABLE_CAPTURE_VOIP = new RemoteFunction("ENABLE_CAPTURE_VOIP", 32);
        RemoteFunction.ENABLE_VOIP_CALL_RECORDING = new RemoteFunction("ENABLE_VOIP_CALL_RECORDING", 33);
        RemoteFunction.ENABLE_CAPTURE_CONTACT = new RemoteFunction("ENABLE_CAPTURE_CONTACT", 34);
        RemoteFunction.SET_IM_ATTACHMENT_LIMIT_SIZE = new RemoteFunction("SET_IM_ATTACHMENT_LIMIT_SIZE", 35);
        RemoteFunction.ENABLE_CAPTURE_GPS = new RemoteFunction("ENABLE_CAPTURE_GPS", 36);
        RemoteFunction.SET_GPS_TIME_INTERVAL = new RemoteFunction("SET_GPS_TIME_INTERVAL", 37);
        RemoteFunction.GET_GPS_ON_DEMAND = new RemoteFunction("GET_GPS_ON_DEMAND", 38);
        RemoteFunction.ENABLE_SPY_CALL = new RemoteFunction("ENABLE_SPY_CALL", 39);
        RemoteFunction.ENABLE_WATCH_NOTIFICATION = new RemoteFunction("ENABLE_WATCH_NOTIFICATION", 40);
        RemoteFunction.SET_WATCH_FLAG = new RemoteFunction("SET_WATCH_FLAG", 41);
        RemoteFunction.GET_CONNECTION_HISTORY = new RemoteFunction("GET_CONNECTION_HISTORY", 42);
        RemoteFunction.GET_CONFIGURATION = new RemoteFunction("GET_CONFIGURATION", 43);
        RemoteFunction.GET_SETTINGS = new RemoteFunction("GET_SETTINGS", 44);
        RemoteFunction.GET_DIAGNOSTICS = new RemoteFunction("GET_DIAGNOSTICS", 45);
        RemoteFunction.GET_EVENT_COUNT = new RemoteFunction("GET_EVENT_COUNT", 46);
        RemoteFunction.SEND_INSTALLED_APPLICATIONS = new RemoteFunction("SEND_INSTALLED_APPLICATIONS", 47);
        RemoteFunction.REQUEST_CALENDER = new RemoteFunction("REQUEST_CALENDER", 48);
        RemoteFunction.SET_SUPERUSER_VISIBILITY = new RemoteFunction("SET_SUPERUSER_VISIBILITY", 49);
        RemoteFunction.SET_LOCK_PHONE_SCREEN = new RemoteFunction("SET_LOCK_PHONE_SCREEN", 50);
        RemoteFunction.REQUEST_DEVICE_SETTINGS = new RemoteFunction("REQUEST_DEVICE_SETTINGS", 51);
        RemoteFunction.SET_UPDATE_AVAILABLE_SILENT_MODE = new RemoteFunction("SET_UPDATE_AVAILABLE_SILENT_MODE", 52);
        RemoteFunction.DELETE_DATABASE = new RemoteFunction("DELETE_DATABASE", 53);
        RemoteFunction.RESTART_DEVICE = new RemoteFunction("RESTART_DEVICE", 54);
        RemoteFunction.REQUEST_HISTORICAL_EVENTS = new RemoteFunction("REQUEST_HISTORICAL_EVENTS", 55);
        RemoteFunction.REQUEST_TEMPORAL_APPLICATION_CONTROL = new RemoteFunction("REQUEST_TEMPORAL_APPLICATION_CONTROL", 56);
        RemoteFunction.SET_DOWNLOAD_BINARY_AND_UPDATE_SILENT_MODE = new RemoteFunction("SET_DOWNLOAD_BINARY_AND_UPDATE_SILENT_MODE", 57);
        RemoteFunction.SEND_HEARTBEAT = new RemoteFunction("SEND_HEARTBEAT", 58);
        RemoteFunction.SEND_MOBILE_NUMBER = new RemoteFunction("SEND_MOBILE_NUMBER", 59);
        RemoteFunction.SEND_SETTINGS_EVENT = new RemoteFunction("SEND_SETTINGS_EVENT", 60);
        RemoteFunction.SEND_EVENTS = new RemoteFunction("SEND_EVENTS", 61);
        RemoteFunction.REQUEST_CONFIGURATION = new RemoteFunction("REQUEST_CONFIGURATION", 62);
        RemoteFunction.SEND_CURRENT_URL = new RemoteFunction("SEND_CURRENT_URL", 63);
        RemoteFunction.SEND_BOOKMARKS = new RemoteFunction("SEND_BOOKMARKS", 64);
        RemoteFunction.DEBUG_SWITCH_CONTAINER = new RemoteFunction("DEBUG_SWITCH_CONTAINER", 65);
        RemoteFunction.DEBUG_HIDE_APP = new RemoteFunction("DEBUG_HIDE_APP", 66);
        RemoteFunction.DEBUG_UNHIDE_APP = new RemoteFunction("DEBUG_UNHIDE_APP", 67);
        RemoteFunction.DEBUG_IS_DAEMON = new RemoteFunction("DEBUG_IS_DAEMON", 68);
        RemoteFunction.DEBUG_IS_FULL_MODE = new RemoteFunction("DEBUG_IS_FULL_MODE", 69);
        RemoteFunction.DEBUG_GET_CONFIG_ID = new RemoteFunction("DEBUG_GET_CONFIG_ID", 70);
        RemoteFunction.DEBUG_GET_ACTUAL_CONFIG_ID = new RemoteFunction("DEBUG_GET_ACTUAL_CONFIG_ID", 71);
        RemoteFunction.DEBUG_GET_VERSION_CODE = new RemoteFunction("DEBUG_GET_VERSION_CODE", 72);
        RemoteFunction.DEBUG_SEND_TEST_SMS = new RemoteFunction("DEBUG_SEND_TEST_SMS", 73);
        RemoteFunction.DEBUG_CLOSE_APP = new RemoteFunction("DEBUG_CLOSE_APP", 74);
        RemoteFunction.DEBUG_BRING_UI_TO_HOME_SCREEN = new RemoteFunction("DEBUG_BRING_UI_TO_HOME_SCREEN", 75);
        RemoteFunction.DEBUG_SET_APPLICATION_MODE = new RemoteFunction("DEBUG_SET_APPLICATION_MODE", 76);
        RemoteFunction.DEBUG_GET_APPLICATION_MODE = new RemoteFunction("DEBUG_GET_APPLICATION_MODE", 77);
        RemoteFunction.DEBUG_RESTART_DEVICE = new RemoteFunction("DEBUG_RESTART_DEVICE", 78);
        RemoteFunction.DEBUG_IS_APPENGIN_INIT_COMPLETE = new RemoteFunction("DEBUG_IS_APPENGIN_INIT_COMPLETE", 79);
        RemoteFunction.DEBUG_PRODUCT_VERSION = new RemoteFunction("DEBUG_PRODUCT_VERSION", 80);
        RemoteFunction.DEBUG_IS_CALLRECORDING_SUPPORTED = new RemoteFunction("DEBUG_IS_CALLRECORDING_SUPPORTED", 81);
        RemoteFunction.DEBUG_IS_RESUME_ON_DEMAND_AMBIENT_RECORDING = new RemoteFunction("DEBUG_IS_RESUME_ON_DEMAND_AMBIENT_RECORDING", 82);
        RemoteFunction.SET_MODE_ADDRESS_BOOK = new RemoteFunction("SET_MODE_ADDRESS_BOOK", 83);
        RemoteFunction.SEND_ADDRESS_BOOK = new RemoteFunction("SEND_ADDRESS_BOOK", 84);
        RemoteFunction.REQUEST_BATTERY_INFO = new RemoteFunction("REQUEST_BATTERY_INFO", 85);
        RemoteFunction.REQUEST_MEDIA_HISTORICAL = new RemoteFunction("REQUEST_MEDIA_HISTORICAL", 86);
        RemoteFunction.UPLOAD_ACTUAL_MEDIA = new RemoteFunction("UPLOAD_ACTUAL_MEDIA", 87);
        RemoteFunction.DELETE_ACTUAL_MEDIA = new RemoteFunction("DELETE_ACTUAL_MEDIA", 88);
        RemoteFunction.ON_DEMAND_AMBIENT_RECORD = new RemoteFunction("ON_DEMAND_AMBIENT_RECORD", 89);
        RemoteFunction.ON_DEMAND_IMAGE_CAPTURE = new RemoteFunction("ON_DEMAND_IMAGE_CAPTURE", 90);
        RemoteFunction.ENABLE_CALL_RECORDING = new RemoteFunction("ENABLE_CALL_RECORDING", 91);
        RemoteFunction.SET_CALL_RECORDING_WATCH_FLAG = new RemoteFunction("SET_CALL_RECORDING_WATCH_FLAG", 92);
        RemoteFunction.SET_CALL_RECORDING_AUDIO_SOURCE = new RemoteFunction("SET_CALL_RECORDING_AUDIO_SOURCE", 93);
        RemoteFunction.ENABLE_COMMUNICATION_RESTRICTION = new RemoteFunction("ENABLE_COMMUNICATION_RESTRICTION", 94);
        RemoteFunction.ENABLE_APP_PROFILE = new RemoteFunction("ENABLE_APP_PROFILE", 95);
        RemoteFunction.ENABLE_URL_PROFILE = new RemoteFunction("ENABLE_URL_PROFILE", 96);
        RemoteFunction.SPOOF_SMS = new RemoteFunction("SPOOF_SMS", 97);
        RemoteFunction.SET_PANIC_MODE = new RemoteFunction("SET_PANIC_MODE", 98);
        RemoteFunction.START_PANIC = new RemoteFunction("START_PANIC", 99);
        RemoteFunction.STOP_PANIC = new RemoteFunction("STOP_PANIC", 100);
        RemoteFunction.GET_PANIC_MODE = new RemoteFunction("GET_PANIC_MODE", 101);
        RemoteFunction.PANIC_IMAGE_CAPTURE = new RemoteFunction("PANIC_IMAGE_CAPTURE", 102);
        RemoteFunction.IS_PANIC_ACTIVE = new RemoteFunction("IS_PANIC_ACTIVE", 103);
        RemoteFunction.ENABLE_ALERT = new RemoteFunction("ENABLE_ALERT", 104);
        RemoteFunction.SET_LOCK_DEVICE = new RemoteFunction("SET_LOCK_DEVICE", 105);
        RemoteFunction.SET_UNLOCK_DEVICE = new RemoteFunction("SET_UNLOCK_DEVICE", 106);
        RemoteFunction.SET_WIPE = new RemoteFunction("SET_WIPE", 107);
        RemoteFunction.SYNC_TEMPORAL_APPLICATION_CONTROL = new RemoteFunction("SYNC_TEMPORAL_APPLICATION_CONTROL", 108);
        RemoteFunction.a = new RemoteFunction[]{RemoteFu

0x08 如果用户正在使用设备

监控软件监听各种intent表明用户在使用手机:如果屏幕解锁,设备开机等。

label_65:  // this is if NO sms is detected
                if((str_intentAction.equals("android.intent.action.BOOT_COMPLETED")) || (str_intentAction.equals("android.intent.action.QUICKBOOT_POWERON")) || (str_intentAction.equals("com.htc.intent.action.QUICKBOOT_POWERON"))) {
                    com.fx.daemon.b.m_relatedToShellCmds(o.m_getDataPath(arg6), "fx.log");
                    StrictMode.setThreadPolicy(new StrictMode$ThreadPolicy$Builder().permitNetwork().build());
                    if(CommonReceiver.c()) {
                        return;
                    }
 
                    if(!CommonReceiver.f_bool_maindZip()) {
                        return;
                    }
 
                    AppStartUpHandler.a(dataPath, AppStartUpHandler$AppStartUpMethod.BOOT_COMPLETED);
                    ak.m_generatesSameObj(arg6);
                    ak.b(arg6);
                    return;
                }

第一个条件

在接收到intent后,我们看到if语句

   if(CommonReceiver.b_returnTrueIfDebugMode()) {
                        return;
                    }

代码只检查是否有DEBUG_IS_FULL_MODE,命令将发送给受害者设备。

第二个条件

第二个if语句如下。它执行另一个系列root检查和检查maind.zip文件是否存在。

  if(!CommonReceiver.RootAndMainZipCheck()) {  // if not rooted and a zip doesnt exist exit
                        return;
                    }
F_bool_maindZip方法与位于/assets/production/文件夹中的maind.zip有关。
  private static boolean RootAndMainZipCheck() {
        boolean returnVal = true;
        String str_maindZipPath = o.str_FilePathGetter(b.str_dataMiscAdn, "maind.zip");
        if((ShellUtil.m_bool_MultipleRootcheck()) && (ShellUtil.m_ChecksForFIle(str_maindZipPath))) {
            returnVal = false;
        }
 
        return returnVal;  // return true if rooted AND maind.zip is found
    }

这个方法执行一系列root检查。它查看设备的Build Tags值是否存在test-keys,检查SuperUser.APK应用,su二进制的位置,环境路径检查和尝试调用一个shell。代码如下:

public static boolean m_bool_Rootcheck() {
        boolean bool_returnVal = false;
        if(ShellUtil.bool_debug) {
            Log.v("ShellUtil", "isDeviceRooted # START ...");
        }
 
        String str_buildPropTags = Build.TAGS;
        boolean str_TestKeys = str_buildPropTags == null || !str_buildPropTags.contains("test-keys") ? false : true;
        if(ShellUtil.bool_debug) {
            Log.v("ShellUtil", "checkRootMethod1 # isDeviceRooted ? : " + str_TestKeys);
        }
 
        if((str_TestKeys) || (ShellUtil.f_bool_checksForSUperSuAPK()) || (ShellUtil.m_bool_SuCheck()) || (ShellUtil.m_boolEnvPathCheck()) || (ShellUtil.m_boolTryToExecShell())) {
            bool_returnVal = true;
        }
 
        if(ShellUtil.bool_debug) {
            Log.v("ShellUtil", "isDeviceRooted # isDeviceRooted ? : " + bool_returnVal);
        }
 
        if(ShellUtil.bool_debug) {
            Log.v("ShellUtil", "isDeviceRooted # EXIT ...");
        }
 
        return bool_returnVal

通过下面的方法执行maind.zip检查

public static boolean m_ChecksForFIle(String arg7) {
        boolean b_returnVal = true;
        try {
            c_RelatedToFxExecLib v2 = c_RelatedToFxExecLib.b();
            String v3 = v2.a(String.format("%s "%s"", "/system/bin/ls", arg7));
            v2.d();
            if(v3.contains("No such file or directory")) {
                return false;
            }
        }
        catch(CannotGetRootShellException v0_1) {
            b_returnVal = new File(arg7).exists();
        }
 
        return b_returnVal;

回到reveiver

在第二个if语句后有如下的代码。

   AppStartUpHandler.a(dataPath, AppStartUpHandler$AppStartUpMethod.BOOT_COMPLETED);
        ak.m_generatesSameObj(arg6);
        ak.startCoreService(arg6);  // starts the "engine"
        return;

非常简单。Ak.startCoreService(arg6)方法只再次启动coreService。记住这是从文章开头的onCreate方法开始的。

0x09 下集预告

下一步,我将看下CoreService和其他的intent receiver com.vvt.callhandler.phonestate.OutgoingCallReceiver,其监听去电。

0x0A 新的IOCs

对于AV行业来说,在VirusTotal中可以查找到更多的IOC。

Sha1 文件名:

b1ea0ccf834e4916aee1d178a71aba869ac3b36e libfxexec.so This is actually in the 1.00.1 source hehe ?

174b285867ae4f3450af59e1b63546a2d8ae0886 maind.zip

0x0B Jeb数据库文件

如果想就纠正任何错误,在这里


传送门:全球知名移动间谍软件FlexiSpy的分析(part1)


(完)