前段时间心血来潮,突然想研究一下dns检测是什么实现的,于是拿wifi管家开刀了,下面是分析结果:
首先入口函数:
protected boolean arQ() {
String v0_2;
String v4_1;
int v12 = 2;
int v11 = 3;
int v4 = ((int)(this.fNS / 2));
int v5 = new n(ai.fNh).a("DnsLocalDetecter", PiSessionManagerUD.amB().kH());
boolean v0 = v5 == 0 ? true : false;
boolean v3 = this.mCurrentSessionItem == null || this.mCurrentSessionItem.fOA == 4098 || this.mCurrentSessionItem.fOA == 4100 ? false : true;
if((v0) && (v3)) {
String v5_1 = "http://tools.3g.qq.com/wifi/ssl";
String v6 = "baidu.com";
String v3_1 = "http://m.taobao.com";
String v7 = "https://m.taobao.com";
a v8 = this.av(v5_1, v4);
a v9 = this.av(v3_1, v4);
try {
v4_1 = URLEncoder.encode(v5_1, "UTF-8");
v0_2 = URLEncoder.encode(v3_1, "UTF-8");
}
catch(Exception v0_1) {
v0_2 = v3_1;
v4_1 = v5_1;
}
if((TextUtils.isEmpty(((CharSequence)v4_1))) || (TextUtils.isEmpty(v4_1.toLowerCase()))) {
v4_1 = v5_1;
}
if((TextUtils.isEmpty(((CharSequence)v0_2))) || (TextUtils.isEmpty(v0_2.toLowerCase()))) {
v0_2 = v3_1;
}
if(!v8.fNY && !TextUtils.isEmpty(v8.bVW) && ((v8.bVW.toLowerCase().contains(v4_1.toLowerCase())) || (v8.bVW.toLowerCase().contains(((CharSequence)v5_1))))) {
this.fNV = "Redirect baidu RedirectUrl = " + v8.bVW + ", taobao RedirectUrl = " + v9.bVW;
this.bc(v12, 0);
return 1;
}
if(!v8.fNY && !TextUtils.isEmpty(v8.bVW) && !v8.bVW.toLowerCase().contains(((CharSequence)v6))) {
this.fNV = "baidu: " + v8.bVW;
this.bc(v11, v11);
return 1;
}
if(!v9.fNY && !TextUtils.isEmpty(v9.bVW) && ((v9.bVW.toLowerCase().contains(v0_2.toLowerCase())) || (v9.bVW.toLowerCase().contains(((CharSequence)v3_1))))) {
this.fNV = "Redirect baidu RedirectUrl = " + v8.bVW + ", taobao RedirectUrl = " + v9.bVW;
this.bc(v12, 0);
return 1;
}
if(!v9.fNY && !TextUtils.isEmpty(v9.bVW) && !v9.bVW.toLowerCase().startsWith(v3_1) && !v9.bVW.toLowerCase().startsWith(v7)) {
this.fNV = "taobao: " + v9.bVW;
this.bc(v11, v11);
return 1;
}
if(!v8.fNY && !v9.fNY && !TextUtils.isEmpty(v8.bVW) && !TextUtils.isEmpty(v9.bVW) && (TextUtils.equals(v8.bVW.toLowerCase(), v9.bVW.toLowerCase()))) {
this.fNV = "baidu and taobao has the same redirectUrl, url = " + v9.bVW;
this.bc(v11, v11);
return 1;
}
this.fNV = "safe";
this.bc(v12, 0);
}
else {
this.fNV = "isNetAvalible = " + v0 + ", isConnected = " + v3 + ", retCode = " + v5;
this.bc(v12, 0);
}
return 1;
}
可以大概看到主要拿了两个网址作为检测的依据,第一个是http://tools.3g.qq.com/wifi/ssl,这个网址是腾讯自己的,会返回301响应,而且会重定向到baidu.com,另一个是https://m.taobao.com,这个会返回200的响应,然后就拿这两个Url分别进行请求,主要函数是this.av,下面看一下这个函数:
private a av(String arg7, int arg8) {
HttpURLConnection v2_4;
HttpURLConnection v3;
String v1 = null;
a v0 = new a(this);
v0.fNX = arg7;
v0.bVW = v1;
InputStream v2 = null;
try {
v3 = this.aw(arg7, arg8);
if(v3 != null) {
goto label_15;
}
}
catch(Throwable v0_1) {
v2 = ((InputStream)v1);
v3 = ((HttpURLConnection)v1);
goto label_85;
}
catch(Exception v2_1) {
v2 = ((InputStream)v1);
v3 = ((HttpURLConnection)v1);
goto label_74;
}
catch(IOException v2_2) {
v2 = ((InputStream)v1);
v3 = ((HttpURLConnection)v1);
goto label_62;
}
catch(SocketTimeoutException v2_3) {
v2_4 = ((HttpURLConnection)v1);
goto label_50;
}
try {
v0.fNY = true;
if(0 != 0) {
goto label_11;
}
goto label_12;
}
catch(Exception v2_1) {
goto label_102;
}
catch(IOException v2_2) {
goto label_107;
}
catch(SocketTimeoutException v2_3) {
goto label_115;
}
catch(Throwable v0_1) {
goto label_93;
}
try {
label_11:
v2.close();
label_12:
if(v3 == null) {
return v0;
}
v3.disconnect();
}
catch(IOException v1_1) {
}
return v0;
try {
label_15:
int v4 = v3.getResponseCode();
v2 = v3.getInputStream();
if(v4 != 200) {
goto label_27;
}
}
catch(Throwable v0_1) {
label_93:
v2 = ((InputStream)v1);
goto label_85;
}
catch(Exception v2_1) {
label_102:
v2 = ((InputStream)v1);
goto label_74;
}
catch(IOException v2_2) {
label_107:
v2 = ((InputStream)v1);
goto label_62;
}
catch(SocketTimeoutException v2_3) {
label_115:
v2_4 = v3;
goto label_50;
}
try {
v0.bVW = arg7;
if(v2 != null) {
goto label_21;
}
goto label_22;
}
catch(Exception v1_2) {
goto label_105;
}
catch(IOException v1_1) {
goto label_110;
}
catch(SocketTimeoutException v1_3) {
goto label_47;
}
catch(Throwable v0_1) {
goto label_96;
}
try {
label_21:
v2.close();
label_22:
if(v3 == null) {
return v0;
}
v3.disconnect();
}
catch(IOException v1_1) {
}
return v0;
label_27:
if(v4 == 301 || v4 == 302) {
if(v2 != null) {
int v1_4 = -1;
try {
v1 = n.a(v2, v1_4);
label_34:
v0.bVW = this.a(v3, arg7, v1);
goto label_36;
}
...
private HttpURLConnection aw(String arg4, int arg5) {
HttpURLConnection v0_2;
int v1_2;
URLConnection v0_1;
HttpURLConnection v1 = null;
try {
v0_1 = new URL(arg4).openConnection();
}
catch(Exception v0) {
goto label_26;
}
try {
v1_2 = uc.KF();
goto label_5;
}
catch(Exception v1_1) {
}
catch(Exception v0) {
label_26:
v0_2 = ((HttpURLConnection)v1_2);
return v0_2;
try {
label_5:
if(v1_2 < 8) {
System.setProperty("http.keepAlive", "false");
}
((HttpURLConnection)v0_1).setUseCaches(false);
((HttpURLConnection)v0_1).setRequestProperty("Pragma", "no-cache");
((HttpURLConnection)v0_1).setRequestProperty("Cache-Control", "no-cache");
((HttpURLConnection)v0_1).setInstanceFollowRedirects(false);
((HttpURLConnection)v0_1).setRequestMethod("GET");
((HttpURLConnection)v0_1).setReadTimeout(arg5);
((HttpURLConnection)v0_1).setConnectTimeout(arg5);
}
catch(Exception v1_1) {
}
}
return v0_2;
}
通过上面可以看到,主要是发送一个http请求,然后根据返回码进行处理,如果是200,那么bVW就是当前的url(bVW是redirec url,后面会根据这个判断,很重要),如果是301或302,那么说明发生了重定向,这种情况下就要获取重定向的url,有下面三种情况:
1. 如果response的header里面有Location这个字段,那么重定向url就是它里面的内容
2. 如果response的header里面有Refresh这个字段,那么重定向url就是它里面的部分内容
3. 如果response的url为空,那么查找body里面是否有location.href这个字段,有的话重定向url就是它指向的内容
具体代码如下:
private String a(HttpURLConnection arg5, String arg6, String arg7) {
String v1_3;
String v0 = "";
try {
if(TextUtils.isEmpty(((CharSequence)v0))) {
v0 = arg5.getHeaderField("Location");
}
if(!TextUtils.isEmpty(((CharSequence)v0))) {
goto label_18;
}
try {
String[] v1_2 = arg5.getHeaderField("Refresh").split(";");
if(v1_2 == null) {
goto label_18;
}
if(v1_2.length != 2) {
goto label_18;
}
v0 = v1_2[1].trim();
goto label_18;
}
catch(Exception v1_1) {
try {
v1_1.printStackTrace();
label_18:
if(TextUtils.isEmpty(((CharSequence)v0))) {
String v2 = arg6 != null ? new URL(arg6).getHost() : "";
v1_3 = arg5.getURL() != null ? arg5.getURL().getHost() : "";
if(!TextUtils.isEmpty(((CharSequence)v0))) {
goto label_58;
}
if(v2.compareTo(v1_3) == 0) {
goto label_58;
}
v0 = arg5.getURL().toExternalForm();
v1_3 = v0;
goto label_36;
return v0;
}
else {
}
}
catch(Throwable v1) {
return v0;
}
}
}
catch(Throwable v1) {
return v0;
}
label_58:
v1_3 = v0;
try {
label_36:
if((TextUtils.isEmpty(((CharSequence)v1_3))) && !TextUtils.isEmpty(((CharSequence)arg7))) {
v0 = n.pN(arg7);
if(v0 == null) {
return v1_3;
}
return v0;
}
}
catch(Throwable v0_1) {
return v1_3;
}
return v1_3;
}
public static String pN(String arg3) {
int v2;
String v0 = "";
if(v0 != null) {
int v1 = arg3.indexOf("location.href=\"");
if(v1 > 0) {
v1 += "location.href=\"".length();
v2 = arg3.indexOf("\"", v1);
if(v2 > v1 && v2 > 0) {
v0 = arg3.substring(v1, v2);
if(v0 != null && !v0.trim().toLowerCase().startsWith("http")) {
v0 = "";
}
}
}
if(!TextUtils.isEmpty(((CharSequence)v0))) {
return v0;
}
v1 = arg3.indexOf("location.href=\'");
if(v1 <= 0) {
return v0;
}
v1 += "location.href=\'".length();
v2 = arg3.indexOf("\'", v1);
if(v2 <= v1) {
return v0;
}
if(v2 <= 0) {
return v0;
}
v0 = arg3.substring(v1, v2);
if(v0 == null) {
return v0;
}
if(v0.trim().toLowerCase().startsWith("http")) {
return v0;
}
v0 = "";
}
return v0;
}
获取到重定向的url,接下来返回入口函数,对这个重定向url进行处理,下面是处理代码:
if((TextUtils.isEmpty(((CharSequence)v4_1))) || (TextUtils.isEmpty(v4_1.toLowerCase()))) {
v4_1 = v5_1;
}
if((TextUtils.isEmpty(((CharSequence)v0_2))) || (TextUtils.isEmpty(v0_2.toLowerCase()))) {
v0_2 = v3_1;
}
if(!v8.fNY && !TextUtils.isEmpty(v8.bVW) && ((v8.bVW.toLowerCase().contains(v4_1.toLowerCase())) || (v8.bVW.toLowerCase().contains(((CharSequence)v5_1))))) {
this.fNV = "Redirect baidu RedirectUrl = " + v8.bVW + ", taobao RedirectUrl = " + v9.bVW;
this.bc(v12, 0);
return 1;
}
if(!v8.fNY && !TextUtils.isEmpty(v8.bVW) && !v8.bVW.toLowerCase().contains(((CharSequence)v6))) {
this.fNV = "baidu: " + v8.bVW;
this.bc(v11, v11);
return 1;
}
if(!v9.fNY && !TextUtils.isEmpty(v9.bVW) && ((v9.bVW.toLowerCase().contains(v0_2.toLowerCase())) || (v9.bVW.toLowerCase().contains(((CharSequence)v3_1))))) {
this.fNV = "Redirect baidu RedirectUrl = " + v8.bVW + ", taobao RedirectUrl = " + v9.bVW;
this.bc(v12, 0);
return 1;
}
if(!v9.fNY && !TextUtils.isEmpty(v9.bVW) && !v9.bVW.toLowerCase().startsWith(v3_1) && !v9.bVW.toLowerCase().startsWith(v7)) {
this.fNV = "taobao: " + v9.bVW;
this.bc(v11, v11);
return 1;
}
if(!v8.fNY && !v9.fNY && !TextUtils.isEmpty(v8.bVW) && !TextUtils.isEmpty(v9.bVW) && (TextUtils.equals(v8.bVW.toLowerCase(), v9.bVW.toLowerCase()))) {
this.fNV = "baidu and taobao has the same redirectUrl, url = " + v9.bVW;
this.bc(v11, v11);
return 1;
}
首先解释一下相关变量的意义,fNY是一个boolean值,代表的是响应是否是301、302这两个里面的一个,如果不是,那就是没有重定向,默认是safe.然后是bVW这个变量,这个就是之前获取到的重定向的url,最后是v11和v12这两个变量代表检测结果,v11代表有危险,v12代表安全,所以看到返回v11的就是不安全的几种情况,比如http://tools.3g.qq.com/wifi/ssl本来应该重定向到baidu.com,如果重定向结果不是这个说明dns遭到篡改了,还有就是淘宝的那个url本来不应该重定向的,如果发生了重定向也说明dns有问题,列出了所有情况,检测就结束了