├── .gitattributes ├── .gitignore ├── Readme.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── XposedBridgeApi.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── trust │ │ └── just │ │ └── justtrustme │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── xposed_init │ ├── java │ └── just │ │ └── trust │ │ └── me │ │ └── Main.java │ └── res │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── build.sh ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | /bin/ 3 | app/build/ 4 | app/src/main/bin/ 5 | app/src/main/gen/ 6 | build/ 7 | .idea/ 8 | .gradle 9 | /local.properties 10 | /.idea/workspace.xml 11 | .DS_Store 12 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # JustTrustMe-master 2 | 默认的JustTrustMe只会应用启动后Hook一次,因此在这基础上修改了log日志打印位置,使得每一次Hook函数调用都会输出实时日志,便于追踪SSL函数 3 | 4 | ![](https://raw.githubusercontent.com/la0s/la0s.github.io/master/screenshots/JustTrustMe-master.png) 5 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion '28.0.1' 6 | useLibrary 'org.apache.http.legacy' 7 | defaultConfig { 8 | applicationId 'just.trust.me' 9 | minSdkVersion 16 10 | targetSdkVersion 22 11 | versionCode 3 12 | versionName '.3' 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | } 19 | } 20 | productFlavors { 21 | } 22 | } 23 | 24 | dependencies { 25 | provided fileTree(dir: 'libs', include: ['*.jar']) 26 | } 27 | -------------------------------------------------------------------------------- /app/libs/XposedBridgeApi.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/la0s/JustTrustMe-master/d0072cf6f1ccae0c7dec020840c1e46c84bfb0e3/app/libs/XposedBridgeApi.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/fuzion24/bin/android_sdk_home/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/me/trust/just/justtrustme/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.trust.just.justtrustme; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 12 | 15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | just.trust.me.Main -------------------------------------------------------------------------------- /app/src/main/java/just/trust/me/Main.java: -------------------------------------------------------------------------------- 1 | package just.trust.me; 2 | 3 | import android.content.Context; 4 | import android.net.http.SslError; 5 | import android.util.Log; 6 | import android.webkit.SslErrorHandler; 7 | import android.webkit.WebView; 8 | 9 | import org.apache.http.conn.ClientConnectionManager; 10 | import org.apache.http.conn.scheme.HostNameResolver; 11 | import org.apache.http.conn.scheme.PlainSocketFactory; 12 | import org.apache.http.conn.scheme.Scheme; 13 | import org.apache.http.conn.scheme.SchemeRegistry; 14 | import org.apache.http.conn.ssl.SSLSocketFactory; 15 | import org.apache.http.impl.client.DefaultHttpClient; 16 | import org.apache.http.impl.conn.SingleClientConnManager; 17 | import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 18 | import org.apache.http.params.HttpParams; 19 | 20 | import java.io.IOException; 21 | import java.net.Socket; 22 | import java.net.UnknownHostException; 23 | import java.security.KeyManagementException; 24 | import java.security.KeyStore; 25 | import java.security.KeyStoreException; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.security.SecureRandom; 28 | import java.security.UnrecoverableKeyException; 29 | import java.security.cert.CertificateException; 30 | import java.security.cert.X509Certificate; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | import javax.net.ssl.HostnameVerifier; 35 | import javax.net.ssl.KeyManager; 36 | import javax.net.ssl.SSLContext; 37 | import javax.net.ssl.SSLSession; 38 | import javax.net.ssl.TrustManager; 39 | import javax.net.ssl.X509TrustManager; 40 | 41 | import de.robv.android.xposed.IXposedHookLoadPackage; 42 | import de.robv.android.xposed.XC_MethodHook; 43 | import de.robv.android.xposed.XC_MethodReplacement; 44 | import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; 45 | 46 | import static de.robv.android.xposed.XposedHelpers.callMethod; 47 | import static de.robv.android.xposed.XposedHelpers.callStaticMethod; 48 | import static de.robv.android.xposed.XposedHelpers.findAndHookConstructor; 49 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; 50 | import static de.robv.android.xposed.XposedHelpers.findClass; 51 | import static de.robv.android.xposed.XposedHelpers.getObjectField; 52 | import static de.robv.android.xposed.XposedHelpers.newInstance; 53 | import static de.robv.android.xposed.XposedHelpers.setObjectField; 54 | 55 | public class Main implements IXposedHookLoadPackage { 56 | 57 | private static final String TAG = "JustTrustMe"; 58 | String currentPackageName = ""; 59 | 60 | public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable { 61 | 62 | currentPackageName = lpparam.packageName; 63 | 64 | 65 | 66 | /* Apache Hooks */ 67 | /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ 68 | /* public DefaultHttpClient() */ 69 | 70 | findAndHookConstructor(DefaultHttpClient.class, new XC_MethodHook() { 71 | @Override 72 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 73 | Log.d(TAG, "Hooking DefaultHTTPClient for: " + currentPackageName); 74 | 75 | setObjectField(param.thisObject, "defaultParams", null); 76 | setObjectField(param.thisObject, "connManager", getSCCM()); 77 | } 78 | }); 79 | 80 | /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ 81 | /* public DefaultHttpClient(HttpParams params) */ 82 | 83 | findAndHookConstructor(DefaultHttpClient.class, HttpParams.class, new XC_MethodHook() { 84 | @Override 85 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 86 | Log.d(TAG, "Hooking DefaultHTTPClient(HttpParams) for: " + currentPackageName); 87 | 88 | setObjectField(param.thisObject, "defaultParams", (HttpParams) param.args[0]); 89 | setObjectField(param.thisObject, "connManager", getSCCM()); 90 | } 91 | }); 92 | 93 | /* external/apache-http/src/org/apache/http/impl/client/DefaultHttpClient.java */ 94 | /* public DefaultHttpClient(ClientConnectionManager conman, HttpParams params) */ 95 | 96 | findAndHookConstructor(DefaultHttpClient.class, ClientConnectionManager.class, HttpParams.class, new XC_MethodHook() { 97 | @Override 98 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 99 | Log.d(TAG, "Hooking DefaultHTTPClient(ClientConnectionManager, HttpParams) for: " + currentPackageName); 100 | 101 | HttpParams params = (HttpParams) param.args[1]; 102 | 103 | setObjectField(param.thisObject, "defaultParams", params); 104 | setObjectField(param.thisObject, "connManager", getCCM(param.args[0], params)); 105 | } 106 | }); 107 | 108 | /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ 109 | /* public SSLSocketFactory( ... ) */ 110 | 111 | findAndHookConstructor(SSLSocketFactory.class, String.class, KeyStore.class, String.class, KeyStore.class, 112 | SecureRandom.class, HostNameResolver.class, new XC_MethodHook() { 113 | @Override 114 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 115 | Log.d(TAG, "Hooking SSLSocketFactory(String, KeyStore, String, KeyStore) for: " + currentPackageName); 116 | 117 | String algorithm = (String) param.args[0]; 118 | KeyStore keystore = (KeyStore) param.args[1]; 119 | String keystorePassword = (String) param.args[2]; 120 | SecureRandom random = (SecureRandom) param.args[4]; 121 | 122 | KeyManager[] keymanagers = null; 123 | TrustManager[] trustmanagers = null; 124 | 125 | if (keystore != null) { 126 | keymanagers = (KeyManager[]) callStaticMethod(SSLSocketFactory.class, "createKeyManagers", keystore, keystorePassword); 127 | } 128 | 129 | trustmanagers = new TrustManager[]{new ImSureItsLegitTrustManager()}; 130 | 131 | setObjectField(param.thisObject, "sslcontext", SSLContext.getInstance(algorithm)); 132 | callMethod(getObjectField(param.thisObject, "sslcontext"), "init", keymanagers, trustmanagers, random); 133 | setObjectField(param.thisObject, "socketfactory", 134 | callMethod(getObjectField(param.thisObject, "sslcontext"), "getSocketFactory")); 135 | } 136 | 137 | }); 138 | 139 | 140 | /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ 141 | /* public static SSLSocketFactory getSocketFactory() */ 142 | 143 | findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", lpparam.classLoader, "getSocketFactory", new XC_MethodReplacement() { 144 | @Override 145 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 146 | Log.d(TAG, "Hooking static SSLSocketFactory(String, KeyStore, String, KeyStore) for: " + currentPackageName); 147 | return (SSLSocketFactory) newInstance(SSLSocketFactory.class); 148 | } 149 | }); 150 | 151 | /* external/apache-http/src/org/apache/http/conn/ssl/SSLSocketFactory.java */ 152 | /* public boolean isSecure(Socket) */ 153 | 154 | findAndHookMethod("org.apache.http.conn.ssl.SSLSocketFactory", lpparam.classLoader, "isSecure", Socket.class, new XC_MethodReplacement() { 155 | @Override 156 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 157 | Log.d(TAG, "Hooking SSLSocketFactory(Socket) for: " + currentPackageName); 158 | return true; 159 | } 160 | }); 161 | 162 | /* JSSE Hooks */ 163 | /* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */ 164 | /* public final TrustManager[] getTrustManager() */ 165 | 166 | findAndHookMethod("javax.net.ssl.TrustManagerFactory", lpparam.classLoader, "getTrustManagers", new XC_MethodHook() { 167 | @Override 168 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 169 | Log.d(TAG, "Hooking TrustManagerFactory.getTrustManagers() for: " + currentPackageName); 170 | 171 | if (hasTrustManagerImpl()) { 172 | Class cls = findClass("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader); 173 | 174 | TrustManager[] managers = (TrustManager[]) param.getResult(); 175 | if (managers.length > 0 && cls.isInstance(managers[0])) 176 | return; 177 | } 178 | 179 | param.setResult(new TrustManager[]{new ImSureItsLegitTrustManager()}); 180 | } 181 | }); 182 | 183 | /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ 184 | /* public void setDefaultHostnameVerifier(HostnameVerifier) */ 185 | 186 | findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setDefaultHostnameVerifier", 187 | HostnameVerifier.class, new XC_MethodReplacement() { 188 | @Override 189 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 190 | Log.d(TAG, "Hooking HttpsURLConnection.setDefaultHostnameVerifier for: " + currentPackageName); 191 | return null; 192 | } 193 | }); 194 | 195 | /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ 196 | /* public void setSSLSocketFactory(SSLSocketFactory) */ 197 | 198 | findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setSSLSocketFactory", javax.net.ssl.SSLSocketFactory.class, 199 | new XC_MethodReplacement() { 200 | @Override 201 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 202 | Log.d(TAG, "Hooking HttpsURLConnection.setDefaultHostnameVerifier for: " + currentPackageName); 203 | return null; 204 | } 205 | }); 206 | 207 | /* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */ 208 | /* public void setHostnameVerifier(HostNameVerifier) */ 209 | 210 | findAndHookMethod("javax.net.ssl.HttpsURLConnection", lpparam.classLoader, "setHostnameVerifier", HostnameVerifier.class, 211 | new XC_MethodReplacement() { 212 | @Override 213 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 214 | Log.d(TAG, "Hooking HttpsURLConnection.setHostnameVerifier for: " + currentPackageName); 215 | return null; 216 | } 217 | }); 218 | 219 | 220 | /* WebView Hooks */ 221 | /* frameworks/base/core/java/android/webkit/WebViewClient.java */ 222 | /* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */ 223 | 224 | 225 | findAndHookMethod("android.webkit.WebViewClient", lpparam.classLoader, "onReceivedSslError", 226 | WebView.class, SslErrorHandler.class, SslError.class, new XC_MethodReplacement() { 227 | @Override 228 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 229 | Log.d(TAG, "Hooking WebViewClient.onReceivedSslError(WebView, SslErrorHandler, SslError) for: " + currentPackageName); 230 | ((android.webkit.SslErrorHandler) param.args[1]).proceed(); 231 | return null; 232 | } 233 | }); 234 | 235 | /* frameworks/base/core/java/android/webkit/WebViewClient.java */ 236 | /* public void onReceivedError(WebView, int, String, String) */ 237 | 238 | 239 | findAndHookMethod("android.webkit.WebViewClient", lpparam.classLoader, "onReceivedError", 240 | WebView.class, int.class, String.class, String.class, new XC_MethodReplacement() { 241 | @Override 242 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 243 | Log.d(TAG, "Hooking WebViewClient.onReceivedSslError(WebView, int, string, string) for: " + currentPackageName); 244 | return null; 245 | } 246 | }); 247 | 248 | //SSLContext.init >> (null,ImSureItsLegitTrustManager,null) 249 | findAndHookMethod("javax.net.ssl.SSLContext", lpparam.classLoader, "init", KeyManager[].class, TrustManager[].class, SecureRandom.class, new XC_MethodHook() { 250 | 251 | @Override 252 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 253 | Log.d(TAG, "Hooking javax.net.ssl.SSLContext.init for: " + currentPackageName); 254 | 255 | param.args[0] = null; 256 | param.args[1] = new TrustManager[]{new ImSureItsLegitTrustManager()}; 257 | param.args[2] = null; 258 | 259 | } 260 | }); 261 | 262 | // Multi-dex support: https://github.com/rovo89/XposedBridge/issues/30#issuecomment-68486449 263 | findAndHookMethod("android.app.Application", 264 | lpparam.classLoader, 265 | "attach", 266 | Context.class, 267 | new XC_MethodHook() { 268 | @Override 269 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 270 | // Hook OkHttp or third party libraries. 271 | Context context = (Context) param.args[0]; 272 | processOkHttp(context.getClassLoader()); 273 | processHttpClientAndroidLib(context.getClassLoader()); 274 | processXutils(context.getClassLoader()); 275 | } 276 | } 277 | ); 278 | 279 | /* Only for newer devices should we try to hook TrustManagerImpl */ 280 | if (hasTrustManagerImpl()) { 281 | /* TrustManagerImpl Hooks */ 282 | /* external/conscrypt/src/platform/java/org/conscrypt/TrustManagerImpl.java */ 283 | 284 | 285 | /* public void checkServerTrusted(X509Certificate[] chain, String authType) */ 286 | findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, 287 | "checkServerTrusted", X509Certificate[].class, String.class, 288 | new XC_MethodReplacement() { 289 | @Override 290 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 291 | Log.d(TAG, "Hooking com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(X509Certificate[] chain, String authType) for: " + currentPackageName); 292 | return 0; 293 | } 294 | }); 295 | 296 | /* public List checkServerTrusted(X509Certificate[] chain, 297 | String authType, String host) throws CertificateException */ 298 | findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, 299 | "checkServerTrusted", X509Certificate[].class, String.class, 300 | String.class, new XC_MethodReplacement() { 301 | @Override 302 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 303 | Log.d(TAG, "Hooking com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(X509Certificate[] chain, String authType, String host) for: " + currentPackageName); 304 | ArrayList list = new ArrayList(); 305 | return list; 306 | } 307 | }); 308 | 309 | 310 | /* public List checkServerTrusted(X509Certificate[] chain, 311 | String authType, SSLSession session) throws CertificateException */ 312 | findAndHookMethod("com.android.org.conscrypt.TrustManagerImpl", lpparam.classLoader, 313 | "checkServerTrusted", X509Certificate[].class, String.class, 314 | SSLSession.class, new XC_MethodReplacement() { 315 | @Override 316 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { 317 | Log.d(TAG, "Hooking com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(X509Certificate[] chain, String authType, SSLSession session) for: " + currentPackageName); 318 | ArrayList list = new ArrayList(); 319 | return list; 320 | } 321 | }); 322 | } 323 | 324 | } // End Hooks 325 | 326 | /* Helpers */ 327 | // Check for TrustManagerImpl class 328 | public boolean hasTrustManagerImpl() { 329 | 330 | try { 331 | Class.forName("com.android.org.conscrypt.TrustManagerImpl"); 332 | } catch (ClassNotFoundException e) { 333 | return false; 334 | } 335 | return true; 336 | } 337 | 338 | private javax.net.ssl.SSLSocketFactory getEmptySSLFactory() { 339 | try { 340 | SSLContext sslContext = SSLContext.getInstance("TLS"); 341 | sslContext.init(null, new TrustManager[]{new ImSureItsLegitTrustManager()}, null); 342 | return sslContext.getSocketFactory(); 343 | } catch (NoSuchAlgorithmException e) { 344 | return null; 345 | } catch (KeyManagementException e) { 346 | return null; 347 | } 348 | } 349 | 350 | //Create a SingleClientConnManager that trusts everyone! 351 | public ClientConnectionManager getSCCM() { 352 | 353 | KeyStore trustStore; 354 | try { 355 | 356 | trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 357 | trustStore.load(null, null); 358 | 359 | SSLSocketFactory sf = new TrustAllSSLSocketFactory(trustStore); 360 | sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 361 | 362 | SchemeRegistry registry = new SchemeRegistry(); 363 | registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 364 | registry.register(new Scheme("https", sf, 443)); 365 | 366 | ClientConnectionManager ccm = new SingleClientConnManager(null, registry); 367 | 368 | return ccm; 369 | 370 | } catch (Exception e) { 371 | return null; 372 | } 373 | } 374 | 375 | //This function creates a ThreadSafeClientConnManager that trusts everyone! 376 | public ClientConnectionManager getTSCCM(HttpParams params) { 377 | 378 | KeyStore trustStore; 379 | try { 380 | 381 | trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 382 | trustStore.load(null, null); 383 | 384 | SSLSocketFactory sf = new TrustAllSSLSocketFactory(trustStore); 385 | sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 386 | 387 | SchemeRegistry registry = new SchemeRegistry(); 388 | registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 389 | registry.register(new Scheme("https", sf, 443)); 390 | 391 | ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); 392 | 393 | return ccm; 394 | 395 | } catch (Exception e) { 396 | return null; 397 | } 398 | } 399 | 400 | //This function determines what object we are dealing with. 401 | public ClientConnectionManager getCCM(Object o, HttpParams params) { 402 | 403 | String className = o.getClass().getSimpleName(); 404 | 405 | if (className.equals("SingleClientConnManager")) { 406 | return getSCCM(); 407 | } else if (className.equals("ThreadSafeClientConnManager")) { 408 | return getTSCCM(params); 409 | } 410 | 411 | return null; 412 | } 413 | 414 | private void processXutils(ClassLoader classLoader) { 415 | 416 | try { 417 | classLoader.loadClass("org.xutils.http.RequestParams"); 418 | findAndHookMethod("org.xutils.http.RequestParams", classLoader, "setSslSocketFactory", javax.net.ssl.SSLSocketFactory.class, new XC_MethodHook() { 419 | @Override 420 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 421 | Log.d(TAG, "Hooking org.xutils.http.RequestParams.setSslSocketFactory(SSLSocketFactory) (3) for: " + currentPackageName); 422 | super.beforeHookedMethod(param); 423 | param.args[0] = getEmptySSLFactory(); 424 | } 425 | }); 426 | findAndHookMethod("org.xutils.http.RequestParams", classLoader, "setHostnameVerifier", HostnameVerifier.class, new XC_MethodHook() { 427 | @Override 428 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 429 | Log.d(TAG, "Hooking org.xutils.http.RequestParams.setHostnameVerifier for: " + currentPackageName); 430 | super.beforeHookedMethod(param); 431 | param.args[0] = new ImSureItsLegitHostnameVerifier(); 432 | } 433 | }); 434 | } catch (Exception e) { 435 | Log.d(TAG, "org.xutils.http.RequestParams not found in " + currentPackageName + "-- not hooking"); 436 | } 437 | } 438 | 439 | void processOkHttp(ClassLoader classLoader) { 440 | /* hooking OKHTTP by SQUAREUP */ 441 | /* com/squareup/okhttp/CertificatePinner.java available online @ https://github.com/square/okhttp/blob/master/okhttp/src/main/java/com/squareup/okhttp/CertificatePinner.java */ 442 | /* public void check(String hostname, List peerCertificates) throws SSLPeerUnverifiedException{}*/ 443 | /* Either returns true or a exception so blanket return true */ 444 | /* Tested against version 2.5 */ 445 | 446 | 447 | try { 448 | classLoader.loadClass("com.squareup.okhttp.CertificatePinner"); 449 | findAndHookMethod("com.squareup.okhttp.CertificatePinner", 450 | classLoader, 451 | "check", 452 | String.class, 453 | List.class, 454 | new XC_MethodReplacement() { 455 | @Override 456 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { 457 | Log.d(TAG, "Hooking com.squareup.okhttp.CertificatePinner.check(String,List) (2.5) for: " + currentPackageName); 458 | return true; 459 | } 460 | }); 461 | } catch (ClassNotFoundException e) { 462 | // pass 463 | Log.d(TAG, "OKHTTP 2.5 not found in " + currentPackageName + "-- not hooking"); 464 | } 465 | 466 | //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/CertificatePinner.java#L144 467 | 468 | 469 | try { 470 | classLoader.loadClass("okhttp3.CertificatePinner"); 471 | findAndHookMethod("okhttp3.CertificatePinner", 472 | classLoader, 473 | "check", 474 | String.class, 475 | List.class, 476 | new XC_MethodReplacement() { 477 | @Override 478 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { 479 | Log.d(TAG, "Hooking okhttp3.CertificatePinner.check(String,List) (3.x) for: " + currentPackageName); 480 | return null; 481 | } 482 | }); 483 | } catch (ClassNotFoundException e) { 484 | Log.d(TAG, "OKHTTP 3.x not found in " + currentPackageName + " -- not hooking"); 485 | // pass 486 | } 487 | 488 | //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/internal/tls/OkHostnameVerifier.java 489 | try { 490 | classLoader.loadClass("okhttp3.internal.tls.OkHostnameVerifier"); 491 | findAndHookMethod("okhttp3.internal.tls.OkHostnameVerifier", 492 | classLoader, 493 | "verify", 494 | String.class, 495 | javax.net.ssl.SSLSession.class, 496 | new XC_MethodReplacement() { 497 | @Override 498 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { 499 | Log.d(TAG, "Hooking okhttp3.internal.tls.OkHostnameVerifier.verify(String, SSLSession) for: " + currentPackageName); 500 | return true; 501 | } 502 | }); 503 | } catch (ClassNotFoundException e) { 504 | Log.d(TAG, "OKHTTP 3.x not found in " + currentPackageName + " -- not hooking OkHostnameVerifier.verify(String, SSLSession)"); 505 | // pass 506 | } 507 | 508 | //https://github.com/square/okhttp/blob/parent-3.0.1/okhttp/src/main/java/okhttp3/internal/tls/OkHostnameVerifier.java 509 | try { 510 | classLoader.loadClass("okhttp3.internal.tls.OkHostnameVerifier"); 511 | findAndHookMethod("okhttp3.internal.tls.OkHostnameVerifier", 512 | classLoader, 513 | "verify", 514 | String.class, 515 | java.security.cert.X509Certificate.class, 516 | new XC_MethodReplacement() { 517 | @Override 518 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { 519 | Log.d(TAG, "Hooking okhttp3.internal.tls.OkHostnameVerifier.verify(String, X509) for: " + currentPackageName); 520 | return true; 521 | } 522 | }); 523 | } catch (ClassNotFoundException e) { 524 | Log.d(TAG, "OKHTTP 3.x not found in " + currentPackageName + " -- not hooking OkHostnameVerifier.verify(String, X509)("); 525 | // pass 526 | } 527 | } 528 | 529 | void processHttpClientAndroidLib(ClassLoader classLoader) { 530 | /* httpclientandroidlib Hooks */ 531 | /* public final void verify(String host, String[] cns, String[] subjectAlts, boolean strictWithSubDomains) throws SSLException */ 532 | 533 | 534 | try { 535 | classLoader.loadClass("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier"); 536 | findAndHookMethod("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier", classLoader, "verify", 537 | String.class, String[].class, String[].class, boolean.class, 538 | new XC_MethodReplacement() { 539 | @Override 540 | protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { 541 | Log.d(TAG, "Hooking AbstractVerifier.verify(String, String[], String[], boolean) for: " + currentPackageName); 542 | return null; 543 | } 544 | }); 545 | } catch (ClassNotFoundException e) { 546 | // pass 547 | Log.d(TAG, "httpclientandroidlib not found in " + currentPackageName + "-- not hooking"); 548 | } 549 | } 550 | 551 | private class ImSureItsLegitTrustManager implements X509TrustManager { 552 | @Override 553 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 554 | } 555 | 556 | @Override 557 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 558 | } 559 | 560 | @Override 561 | public X509Certificate[] getAcceptedIssuers() { 562 | return new X509Certificate[0]; 563 | } 564 | } 565 | 566 | private class ImSureItsLegitHostnameVerifier implements HostnameVerifier { 567 | 568 | @Override 569 | public boolean verify(String hostname, SSLSession session) { 570 | return true; 571 | } 572 | } 573 | 574 | /* This class creates a SSLSocket that trusts everyone. */ 575 | public class TrustAllSSLSocketFactory extends SSLSocketFactory { 576 | 577 | SSLContext sslContext = SSLContext.getInstance("TLS"); 578 | 579 | public TrustAllSSLSocketFactory(KeyStore truststore) throws 580 | NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { 581 | super(truststore); 582 | 583 | TrustManager tm = new X509TrustManager() { 584 | 585 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 586 | } 587 | 588 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 589 | } 590 | 591 | public X509Certificate[] getAcceptedIssuers() { 592 | return null; 593 | } 594 | }; 595 | 596 | sslContext.init(null, new TrustManager[]{tm}, null); 597 | } 598 | 599 | @Override 600 | public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { 601 | return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); 602 | } 603 | 604 | @Override 605 | public Socket createSocket() throws IOException { 606 | return sslContext.getSocketFactory().createSocket(); 607 | } 608 | } 609 | } 610 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JustTrustMe 5 | Hello world! 6 | Settings 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | APK_PATH="bin/JustTrustMe.apk" 2 | ./gradlew assembleRelease && cp app/build/outputs/apk/app-release-unsigned.apk $APK_PATH && signapk $APK_PATH 3 | 4 | #adb install -r bin/AndroidVTS.apk 5 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Mon Jun 26 14:34:35 CST 2017 16 | systemProp.http.proxyHost=127.0.0.1 17 | systemProp.http.proxyPort=1080 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/la0s/JustTrustMe-master/d0072cf6f1ccae0c7dec020840c1e46c84bfb0e3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Apr 08 16:14:51 PDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------