美文网首页
2019-07-16 Charles 在安卓7.0以上系统抓包辅

2019-07-16 Charles 在安卓7.0以上系统抓包辅

作者: 兣甅 | 来源:发表于2019-07-16 17:17 被阅读0次

    本文仅真对OkhttpClient进行抓包适配,参考文章:原文

    1.在创建OkHttpClient的时候,调用OkHttpClient.Builder的build()方法前调用 以下代码
    CharlesUtils.getInstance().setCharlesSSL(builder,
    CharlesUtils.getInstance().getCharlesInputStream(context,"charles.pem"))
    
    2.辅助工具类
    import android.Manifest;
    import android.content.Context;
    import android.content.pm.PackageManager;
    import android.os.Build;
    import android.os.Environment;
    import android.util.Log;
    import java.io.*;
    import java.security.*;
    import java.security.cert.*;
    import java.security.cert.Certificate;
    import java.util.Arrays;
    import java.util.Collection;
    import javax.net.ssl.*;
    import okhttp3.OkHttpClient;
    
    /**
     * 参考:https://www.jianshu.com/p/cc7ae2f96b64
     * app抓包辅助,抓包条件:
     * 1.需要在sd卡下面保存charles的pem文件,文件名称为charles.pem
     * 2.需要SD卡读取权限
     * 3.尽量只对测试渠道的设置抓包
     * 4.如果OkHttpClient是单利,启动APP后才设置代理,则需要杀掉APP后重新打开
     * 5.如果打开了代理,又不能正确读取设置代理,则会出现无法访问的情况
     * Author:caiyoufei
     * Date:19-7-16
     * Time:下午4:49
     */
    public class CharlesUtils {
      private static class SingleTonHolder {
        private static final CharlesUtils INSTANCE = new CharlesUtils();
      }
    
      public static CharlesUtils getInstance() {
        return SingleTonHolder.INSTANCE;
      }
    
      private CharlesUtils() {
      }
    
      /**
       * 获取chales的pem文件流
       *
       * @param context 上下文
       * @param sdRootPemName sd卡下面的pem文件名称
       * @return pem文件流
       */
      public FileInputStream getCharlesInputStream(Context context, String sdRootPemName) {
        if (!isWifiProxy(context)) {
          Log.e("CharlesUtils", "没有使用代理,不用抓包");
          return null;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
            context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED
        ) {
          try {
            File pemFile = new File(Environment.getExternalStorageDirectory(), sdRootPemName);
            if (pemFile.exists()) {
              return new FileInputStream(pemFile);
            } else {
              Log.e("CharlesUtils", "SD卡没有pem文件");
              return null;
            }
          } catch (FileNotFoundException e) {
            Log.e("CharlesUtils", "读取SD卡pem文件失败");
            e.printStackTrace();
            return null;
          }
        } else {
          Log.e("CharlesUtils", "没有SD卡权限读取pem文件");
          return null;
        }
      }
    
      /**
       * 是否使用了代理
       */
      private boolean isWifiProxy(Context context) {
        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);
      }
    
      /**
       * 为okhttp客户端设置抓包验证
       *
       * @param builder okhttp客户端builder
       * @param certificate 自签名证书的输入流
       */
      public void setCharlesSSL(OkHttpClient.Builder builder, InputStream certificate) {
        try {
          if (builder == null || certificate == null) return;
          X509TrustManager trustManager = trustManagerForCertificates(certificate);
          if (trustManager != null) {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //使用构建出的trustManger初始化SSLContext对象
            sslContext.init(null, new TrustManager[] { trustManager }, null);
            //获得sslSocketFactory对象
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            builder.sslSocketFactory(sslSocketFactory, trustManager);
            Log.e("CharlesUtils", "开启抓包");
          } else {
            Log.e("CharlesUtils", "验证pem文件失败");
          }
        } catch (Exception e) {
          e.printStackTrace();
          Log.e("CharlesUtils", "验证pem文件失败:" + e.getMessage());
        }
      }
    
      /**
       * 获去信任自签证书的trustManager
       *
       * @param input 自签证书输入流
       * @return 信任自签证书的trustManager
       */
      private X509TrustManager trustManagerForCertificates(InputStream input) {
        try {
          CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
          //通过证书工厂得到自签证书对象集合
          Collection<? extends Certificate> certificates =
              certificateFactory.generateCertificates(input);
          if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
          }
          //为证书设置一个keyStore
          char[] password = "password".toCharArray(); // Any password will work.
          KeyStore keyStore = newEmptyKeyStore(password);
          if (keyStore == null) return null;
          int index = 0;
          //将证书放入keystore中
          for (Certificate certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificate);
          }
          // Use it to build an X509 trust manager.
          //使用包含自签证书信息的keyStore去构建一个X509TrustManager
          KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
              KeyManagerFactory.getDefaultAlgorithm());
          keyManagerFactory.init(keyStore, password);
          TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
              TrustManagerFactory.getDefaultAlgorithm());
          trustManagerFactory.init(keyStore);
          TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
          if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                + Arrays.toString(trustManagers));
          }
          return (X509TrustManager) trustManagers[0];
        } catch (Exception e) {
          e.printStackTrace();
          return null;
        }
      }
    
      private KeyStore newEmptyKeyStore(char[] password) {
        try {
          KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
          keyStore.load(null, password);
          return keyStore;
        } catch (Exception e) {
          e.printStackTrace();
          return null;
        }
      }
    }
    

    附:Charles 抓包配置

    相关文章

      网友评论

          本文标题:2019-07-16 Charles 在安卓7.0以上系统抓包辅

          本文链接:https://www.haomeiwen.com/subject/rhitlctx.html