前一段时间看到一款比较不错的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代理了。