前一段時間看到一款比較不錯的app,叫作麻花影視 java
感受很良心,並且上面居然有最新的電視劇的更新。因此想抓包看下能不能拿到這個app的視頻來源。可是發現,鏈接上Charles以後,直接請求不到數據。android
結果掛上Charles以後居然界面沒有數據而且 Toast 提示 請關閉代理重試
。bash
我能猜想到的引發這種現象的有兩種狀況:網絡
進一步猜想並測試,咱們再嘗試一個別的代理。用手機上的app,packet capture 嘗試一下結果居然能夠訪問,並且也可以抓到數據。因此猜想證書引發的可能性不大。app
而且它Toast 提示 請關閉代理重試
。這一行提示出賣了他。說明他知道我掛了代理,那麼它裏面頗有可能進行了網絡代理檢測。並且用Charles抓包的時候,咱們根本沒有抓到任何的請求,若是是證書固定的話,那麼會在握手的時候出現錯誤。ide
網上搜一下如何判斷當前wifi是否使用了代理的基本方法,都是下面這段代碼:測試
public static boolean isWifiProxy() {
final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
String proxyAddress;
int proxyPort;
if (IS_ICS_OR_LATER) {
proxyAddress = System.getProperty("http.proxyHost");
String portStr = System.getProperty("http.proxyPort");
proxyPort = Integer.parseInt((portStr != null ? portStr : "-1"));
} else {
proxyAddress = android.net.Proxy.getHost(context);
proxyPort = android.net.Proxy.getPort(context);
}
return (!TextUtils.isEmpty(proxyAddress)) && (proxyPort != -1);
}
複製代碼
因此咱們找下他的app代碼裏面是否是有相關的特徵值。jadx 全局搜索 System.getProperty("http.proxyHost");
獲得 com.mh.movie.core.app.i
類裏有以下代碼:ui
//不就是特麼這個方法嗎、
private boolean a(Context context) {
CharSequence property;
int parseInt;
if ((VERSION.SDK_INT >= 14 ? 1 : null) != null) {
property = System.getProperty("http.proxyHost");
String property2 = System.getProperty("http.proxyPort");
if (TextUtils.isEmpty(property2)) {
property2 = "-1";
}
parseInt = Integer.parseInt(property2);
} else {
String host = Proxy.getHost(context);
parseInt = Proxy.getPort(context);
property = host;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("proxyAddress : ");
stringBuilder.append(property);
stringBuilder.append(", port : ");
stringBuilder.append(parseInt);
Log.i("checkWifiProxy", stringBuilder.toString());
if (TextUtils.isEmpty(property) || parseInt == -1) {
return false;
}
return true;
}
複製代碼
直接用Xposed hook上的方法 ,而後返回false就好了,false代表沒有是用代理:this
Class i = loadPackageParam.classLoader.loadClass("com.mh.movie.core.app.i");
XposedHelpers.findAndHookMethod(i,
"a",
Context.class,
new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
return false;
}
});
複製代碼
原本覺得事情到這裏就結束了,可是,TMD、雖然能訪問網絡,可是抓不到包,抓不到包。。。。。why?spa
引用網上的一段話:對於一些經常使用的網絡庫,實際上是提供了咱們設置的代理的接口,咱們只須要將其設置成無代理的模式,它就不會去應用系統默認的代理了。
就拿比較經常使用的 OkHttp 來舉例,在初始化的時候,就能夠經過 proxy() 方法,爲 OkHttp 設置一個代理。
OkHttpClient.Builder httpBuilder = OkHttpClient.Builder()
.addInterceptor(defaultInterceptor())
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)
.proxy(Proxy.NO_PROXY)
複製代碼
爲了處理比較完全,咱們直接經過Xposed hook OkHttpClient.Builder 的 proxy方法,而後取消掉這個設置PROXY的過程,讓方法直接返回:
Class Builder = loadPackageParam.classLoader.loadClass("okhttp3.OkHttpClient$Builder");
Class Proxy = loadPackageParam.classLoader.loadClass("java.net.Proxy");
XposedHelpers.findAndHookMethod(Builder,
"proxy",
Proxy,
new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
return methodHookParam.thisObject;
}
});
複製代碼
好了,到如今爲止,能夠經過Charles抓取他的API了。他的防抓包策略徹底能夠用到咱們本身的項目裏面,防止別人抓包。
總結一下,他這裏的抓包防禦總共有兩處 1,檢查是否是用了Http代理,若是是,那麼客戶端再也不發送網絡請求; 2,經過Okhttp 設置默認代理,那麼就不會走咱們的Charles代理了。