如何使用Xposed绕过APP自定义证书验证去抓Https包 - CSDN博客

2,878 阅读2分钟
原文链接: blog.csdn.net

我们团队在开发过程中,测试接口时,常使用fiddler抓包查看请求报文和响应报文快速定位问题所在,这可比在代码中打断点看数据高效一万倍……

然而fiddler只能抓http包,如果是https,有可能因为证书问题抓不到包。

而这种场景一般都出现在,需要黑别家app,查看一些小秘密。

没错,这次我们由于业务需要,得分析某竞品,自然不能倒在这抓包的第一步,所以下面记录下使用Xpose绕过自定义证书验证的全过程。

反编译APK

常见的套路,apk后缀改zip解压,拿到dex文件,这里一般会有多个dex,全部拷到dex2jar目录下。

接下来我们要使用d2j-dex2jar.bat 把dex反编译成jar。

最简单的方式,把d2j-dex2jar.bat和dex文件都拖到终端命令框,回车。

把反编译的jar丢到gui,然后:

这里写图片描述

得到java源文件,到此为止我们就拿到了混淆后的java文件。

接下来就要考验大家对代码的敏感度了,因为核心代码都是abc这样的字母,我们要靠它们找到代码中疑似设置httpClinet的地方。

定位https

这里推荐使用EditPlus,可以全局搜索字符串,快捷键是Ctrl + Shift + F5

我们直接全局搜httpClinet,找到对应代码段:

private static DefaultHttpClient a(boolean paramBoolean)
  {
      ……
      KeyStore ks= KeyStore.getInstance(KeyStore.getDefaultType());
      ks.load(null, null);
      b localb = new b(ks, paramBoolean);
      localb.setHostnameVerifier(b.ALLOW_ALL_HOSTNAME_VERIFIER);
      BasicHttpParams localBasicHttpParams = new BasicHttpParams();
      localBasicHttpParams.setParameter("http.protocol.cookie-policy", "netscape");
      HttpConnectionParams.setSocketBufferSize(localBasicHttpParams, 8192);
      HttpConnectionParams.setStaleCheckingEnabled(localBasicHttpParams, false);
      HttpConnectionParams.setConnectionTimeout(localBasicHttpParams, 20000);
      HttpConnectionParams.setSoTimeout(localBasicHttpParams, 20000);
      HttpProtocolParams.setUseExpectContinue(localBasicHttpParams, false);
      SchemeRegistry localSchemeRegistry = new SchemeRegistry();
      //注册http协议
      localSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
      //注册https协议
      localSchemeRegistry.register(new Scheme("https", localb, 443));

      DefaultHttpClient localDefaultHttpClient = new DefaultHttpClient(new ThreadSafeClientConnManager(localBasicHttpParams, localSchemeRegistry), localBasicHttpParams);
      localDefaultHttpClient.setRedirectHandler(new f());
      ……
  }

可以看到https协议用了自己的证书,却信任全部证书……那就很简单了,只要勾住SchemeRegistry中的register方法,把其第二个参数(证书)替换成http证书即可。

Hook

直接上代码:

public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        if (!lpparam.packageName.equals("目标包名"))
            return;

        classLoader = lpparam.classLoader;

        //勾住android入口函数
        XposedHelpers.findAndHookMethod("android.app.Instrumentation", lpparam.classLoader, "newActivity", ClassLoader.class, String.class, Intent.class, new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {

            }

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                ClassLoader realClassLoader = lpparam.classLoader;

                final Class<?> acpv = XposedHelpers.findClass("org.apache.http.conn.scheme.SchemeRegistry", realClassLoader);
                XposedBridge.hookAllMethods(acpv, "register", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                    }

                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Scheme s = (Scheme) param.args[0];
                        if (s.getDefaultPort() == 443) {
                            //这里把证书替换成http证书
                            param.args[0] = new Scheme("https", PlainSocketFactory.getSocketFactory(), 443);
                        }
                        super.beforeHookedMethod(param);
                    }
                });
                super.afterHookedMethod(param);
            }
        });
    }

由于目标代码信任全部证书,所以这里只是简单的替换证书。

对于Xpose再提一点,每次更新了hook代码,都要在Xpose框架里重启手机让hook代码生效。

对于更严格的,验证了自定义证书的目标,可以使用现成的轮子: JustTrustMe

轮子将APK中所有用于校验SSL证书的API都进行了Hook,真狠呐……

虽然有现成的轮子,不过对于简单的东西,能自己动手实现一番,何乐而不为呢?