package mobi.acpm.inspeckage.hooks; import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.ssl.SSLSocketFactory; import java.net.Socket; import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.callbacks.XC_LoadPackage; import mobi.acpm.inspeckage.Module; import static de.robv.android.xposed.XposedHelpers.callMethod; import static de.robv.android.xposed.XposedHelpers.callStaticMethod; import static de.robv.android.xposed.XposedHelpers.findAndHookConstructor; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; import static de.robv.android.xposed.XposedHelpers.findClass; import static de.robv.android.xposed.XposedHelpers.getObjectField; import static de.robv.android.xposed.XposedHelpers.newInstance; import static de.robv.android.xposed.XposedHelpers.setObjectField; /** * Created by acpm on 25/11/15. * * Code from SSLUnpinning project https://github.com/ac-pm/SSLUnpinning_Xposed */ public class SSLPinningHook extends XC_MethodHook { public static final String TAG = "Inspeckage_SSLPinning:"; private static XSharedPreferences sPrefs; public static void loadPrefs() { sPrefs = new XSharedPreferences(Module.class.getPackage().getName(), Module.PREFS); sPrefs.makeWorldReadable(); } public static void initAllHooks(final XC_LoadPackage.LoadPackageParam loadPackageParam) { // --- Java Secure Socket Extension (JSSE) --- //TrustManagerFactory.getTrustManagers >> EmptyTrustManager findAndHookMethod("javax.net.ssl.TrustManagerFactory", loadPackageParam.classLoader, "getTrustManagers", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { TrustManager[] tms = EmptyTrustManager.getInstance(); param.setResult(tms); } } }); //SSLContext.init >> (null,EmptyTrustManager,null) findAndHookMethod("javax.net.ssl.SSLContext", loadPackageParam.classLoader, "init", KeyManager[].class, TrustManager[].class, SecureRandom.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.args[0] = null; param.args[1] = EmptyTrustManager.getInstance(); param.args[2] = null; } } }); //HttpsURLConnection.setSSLSocketFactory >> new SSLSocketFactory findAndHookMethod("javax.net.ssl.HttpsURLConnection", loadPackageParam.classLoader, "setSSLSocketFactory", javax.net.ssl.SSLSocketFactory.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.args[0] = newInstance(javax.net.ssl.SSLSocketFactory.class); } } }); // --- APACHE --- try { final Class<?> httpsURLConnection = findClass("org.apache.http.conn.ssl.HttpsURLConnection", loadPackageParam.classLoader); if (httpsURLConnection != null) { //HttpsURLConnection.setDefaultHostnameVerifier >> SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER try { findAndHookMethod(httpsURLConnection, "setDefaultHostnameVerifier", HostnameVerifier.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.args[0] = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; } } }); } catch (Error e) { Module.logError(e); } //HttpsURLConnection.setHostnameVerifier >> SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER try { findAndHookMethod("org.apache.http.conn.ssl.HttpsURLConnection", loadPackageParam.classLoader, "setHostnameVerifier", HostnameVerifier.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.args[0] = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; } } }); } catch (Error e) { Module.logError(e); } //SSLSocketFactory.getSocketFactory >> new SSLSocketFactory try { findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", loadPackageParam.classLoader, "getSocketFactory", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.setResult((SSLSocketFactory) newInstance(SSLSocketFactory.class)); } } }); } catch (Error e) { Module.logError(e); } //SSLSocketFactory(...) >> SSLSocketFactory(...){ new EmptyTrustManager()} try { Class<?> sslSocketFactory = findClass("org.apache.http.conn.ssl.SSLSocketFactory", loadPackageParam.classLoader); findAndHookConstructor(sslSocketFactory, String.class, KeyStore.class, String.class, KeyStore.class, SecureRandom.class, HostNameResolver.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { String algorithm = (String) param.args[0]; KeyStore keystore = (KeyStore) param.args[1]; String keystorePassword = (String) param.args[2]; SecureRandom random = (SecureRandom) param.args[4]; KeyManager[] keymanagers = null; TrustManager[] trustmanagers; if (keystore != null) { keymanagers = (KeyManager[]) callStaticMethod(SSLSocketFactory.class, "createKeyManagers", keystore, keystorePassword); } trustmanagers = new TrustManager[]{new EmptyTrustManager()}; setObjectField(param.thisObject, "sslcontext", SSLContext.getInstance(algorithm)); callMethod(getObjectField(param.thisObject, "sslcontext"), "init", keymanagers, trustmanagers, random); setObjectField(param.thisObject, "socketfactory", callMethod(getObjectField(param.thisObject, "sslcontext"), "getSocketFactory")); } } }); } catch (Error e) { Module.logError(e); } //SSLSocketFactory.isSecure >> true try { findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", loadPackageParam.classLoader, "isSecure", Socket.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.setResult(true); } } }); } catch (Error e) { Module.logError(e); } } } catch (Error e) { Module.logError(e); } ///OKHTTP try { findAndHookMethod("okhttp3.CertificatePinner", loadPackageParam.classLoader, "findMatchingPins", String.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); if (sPrefs.getBoolean("sslunpinning", false)) { param.args[0] = ""; } } }); } catch (Error e) { Module.logError(e); } } } class EmptyTrustManager implements X509TrustManager { private static TrustManager[] emptyTM = null; public static TrustManager[] getInstance() { if (emptyTM == null) { emptyTM = new TrustManager[1]; emptyTM[0] = new EmptyTrustManager(); } return emptyTM; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }