前一段时间看到一款比较不错的app,叫做麻花影视

感觉很良心,而且上面竟然有最新的电视剧的更新。所以想抓包看下能不能拿到这个app的视频来源。但是发现,连接上Charles之后,直接请求不到数据。
结果挂上Charles之后竟然界面没有数据并且 Toast 提示 请关闭代理重试
。
我能猜测到的引起这种现象的有两种情况:
- 证书不匹配,项目固定了证书,或者服务端对客户端证书进行了验证;
- 项目里面有代理检测
进一步猜测并测试,我们再尝试一个别的代理。用手机上的app,packet capture 尝试一下结果竟然可以访问,而且也能够抓到数据。所以猜测证书引起的可能性不大。
并且它Toast 提示 请关闭代理重试
。这一行提示出卖了他。说明他知道我挂了代理,那么它里面很有可能进行了网络代理检测。而且用Charles抓包的时候,我们根本没有抓到任何的请求,如果是证书固定的话,那么会在握手的时候出现错误。
网上搜一下如何判断当前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
类里有如下代码:
//不就是特么这个方法吗、
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表明没有是用代理:
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?
引用网上的一段话:对于一些常用的网络库,其实是提供了我们设置的代理的接口,我们只需要将其设置成无代理的模式,它就不会去应用系统默认的代理了。
就拿比较常用的 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代理了。