https://blog.csdn.net/tangsilian/article/details/86612470
需求:在逆向某些app时通过fiddler抓包。没看到https的流量信息。
解决方法:发现是客户端对 SSL 证书进行了检测,这时候使用了xposed模块JustTrustMe来绕过解决了这个问题。
总结:查看SSL 证书进行了检测的原理,和绕过原理。
转自:https://bbs.pediy.com/thread-214012.htm
JustTrustMe 原理分析 ——挽秋1、JustTrustMe 简介JustTrustMe 一个用来禁用、绕过 SSL 证书检查的基于 Xposed 模块。
项目地址:https://github.com/Fuzion24/JustTrustMe
JustTrustMe 是将 APK 中所有用于校验 SSL 证书的 API 都进行了 Hook,从而绕过证书检
查的,所以弄请原理之前,先得弄清楚 Android 上实现 Https 通信有哪几种方式。
2.1.1 通过 OkHttp 来实现1.通过 OkHttp 来实现
2.自定义证书和 HostnameVerify 来实现 Https 校验
3.通过 HttpsURLConnection 来实现HttpsURLConnection 中进行 SSL 证书校验
OkHttp 是一个第三方库,OkHttp 中进行 SSL 证书校验,有如下两种方式:
1)CertificatePinner(证书锁定):
通过 CertificatePinner 进行连接的 OkHttp,在连接之前,会调用其 check 方法进行证书
校验。
2)自定义证书和 HostnameVerify 来实现 Https 校验:
Okhttp 中如果不指定 HostnameVerifier 默认调用的是 OkHostnameVerifier.verify 进行服
务器主机名校验;如果设置了 HostnameVerifier,则默认调用的是自定义的 verify 方法。
绕过上述 SSL 证书验证,Xposed 需要 Hook 的方法名和类名如下表所示:
类名 方法名
JustTrustME 中的代码并没有 Hook (public OkHttpClient.Builder hostnameVerifier)这个方法,应
该是漏掉了这个方法。
对其中上述四个方法只需要 Hook 函数
2)自定义 SSLSocketFactory 实现其中的 TrustManager 校验策略。
实现代码如下:public HttpClient getHttpClient() { HttpClient httpClient = null; // 初始化工作 try { KeyStore trustStore = KeyStore.getInstance(KeyStore .getDefaultType()); trustStore.load(null, null); SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); //sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //允许所有主机的验证 sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, "utf-8"); HttpProtocolParams.setUseExpectContinue(params, true); // 设置连接管理器的超时 ConnManagerParams.setTimeout(params, 10000); // 设置连接超时 HttpConnectionParams.setConnectionTimeout(params, 10000); // 设置 socket 超时 HttpConnectionParams.setSoTimeout(params, 10000); // 设置 http https 支持 SchemeRegistry schReg = new SchemeRegistry(); schReg.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); schReg.register(new Scheme("https", sf, 443)); ClientConnectionManager conManager = new ThreadSafeClientConnManager( params, schReg); httpClient = new DefaultHttpClient(conManager, params); } catch (Exception e) { e.printStackTrace(); return new DefaultHttpClient(); } return httpClient;}SSLSocketFactoryEx.javaclass SSLSocketFactoryEx extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted( java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException { } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); }}绕过上述 SSL 证书验证,Xposed 需要 Hook 的方法名和类名如下表所示:
类名 方法名
external/apachehttp/src/org/apache/http/impl/client/DefaultHttpClie
nt.java
public DefaultHttpClient()
external/apachehttp/src/org/apache/http/impl/client/DefaultHttpClie
nt.java
public DefaultHttpClient(HttpParams
params)
external/apachehttp/src/org/apache/http/impl/client/DefaultHttpClie
nt.java
public
DefaultHttpClient(ClientConnectionMa
nager conman, HttpParams params)
external/apachehttp/src/org/apache/http/conn/ssl/SSLSocketFactory.
java
public SSLSocketFactory(String,
KeyStore, String, KeyStore)
external/apachehttp/src/org/apache/http/conn/ssl/SSLSocketFactory.
java
public SSLSocketFactory(String,
KeyStore, String, KeyStore)
Hook 的 DefaultHttpClient 三个构造方法,对中都调用(ClientConnectionManager, HttpParams)
这个函数,其中重点需要 Hook 的是 ClientConnectionManager 这个参数,将其替换成如下函
数内容,让其信任所有证书:
2)使用内置的证书初始化一个 KeyStore,实现 TrustManager
实现代码如下:
绕过上述 SSL 证书验证,Xposed 需要 Hook 的方法名和类名如下表所示:
类名 方法名
getTrustManager 的 Hook,跟 2.1.1 中替换方式一样,换成自定义的 TrustManager 让其信任
所有证书,此处不再列出代码。
其他三个函数都是“set”代码,只需要函数替换,不做任何操作即可。
Android 中通过 WebView 加载 Https 页面时,如果出现证书校验错误,则会停止加载页
面,因为只需要 Hook 掉 webview 的证书校验失败的处理方法:onReceivedSslError,让其继
续加载即可。
类名 方法名
对于其中上述两个方法,只需要 webview 继续加载网页即可:handler.proceed()。
2.1.5 JustTrustMe 中其他 Hook 函数JustTrustMe 中其他的 Hook 函数如下:
类名 方法名
external/apachehttp/src/org/apache/http/conn/ssl/SSLSocketF
actory.java
public static SSLSocketFactory
getSocketFactory()/已废弃
external/apachehttp/src/org/apache/http/conn/ssl/SSLSocketF
actory.java
public boolean isSecure(Socket)/已废弃
ch.boye.httpclientandroidlib.conn.ssl.Abstract
Verifier
verify(String, String[], String[], boolean)
前两个函数已经基本没有在使用,而第三个是使用的第三方的库——httpclientandroidlib
进行进行 https 连接的,该 jar14 年以后也没在更新了,几乎没人在使用,所以此处对着三个
函数不继续进行分析,有兴趣的可以继续进行升入分析。
顺便找到xposed高版本的兼容版本
TrustMeAlready https://github.com/ViRb3/TrustMeAlready
一个Xposed模块,在Android上禁用SSL验证和固定。全系统兼容
EdXposed(Android 9, Magisk-based and passes SafetyNet)
‘OG’ Xposed(Android 5-8)
hook这个类com.android.org.conscrypt.TrustManagerImpl下的函数的返回值:
public class Main implements IXposedHookZygoteInit {//在Zygote启动时调用,用于系统服务的Hook 回调方法initZygote() private static final String SSL_CLASS_NAME = "com.android.org.conscrypt.TrustManagerImpl"; private static final String SSL_METHOD_NAME = "checkTrustedRecursive"; private static final Class<?> SSL_RETURN_TYPE = List.class; private static final Class<?> SSL_RETURN_PARAM_TYPE = X509Certificate.class; @Override public void initZygote(StartupParam startupParam) throws Throwable { XposedBridge.log("TrustMeAlready loading..."); int hookedMethods = 0; for (Method method : findClass(SSL_CLASS_NAME, null).getDeclaredMethods()) { //遍历com.android.org.conscrypt.TrustManagerImpl里面的方法 并hook if (!checkSSLMethod(method)) { continue; } List<Object> params = new ArrayList<>(); params.addAll(Arrays.asList(method.getParameterTypes())); params.add(new XC_MethodReplacement() { @Override protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { return new ArrayList<X509Certificate>(); } }); XposedBridge.log("Hooking method:"); XposedBridge.log(method.toString()); findAndHookMethod(SSL_CLASS_NAME, null, SSL_METHOD_NAME, params.toArray());//将方法里的参数的返回值都改为 return new ArrayList<X509Certificate>(); hookedMethods++; } XposedBridge.log(String.format(Locale.ENGLISH, "TrustMeAlready loaded! Hooked %d methods", hookedMethods)); } private boolean checkSSLMethod(Method method) { if (!method.getName().equals(SSL_METHOD_NAME)) { return false; } // check return type if (!SSL_RETURN_TYPE.isAssignableFrom(method.getReturnType())) { return false; } // check if parameterized return type Type returnType = method.getGenericReturnType(); if (!(returnType instanceof ParameterizedType)) { return false; } // check parameter type Type[] args = ((ParameterizedType) returnType).getActualTypeArguments(); if (args.length != 1 || !(args[0].equals(SSL_RETURN_PARAM_TYPE))) { return false; } return true; }}https://www.anquanke.com/post/id/86507
2.1.6 参考文章https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLContext.html
http://www.apihome.cn/api/android/SSLSocketFactory.html
http://blog.sina.com.cn/s/blog_616e189f01018rpk.html
https://github.com/square/okhttp/wiki/HTTPS
https://square.github.io/okhttp/2.x/okhttp/com/squareup/okhttp/CertificatePinner.html
http://hc.apache.org/httpcomponents-clientga/httpclient/apidocs/org/apache/http/conn/ssl/SSLSocketFactory.html
http://pingguohe.net/2016/02/26/Android-App-secure-ssl.html
http://frodoking.github.io/2015/03/12/android-okhttp/
欢迎光临 firemail (http://firemail.wang:8088/) | Powered by Discuz! X3 |