diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index f255ec0..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -Inspeckage \ No newline at end of file diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser new file mode 100644 index 0000000..519649e Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser new file mode 100644 index 0000000..7cf0b08 Binary files /dev/null and b/.idea/caches/gradle_models.ser differ diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 30aa626..681f41a 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,29 +1,116 @@ - - - - - - - - - - + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
\ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 96cc43e..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 97626ba..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index afaee01..ee635a3 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -3,9 +3,11 @@ diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 010be73..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 3b31283..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index ba7052b..dfd2c79 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,30 +1,6 @@ - - - - - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index c6ff81f..be9e68f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 - buildToolsVersion '28.0.2' + buildToolsVersion '28.0.3' defaultConfig { applicationId "mobi.acpm.inspeckage" minSdkVersion 21 diff --git a/app/release/output.json b/app/release/output.json new file mode 100644 index 0000000..235b52b --- /dev/null +++ b/app/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":10,"versionName":"2.4","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/java/mobi/acpm/inspeckage/Module.java b/app/src/main/java/mobi/acpm/inspeckage/Module.java index cd87771..3e3a2e7 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/Module.java +++ b/app/src/main/java/mobi/acpm/inspeckage/Module.java @@ -4,6 +4,7 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; +import android.util.Log; import java.io.File; @@ -22,6 +23,7 @@ import mobi.acpm.inspeckage.hooks.HashHook; import mobi.acpm.inspeckage.hooks.HttpHook; import mobi.acpm.inspeckage.hooks.IPCHook; +import mobi.acpm.inspeckage.hooks.JustTrustMeHook; import mobi.acpm.inspeckage.hooks.MiscHook; import mobi.acpm.inspeckage.hooks.ProxyHook; import mobi.acpm.inspeckage.hooks.SQLiteHook; @@ -33,6 +35,7 @@ import mobi.acpm.inspeckage.hooks.WebViewHook; import mobi.acpm.inspeckage.hooks.entities.LocationHook; import mobi.acpm.inspeckage.util.Config; +import mobi.acpm.inspeckage.util.DexUtil; import mobi.acpm.inspeckage.util.FileType; import mobi.acpm.inspeckage.util.FileUtil; @@ -157,14 +160,13 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { if(sPrefs.getBoolean(Config.SP_TAB_ENABLE_IPC,true)) { IPCHook.initAllHooks(loadPackageParam); } - ProxyHook.initAllHooks(loadPackageParam);// -- if(sPrefs.getBoolean(Config.SP_TAB_ENABLE_SHAREDP,true)) { SharedPrefsHook.initAllHooks(loadPackageParam); } if(sPrefs.getBoolean(Config.SP_TAB_ENABLE_SQLITE,true)) { SQLiteHook.initAllHooks(loadPackageParam); } - SSLPinningHook.initAllHooks(loadPackageParam);// -- + if(sPrefs.getBoolean(Config.SP_TAB_ENABLE_SERIALIZATION,true)) { SerializationHook.initAllHooks(loadPackageParam); } @@ -176,7 +178,12 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { } FingerprintHook.initAllHooks(loadPackageParam); - //DexUtil.saveClassesWithMethodsJson(loadPackageParam, sPrefs); + + + SSLPinningHook.initAllHooks(loadPackageParam);// -- + ProxyHook.initAllHooks(loadPackageParam);// -- + DexUtil.saveClassesWithMethodsJson(loadPackageParam, sPrefs); + JustTrustMeHook.initAllHooks(loadPackageParam);// -- } public static void logError(Error e){ diff --git a/app/src/main/java/mobi/acpm/inspeckage/hooks/JustTrustMeHook.java b/app/src/main/java/mobi/acpm/inspeckage/hooks/JustTrustMeHook.java new file mode 100644 index 0000000..979c1e6 --- /dev/null +++ b/app/src/main/java/mobi/acpm/inspeckage/hooks/JustTrustMeHook.java @@ -0,0 +1,598 @@ +package mobi.acpm.inspeckage.hooks; + +import android.content.Context; +import android.net.http.SslError; +import android.util.Log; +import android.webkit.SslErrorHandler; +import android.webkit.WebView; + +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.HostNameResolver; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.SingleClientConnManager; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.HttpParams; + +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import de.robv.android.xposed.IXposedHookLoadPackage; +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XC_MethodReplacement; +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; + +public class JustTrustMeHook extends XC_MethodHook{ + + private static final String TAG = JustTrustMeHook.class.getSimpleName(); + 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 lpparam) { + + String currentPackageName = lpparam.packageName; + + + + /* Apache Hooks */ + /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ + /* public DefaultHttpClient() */ + Log.d(TAG, "Hooking DefaultHTTPClient for: "); + findAndHookConstructor(DefaultHttpClient.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + setObjectField(param.thisObject, "defaultParams", null); + setObjectField(param.thisObject, "connManager", getSCCM()); + } + }); + + /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ + /* public DefaultHttpClient(HttpParams params) */ + Log.d(TAG, "Hooking DefaultHTTPClient(HttpParams) for: "); + findAndHookConstructor(DefaultHttpClient.class, HttpParams.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + setObjectField(param.thisObject, "defaultParams", (HttpParams) param.args[0]); + setObjectField(param.thisObject, "connManager", getSCCM()); + } + }); + + /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ + /* public DefaultHttpClient(ClientConnectionManager conman, HttpParams params) */ + Log.d(TAG, "Hooking DefaultHTTPClient(ClientConnectionManager, HttpParams) for: "); + findAndHookConstructor(DefaultHttpClient.class, ClientConnectionManager.class, HttpParams.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + HttpParams params = (HttpParams) param.args[1]; + + setObjectField(param.thisObject, "defaultParams", params); + setObjectField(param.thisObject, "connManager", getCCM(param.args[0], params)); + } + }); + + /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ + /* public SSLSocketFactory( ... ) */ + Log.d(TAG, "Hooking SSLSocketFactory(String, KeyStore, String, KeyStore) for: "); + findAndHookConstructor(SSLSocketFactory.class, String.class, KeyStore.class, String.class, KeyStore.class, + SecureRandom.class, HostNameResolver.class, new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + 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 = null; + + if (keystore != null) { + keymanagers = (KeyManager[]) callStaticMethod(SSLSocketFactory.class, "createKeyManagers", keystore, keystorePassword); + } + + trustmanagers = new TrustManager[]{new ImSureItsLegitTrustManager()}; + + 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")); + } + + }); + + + /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ + /* public static SSLSocketFactory getSocketFactory() */ + Log.d(TAG, "Hooking static SSLSocketFactory(String, KeyStore, String, KeyStore) for: "); + findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", lpparam.classLoader, "getSocketFactory", new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return (SSLSocketFactory) newInstance(SSLSocketFactory.class); + } + }); + + /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ + /* public boolean isSecure(Socket) */ + Log.d(TAG, "Hooking SSLSocketFactory(Socket) for: "); + findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", lpparam.classLoader, "isSecure", Socket.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return true; + } + }); + + /* JSSE Hooks */ + /* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */ + /* public final TrustManager[] getTrustManager() */ + Log.d(TAG, "Hooking TrustManagerFactory.getTrustManagers() for: "); + findAndHookMethod("javax.net.ssl.TrustManagerFactory", lpparam.classLoader, "getTrustManagers", new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + if (hasTrustManagerImpl()) { + Class cls = findClass("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader); + + TrustManager[] managers = (TrustManager[]) param.getResult(); + if (managers.length > 0 && cls.isInstance(managers[0])) + return; + } + + param.setResult(new TrustManager[]{new ImSureItsLegitTrustManager()}); + } + }); + + /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ + /* public void setDefaultHostnameVerifier(HostnameVerifier) */ + Log.d(TAG, "Hooking HttpsURLConnection.setDefaultHostnameVerifier for: "); + findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setDefaultHostnameVerifier", + HostnameVerifier.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return null; + } + }); + + /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ + /* public void setSSLSocketFactory(SSLSocketFactory) */ + Log.d(TAG, "Hooking HttpsURLConnection.setSSLSocketFactory for: "); + findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setSSLSocketFactory", javax.net.ssl.SSLSocketFactory.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return null; + } + }); + + /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ + /* public void setHostnameVerifier(HostNameVerifier) */ + Log.d(TAG, "Hooking HttpsURLConnection.setHostnameVerifier for: "); + findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setHostnameVerifier", HostnameVerifier.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return null; + } + }); + + + /* WebView Hooks */ + /* frameworks/base/core/java/android/webkit/WebViewClient.java */ + /* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */ + Log.d(TAG, "Hooking WebViewClient.onReceivedSslError(WebView, SslErrorHandler, SslError) for: "); + + findAndHookMethod("android.webkit.WebViewClient", lpparam.classLoader, "onReceivedSslError", + WebView.class, SslErrorHandler.class, SslError.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + ((android.webkit.SslErrorHandler) param.args[1]).proceed(); + return null; + } + }); + + /* frameworks/base/core/java/android/webkit/WebViewClient.java */ + /* public void onReceivedError(WebView, int, String, String) */ + Log.d(TAG, "Hooking WebViewClient.onReceivedSslError(WebView, int, string, string) for: "); + + findAndHookMethod("android.webkit.WebViewClient", lpparam.classLoader, "onReceivedError", + WebView.class, int.class, String.class, String.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return null; + } + }); + + //SSLContext.init >> (null,ImSureItsLegitTrustManager,null) + findAndHookMethod("javax.net.ssl.SSLContext", lpparam.classLoader, "init", KeyManager[].class, TrustManager[].class, SecureRandom.class, new XC_MethodHook() { + + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + + param.args[0] = null; + param.args[1] = new TrustManager[]{new ImSureItsLegitTrustManager()}; + param.args[2] = null; + + } + }); + + // Multi-dex support: https://github.com/rovo89/XposedBridge/issues/30#issuecomment-68486449 + findAndHookMethod("android.app.Application", + lpparam.classLoader, + "attach", + Context.class, + new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + // Hook OkHttp or third party libraries. + Context context = (Context) param.args[0]; + processOkHttp(context.getClassLoader()); + processHttpClientAndroidLib(context.getClassLoader()); + processXutils(context.getClassLoader()); + } + } + ); + + /* Only for newer devices should we try to hook TrustManagerImpl */ + if (hasTrustManagerImpl()) { + /* TrustManagerImpl Hooks */ + /* external/conscrypt/src/platform/java/org/conscrypt/TrustManagerImpl.java */ + Log.d(TAG, "Hooking com.android.org.conscrypt.TrustManagerImpl for: "); + + /* public void checkServerTrusted(X509Certificate[] chain, String authType) */ + findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, + "checkServerTrusted", X509Certificate[].class, String.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + return 0; + } + }); + + /* public List checkServerTrusted(X509Certificate[] chain, + String authType, String host) throws CertificateException */ + findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, + "checkServerTrusted", X509Certificate[].class, String.class, + String.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + ArrayList list = new ArrayList(); + return list; + } + }); + + + /* public List checkServerTrusted(X509Certificate[] chain, + String authType, SSLSession session) throws CertificateException */ + findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, + "checkServerTrusted", X509Certificate[].class, String.class, + SSLSession.class, new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { + ArrayList list = new ArrayList(); + return list; + } + }); + } + + } // End Hooks + + /* Helpers */ + // Check for TrustManagerImpl class + public static boolean hasTrustManagerImpl() { + + try { + Class.forName("com.android.org.conscrypt.TrustManagerImpl"); + } catch (ClassNotFoundException e) { + return false; + } + return true; + } + + private static javax.net.ssl.SSLSocketFactory getEmptySSLFactory() { + try { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[]{new ImSureItsLegitTrustManager()}, null); + return sslContext.getSocketFactory(); + } catch (NoSuchAlgorithmException e) { + return null; + } catch (KeyManagementException e) { + return null; + } + } + + //Create a SingleClientConnManager that trusts everyone! + public static ClientConnectionManager getSCCM() { + + KeyStore trustStore; + try { + + trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + + SSLSocketFactory sf = new TrustAllSSLSocketFactory(trustStore); + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + registry.register(new Scheme("https", sf, 443)); + + ClientConnectionManager ccm = new SingleClientConnManager(null, registry); + + return ccm; + + } catch (Exception e) { + return null; + } + } + + //This function creates a ThreadSafeClientConnManager that trusts everyone! + public static ClientConnectionManager getTSCCM(HttpParams params) { + + KeyStore trustStore; + try { + + trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + + SSLSocketFactory sf = new TrustAllSSLSocketFactory(trustStore); + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + registry.register(new Scheme("https", sf, 443)); + + ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); + + return ccm; + + } catch (Exception e) { + return null; + } + } + + //This function determines what object we are dealing with. + public static ClientConnectionManager getCCM(Object o, HttpParams params) { + + String className = o.getClass().getSimpleName(); + + if (className.equals("SingleClientConnManager")) { + return getSCCM(); + } else if (className.equals("ThreadSafeClientConnManager")) { + return getTSCCM(params); + } + + return null; + } + + private static void processXutils(ClassLoader classLoader) { + Log.d(TAG, "Hooking org.xutils.http.RequestParams.setSslSocketFactory(SSLSocketFactory) (3) for: "); + try { + classLoader.loadClass("org.xutils.http.RequestParams"); + findAndHookMethod("org.xutils.http.RequestParams", classLoader, "setSslSocketFactory", javax.net.ssl.SSLSocketFactory.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + super.beforeHookedMethod(param); + param.args[0] = getEmptySSLFactory(); + } + }); + findAndHookMethod("org.xutils.http.RequestParams", classLoader, "setHostnameVerifier", HostnameVerifier.class, new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + super.beforeHookedMethod(param); + param.args[0] = new ImSureItsLegitHostnameVerifier(); + } + }); + } catch (Exception e) { + Log.d(TAG, "org.xutils.http.RequestParams not found in -- not hooking"); + } + } + + static void processOkHttp(ClassLoader classLoader) { + /* hooking OKHTTP by SQUAREUP */ + /* com/squareup/okhttp/CertificatePinner.java available online @ https://github.com/square/okhttp/blob/master/okhttp/src/main/java/com/squareup/okhttp/CertificatePinner.java */ + /* public void check(String hostname, List peerCertificates) throws SSLPeerUnverifiedException{}*/ + /* Either returns true or a exception so blanket return true */ + /* Tested against version 2.5 */ + Log.d(TAG, "Hooking com.squareup.okhttp.CertificatePinner.check(String,List) (2.5) for: "); + + try { + classLoader.loadClass("com.squareup.okhttp.CertificatePinner"); + findAndHookMethod("com.squareup.okhttp.CertificatePinner", + classLoader, + "check", + String.class, + List.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { + return true; + } + }); + } catch (ClassNotFoundException e) { + // pass + Log.d(TAG, "OKHTTP 2.5 not found in -- not hooking"); + } + + //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/CertificatePinner.java#L144 + Log.d(TAG, "Hooking okhttp3.CertificatePinner.check(String,List) (3.x) for: "); + + try { + classLoader.loadClass("okhttp3.CertificatePinner"); + findAndHookMethod("okhttp3.CertificatePinner", + classLoader, + "check", + String.class, + List.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { + return null; + } + }); + } catch (ClassNotFoundException e) { + Log.d(TAG, "OKHTTP 3.x not found in -- not hooking"); + // pass + } + + //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/internal/tls/OkHostnameVerifier.java + try { + classLoader.loadClass("okhttp3.internal.tls.OkHostnameVerifier"); + findAndHookMethod("okhttp3.internal.tls.OkHostnameVerifier", + classLoader, + "verify", + String.class, + javax.net.ssl.SSLSession.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { + return true; + } + }); + } catch (ClassNotFoundException e) { + Log.d(TAG, "OKHTTP 3.x not found in -- not hooking OkHostnameVerifier.verify(String, SSLSession)"); + // pass + } + + //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/internal/tls/OkHostnameVerifier.java + try { + classLoader.loadClass("okhttp3.internal.tls.OkHostnameVerifier"); + findAndHookMethod("okhttp3.internal.tls.OkHostnameVerifier", + classLoader, + "verify", + String.class, + java.security.cert.X509Certificate.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { + return true; + } + }); + } catch (ClassNotFoundException e) { + Log.d(TAG, "OKHTTP 3.x not found in -- not hooking OkHostnameVerifier.verify(String, X509)("); + // pass + } + } + + static void processHttpClientAndroidLib(ClassLoader classLoader) { + /* httpclientandroidlib Hooks */ + /* public final void verify(String host, String[] cns, String[] subjectAlts, boolean strictWithSubDomains) throws SSLException */ + Log.d(TAG, "Hooking AbstractVerifier.verify(String, String[], String[], boolean) for: "); + + try { + classLoader.loadClass("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier"); + findAndHookMethod("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier", classLoader, "verify", + String.class, String[].class, String[].class, boolean.class, + new XC_MethodReplacement() { + @Override + protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { + return null; + } + }); + } catch (ClassNotFoundException e) { + // pass + Log.d(TAG, "httpclientandroidlib not found in -- not hooking"); + } + } + + private static class ImSureItsLegitTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public List checkServerTrusted(X509Certificate[] chain, String authType, String host) throws CertificateException { + ArrayList list = new ArrayList(); + return list; + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + + private static class ImSureItsLegitHostnameVerifier implements HostnameVerifier { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + /* This class creates a SSLSocket that trusts everyone. */ + public static class TrustAllSSLSocketFactory extends SSLSocketFactory { + + SSLContext sslContext = SSLContext.getInstance("TLS"); + + public TrustAllSSLSocketFactory(KeyStore truststore) throws + NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { + super(truststore); + + TrustManager tm = new X509TrustManager() { + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + 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(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/mobi/acpm/inspeckage/hooks/LRUCache.java b/app/src/main/java/mobi/acpm/inspeckage/hooks/LRUCache.java new file mode 100644 index 0000000..f55c68a --- /dev/null +++ b/app/src/main/java/mobi/acpm/inspeckage/hooks/LRUCache.java @@ -0,0 +1,18 @@ +package mobi.acpm.inspeckage.hooks; + + +import java.util.LinkedHashMap; + +public class LRUCache extends LinkedHashMap { + private int maxEntries; + + public LRUCache(int maxEntries) { + super(16, 0.75f, true); + this.maxEntries = maxEntries; + } + + @Override + protected boolean removeEldestEntry(Entry eldest) { + return size() > maxEntries; + } +} \ No newline at end of file diff --git a/app/src/main/java/mobi/acpm/inspeckage/hooks/ProxyHook.java b/app/src/main/java/mobi/acpm/inspeckage/hooks/ProxyHook.java index 561c32c..c0e32e9 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/hooks/ProxyHook.java +++ b/app/src/main/java/mobi/acpm/inspeckage/hooks/ProxyHook.java @@ -1,12 +1,19 @@ package mobi.acpm.inspeckage.hooks; +import android.content.Context; import android.os.Build; +import android.util.AttributeSet; +import android.util.Log; +import android.webkit.WebView; import org.apache.http.HttpHost; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.impl.client.DefaultHttpClient; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.net.URI; +import java.net.URL; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; @@ -17,6 +24,7 @@ import static de.robv.android.xposed.XposedBridge.hookAllConstructors; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; +import static mobi.acpm.inspeckage.util.WebViewHttpProxy.setProxy; /** * Created by acpm on 21/11/15. @@ -72,11 +80,25 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { Module.logError(e); } + try{ + findAndHookMethod("java.net.URL", loadPackageParam.classLoader, "openConnection", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) + throws Throwable { + URL url = (URL) param.thisObject; + Log.d("overjt", url.toString()); + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress( sPrefs.getString("host", null), Integer.parseInt(sPrefs.getString("port", null)))); + param.setResult(url.openConnection(proxy)); + } + }); + }catch(Error e){ + Log.d("overjt", "falló algo"); + } + hookAllConstructors(XposedHelpers.findClass("org.apache.http.impl.client.DefaultHttpClient", loadPackageParam.classLoader), new XC_MethodHook() { protected void afterHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); - if (sPrefs.getBoolean("switch_proxy", false)) { String proxyHost = sPrefs.getString("host", null); int proxyPort; @@ -92,5 +114,65 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable { } } }); + + try { + hookWebView(loadPackageParam.classLoader, loadPackageParam.packageName); + }catch (Throwable exception) { + } + } + + private static Class findClass(String className, ClassLoader classLoader) { + try { + return XposedHelpers.findClass(className, classLoader); + } catch (Throwable exception) { + } + return null; + } + + private static void hookWebView(final ClassLoader classLoader, final String packageName) { + final String[] webviewList = { + "android.webkit.WebView", // android webview + "com.tencent.smtt.sdk.WebView", // tencent x5 + "com.uc.webview.export.WebView", // UC + WebView.class.toString() + }; + + LRUCache hookedClassLoader = new LRUCache<>(10000); + + for (int i = 0; i < webviewList.length; i++) { + final String className = webviewList[i]; + final Class cla = findClass(className, classLoader); + if(cla == null){ + continue; + } + String key = cla.getName() + "@" + cla.getClassLoader().hashCode(); + boolean hooked; + if (hookedClassLoader.get(key) == null) { + hookedClassLoader.put(key, true); + hooked = true; + }else{ + hooked = false; + } + if (cla != null && hooked) { + XposedBridge.log(packageName + " hook " + className + "@" + cla.getClassLoader().getClass().getName() + ":" + cla.getClassLoader().hashCode()); + XC_MethodHook WebserviceProxyHook = new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + loadPrefs(); + if (sPrefs.getBoolean("switch_proxy", false)) { + WebView wv = (WebView) param.thisObject; + setProxy(wv, sPrefs.getString("host", null), Integer.parseInt(sPrefs.getString("port", null)), "android.app.Application"); + } + } + }; + + XposedHelpers.findAndHookConstructor(cla, Context.class, WebserviceProxyHook); + XposedHelpers.findAndHookConstructor(cla, Context.class, AttributeSet.class, WebserviceProxyHook); + XposedHelpers.findAndHookConstructor(cla, Context.class, AttributeSet.class, int.class, WebserviceProxyHook); + XposedHelpers.findAndHookConstructor(cla, Context.class, AttributeSet.class, int.class, int.class, WebserviceProxyHook); + XposedHelpers.findAndHookConstructor(cla, Context.class, AttributeSet.class, int.class, boolean.class, WebserviceProxyHook); + } + } } } diff --git a/app/src/main/java/mobi/acpm/inspeckage/hooks/SSLPinningHook.java b/app/src/main/java/mobi/acpm/inspeckage/hooks/SSLPinningHook.java index 823ee4b..11b5ceb 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/hooks/SSLPinningHook.java +++ b/app/src/main/java/mobi/acpm/inspeckage/hooks/SSLPinningHook.java @@ -1,5 +1,7 @@ package mobi.acpm.inspeckage.hooks; +import android.util.Log; + import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.ssl.SSLSocketFactory; @@ -8,10 +10,13 @@ import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.List; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; @@ -46,6 +51,7 @@ public static void loadPrefs() { public static void initAllHooks(final XC_LoadPackage.LoadPackageParam loadPackageParam) { + // --- Java Secure Socket Extension (JSSE) --- //TrustManagerFactory.getTrustManagers >> EmptyTrustManager @@ -227,11 +233,19 @@ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } + public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine) throws CertificateException { + } + @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { + public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { } + public List checkServerTrusted(X509Certificate[] certs, String authType, String hostname) throws CertificateException { + return Arrays.asList(new X509Certificate[0]); + } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; diff --git a/app/src/main/java/mobi/acpm/inspeckage/hooks/WebViewHook.java b/app/src/main/java/mobi/acpm/inspeckage/hooks/WebViewHook.java index 58b2fdc..2c86fcc 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/hooks/WebViewHook.java +++ b/app/src/main/java/mobi/acpm/inspeckage/hooks/WebViewHook.java @@ -1,5 +1,6 @@ package mobi.acpm.inspeckage.hooks; +import android.content.res.XResources; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; @@ -33,21 +34,6 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } }); - findAndHookMethod(WebView.class, "loadUrl", - String.class, new XC_MethodHook() { - - protected void beforeHookedMethod(MethodHookParam param) throws Throwable { - - sb = new StringBuilder(); - WebView wv = (WebView) param.thisObject; - sb.append("Load URL: " + param.args[0]); - - sb.append(checkSettings(wv)); - - XposedBridge.log(TAG + sb.toString()); - } - }); - findAndHookMethod(WebView.class, "loadData", String.class, String.class, String.class, new XC_MethodHook() { @@ -89,6 +75,16 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable { } }); + //XResources.setSystemWideReplacement("android", "string", "config_webViewPackageName", "com.google.android.webview"); + +// findAndHookMethod("android.webkit.WebViewFactory", null, "getWebViewPackageName", new XC_MethodHook() { +// @Override +// protected void beforeHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { +// XposedBridge.log("getWebViewPackageName"); +// param.setResult("com.google.android.webview"); +// } +// }); + } static String checkSettings(WebView wv) { diff --git a/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageReceiver.java b/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageReceiver.java index 55853f2..0ab3497 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageReceiver.java +++ b/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageReceiver.java @@ -5,8 +5,11 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; +import android.preference.PreferenceManager; +import android.util.Log; import android.webkit.WebView; import java.lang.reflect.Field; @@ -156,13 +159,13 @@ public void onReceive(Context context, Intent intent) { String tree = Util.FileTree(activity.getApplicationInfo().dataDir, ""); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this.activity); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("tree",tree); + editor.apply(); + Intent i = new Intent("mobi.acpm.inspeckage.INSPECKAGE_WEB"); i.putExtra("action", "fileTree"); - float m = (float) tree.length() / 3; - String sub1 = tree.substring(0, (int) m); - String sub2 = tree.substring((int) m, tree.length()); - //talvez tenha que dividir pq a arvore pode ficar muito grande para ser enviada via intent - i.putExtra("tree", tree); activity.sendBroadcast(i, null); Util.sb = new StringBuilder(); diff --git a/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageWebReceiver.java b/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageWebReceiver.java index 2d93b34..7e252c9 100644 --- a/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageWebReceiver.java +++ b/app/src/main/java/mobi/acpm/inspeckage/receivers/InspeckageWebReceiver.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.preference.PreferenceManager; import mobi.acpm.inspeckage.Module; import mobi.acpm.inspeckage.util.Config; @@ -29,8 +30,7 @@ public void onReceive(Context context, Intent intent) { String action = intent.getExtras().getString("action"); if(action.equals("fileTree")){ - - String sub1 = intent.getExtras().getString("tree"); + String sub1 = mPrefs.getString("tree",""); String script = "