/* * This script combines, fixes & extends a long list of other scripts, most notably including: * * - https://codeshare.frida.re/@akabe1/frida-multiple-unpinning/ * - https://codeshare.frida.re/@avltree9798/universal-android-ssl-pinning-bypass/ * - https://pastebin.com/TVJD63uM * - https://codeshare.frida.re/@dzonerzy/fridantiroot/ * - https://github.com/AshenOneYe/FridaAntiRootDetection/blob/main/antiroot.js */ setTimeout(function () { Java.perform(function () { console.log("---"); console.log("Unpinning Android app..."); /// -- Generic hook to protect against SSLPeerUnverifiedException -- /// // In some cases, with unusual cert pinning approaches, or heavy obfuscation, we can't // match the real method & package names. This is a problem! Fortunately, we can still // always match built-in types, so here we spot all failures that use the built-in cert // error type (notably this includes OkHttp), and after the first failure, we dynamically // generate & inject a patch to completely disable the method that threw the error. try { const UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException'); UnverifiedCertError.$init.implementation = function (str) { console.log(' --> Unexpected SSL verification failure, adding dynamic patch...'); try { const stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace(); const exceptionStackIndex = stackTrace.findIndex(stack => stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException" ); const callingFunctionStack = stackTrace[exceptionStackIndex + 1]; const className = callingFunctionStack.getClassName(); const methodName = callingFunctionStack.getMethodName(); console.log(` Thrown by ${className}->${methodName}`); const callingClass = Java.use(className); const callingMethod = callingClass[methodName]; if (callingMethod.implementation) return; // Already patched by Frida - skip it console.log(' Attempting to patch automatically...'); const returnTypeName = callingMethod.returnType.type; callingMethod.implementation = function () { console.log(` --> Bypassing ${className}->${methodName} (automatic exception patch)`); // This is not a perfect fix! Most unknown cases like this are really just // checkCert(cert) methods though, so doing nothing is perfect, and if we // do need an actual return value then this is probably the best we can do, // and at least we're logging the method name so you can patch it manually: if (returnTypeName === 'void') { return; } else { return null; } }; console.log(` [+] ${className}->${methodName} (automatic exception patch)`); } catch (e) { console.log(' [ ] Failed to automatically patch failure'); } return this.$init(str); }; console.log('[+] SSLPeerUnverifiedException auto-patcher'); } catch (err) { console.log('[ ] SSLPeerUnverifiedException auto-patcher'); } /// -- Specific targeted hooks: -- /// // HttpsURLConnection try { const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) { console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)'); return; // Do nothing, i.e. don't change the hostname verifier }; console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)'); } catch (err) { console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)'); } try { const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) { console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)'); return; // Do nothing, i.e. don't change the SSL socket factory }; console.log('[+] HttpsURLConnection (setSSLSocketFactory)'); } catch (err) { console.log('[ ] HttpsURLConnection (setSSLSocketFactory)'); } try { const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection"); HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) { console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)'); return; // Do nothing, i.e. don't change the hostname verifier }; console.log('[+] HttpsURLConnection (setHostnameVerifier)'); } catch (err) { console.log('[ ] HttpsURLConnection (setHostnameVerifier)'); } // SSLContext try { const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); const SSLContext = Java.use('javax.net.ssl.SSLContext'); const TrustManager = Java.registerClass({ // Implement a custom TrustManager name: 'dev.asd.test.TrustManager', implements: [X509TrustManager], methods: { checkClientTrusted: function (chain, authType) { }, checkServerTrusted: function (chain, authType) { }, getAcceptedIssuers: function () { return []; } } }); // Prepare the TrustManager array to pass to SSLContext.init() const TrustManagers = [TrustManager.$new()]; // Get a handle on the init() on the SSLContext class const SSLContext_init = SSLContext.init.overload( '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom' ); // Override the init method, specifying the custom TrustManager SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) { console.log(' --> Bypassing Trustmanager (Android < 7) request'); SSLContext_init.call(this, keyManager, TrustManagers, secureRandom); }; console.log('[+] SSLContext'); } catch (err) { console.log('[ ] SSLContext'); } // TrustManagerImpl (Android > 7) try { const array_list = Java.use("java.util.ArrayList"); const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl'); // This step is notably what defeats the most common case: network security config TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) { console.log(' --> Bypassing TrustManagerImpl checkTrusted '); return array_list.$new(); } TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) { console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host); return untrustedChain; }; console.log('[+] TrustManagerImpl'); } catch (err) { console.log('[ ] TrustManagerImpl'); } // OkHTTPv3 (quadruple bypass) try { // Bypass OkHTTPv3 {1} const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner'); okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { console.log(' --> Bypassing OkHTTPv3 (list): ' + a); return; }; console.log('[+] OkHTTPv3 (list)'); } catch (err) { console.log('[ ] OkHTTPv3 (list)'); } try { // Bypass OkHTTPv3 {2} // This method of CertificatePinner.check could be found in some old Android app const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner'); okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) { console.log(' --> Bypassing OkHTTPv3 (cert): ' + a); return; }; console.log('[+] OkHTTPv3 (cert)'); } catch (err) { console.log('[ ] OkHTTPv3 (cert)'); } try { // Bypass OkHTTPv3 {3} const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner'); okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) { console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a); return; }; console.log('[+] OkHTTPv3 (cert array)'); } catch (err) { console.log('[ ] OkHTTPv3 (cert array)'); } try { // Bypass OkHTTPv3 {4} const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner'); okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) { console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a); return; }; console.log('[+] OkHTTPv3 ($okhttp)'); } catch (err) { console.log('[ ] OkHTTPv3 ($okhttp)'); } // Trustkit (triple bypass) try { // Bypass Trustkit {1} const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a); return true; }; console.log('[+] Trustkit OkHostnameVerifier(SSLSession)'); } catch (err) { console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)'); } try { // Bypass Trustkit {2} const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier'); trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a); return true; }; console.log('[+] Trustkit OkHostnameVerifier(cert)'); } catch (err) { console.log('[ ] Trustkit OkHostnameVerifier(cert)'); } try { // Bypass Trustkit {3} const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager'); trustkit_PinningTrustManager.checkServerTrusted.implementation = function () { console.log(' --> Bypassing Trustkit PinningTrustManager'); }; console.log('[+] Trustkit PinningTrustManager'); } catch (err) { console.log('[ ] Trustkit PinningTrustManager'); } // Appcelerator Titanium try { const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager'); appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () { console.log(' --> Bypassing Appcelerator PinningTrustManager'); }; console.log('[+] Appcelerator PinningTrustManager'); } catch (err) { console.log('[ ] Appcelerator PinningTrustManager'); } // OpenSSLSocketImpl Conscrypt try { const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl'); OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) { console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt'); }; console.log('[+] OpenSSLSocketImpl Conscrypt'); } catch (err) { console.log('[ ] OpenSSLSocketImpl Conscrypt'); } // OpenSSLEngineSocketImpl Conscrypt try { const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl'); OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) { console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b); }; console.log('[+] OpenSSLEngineSocketImpl Conscrypt'); } catch (err) { console.log('[ ] OpenSSLEngineSocketImpl Conscrypt'); } // OpenSSLSocketImpl Apache Harmony try { const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl'); OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) { console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony'); }; console.log('[+] OpenSSLSocketImpl Apache Harmony'); } catch (err) { console.log('[ ] OpenSSLSocketImpl Apache Harmony'); } // PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin) try { const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker'); phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) { console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a); return true; }; console.log('[+] PhoneGap sslCertificateChecker'); } catch (err) { console.log('[ ] PhoneGap sslCertificateChecker'); } // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) try { // Bypass IBM MobileFirst {1} const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient'); WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) { console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert); return; }; console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)'); } catch (err) { console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)'); } try { // Bypass IBM MobileFirst {2} const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient'); WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) { console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert); return; }; console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)'); } catch (err) { console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)'); } // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) try { // Bypass IBM WorkLight {1} const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) { console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a); return; }; console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)'); } catch (err) { console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)'); } try { // Bypass IBM WorkLight {2} const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a); return; }; console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)'); } catch (err) { console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)'); } try { // Bypass IBM WorkLight {3} const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) { console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a); return; }; console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)'); } catch (err) { console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)'); } try { // Bypass IBM WorkLight {4} const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning'); worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a); return true; }; console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)'); } catch (err) { console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)'); } // Conscrypt CertPinManager try { const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager'); conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { console.log(' --> Bypassing Conscrypt CertPinManager: ' + a); return true; }; console.log('[+] Conscrypt CertPinManager'); } catch (err) { console.log('[ ] Conscrypt CertPinManager'); } // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager try { const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager'); cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a); return true; }; console.log('[+] CWAC-Netsecurity CertPinManager'); } catch (err) { console.log('[ ] CWAC-Netsecurity CertPinManager'); } // Worklight Androidgap WLCertificatePinningPlugin try { const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin'); androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) { console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a); return true; }; console.log('[+] Worklight Androidgap WLCertificatePinningPlugin'); } catch (err) { console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin'); } // Netty FingerprintTrustManagerFactory try { const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory'); netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) { console.log(' --> Bypassing Netty FingerprintTrustManagerFactory'); }; console.log('[+] Netty FingerprintTrustManagerFactory'); } catch (err) { console.log('[ ] Netty FingerprintTrustManagerFactory'); } // Squareup CertificatePinner [OkHTTP Bypassing Squareup CertificatePinner (cert): ' + a); return; }; console.log('[+] Squareup CertificatePinner (cert)'); } catch (err) { console.log('[ ] Squareup CertificatePinner (cert)'); } try { // Bypass Squareup CertificatePinner {2} const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner'); Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) { console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a); return; }; console.log('[+] Squareup CertificatePinner (list)'); } catch (err) { console.log('[ ] Squareup CertificatePinner (list)'); } // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) try { // Bypass Squareup OkHostnameVerifier {1} const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier'); Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) { console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a); return true; }; console.log('[+] Squareup OkHostnameVerifier (cert)'); } catch (err) { console.log('[ ] Squareup OkHostnameVerifier (cert)'); } try { // Bypass Squareup OkHostnameVerifier {2} const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier'); Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) { console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a); return true; }; console.log('[+] Squareup OkHostnameVerifier (SSLSession)'); } catch (err) { console.log('[ ] Squareup OkHostnameVerifier (SSLSession)'); } // Android WebViewClient (double bypass) try { // Bypass WebViewClient {1} (deprecated from Android 6) const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient'); AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) { console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)'); }; console.log('[+] Android WebViewClient (SslErrorHandler)'); } catch (err) { console.log('[ ] Android WebViewClient (SslErrorHandler)'); } try { // Bypass WebViewClient {2} const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient'); AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) { console.log(' --> Bypassing Android WebViewClient (WebResourceError)'); }; console.log('[+] Android WebViewClient (WebResourceError)'); } catch (err) { console.log('[ ] Android WebViewClient (WebResourceError)'); } // Apache Cordova WebViewClient try { const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient'); CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) { console.log(' --> Bypassing Apache Cordova WebViewClient'); obj3.proceed(); }; } catch (err) { console.log('[ ] Apache Cordova WebViewClient'); } // Boye AbstractVerifier try { const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier'); boye_AbstractVerifier.verify.implementation = function (host, ssl) { console.log(' --> Bypassing Boye AbstractVerifier: ' + host); }; } catch (err) { console.log('[ ] Boye AbstractVerifier'); } // Appmattus try { const appmatus_Activity = Java.use('com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyInterceptor'); appmatus_Activity['intercept'].implementation = function (a) { console.log(' --> Bypassing Appmattus (Transparency)'); return a.proceed(a.request()); }; console.log('[+] Appmattus (CertificateTransparencyInterceptor)'); } catch (err) { console.log('[ ] Appmattus (CertificateTransparencyInterceptor)'); } try { const CertificateTransparencyTrustManager = Java.use( 'com.appmattus.certificatetransparency.internal.verifier.CertificateTransparencyTrustManager' ); CertificateTransparencyTrustManager['checkServerTrusted'].overload( '[Ljava.security.cert.X509Certificate;', 'java.lang.String' ).implementation = function (x509CertificateArr, str) { console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)'); }; CertificateTransparencyTrustManager['checkServerTrusted'].overload( '[Ljava.security.cert.X509Certificate;', 'java.lang.String', 'java.lang.String' ).implementation = function (x509CertificateArr, str, str2) { console.log(' --> Bypassing Appmattus (CertificateTransparencyTrustManager)'); return Java.use('java.util.ArrayList').$new(); }; console.log('[+] Appmattus (CertificateTransparencyTrustManager)'); } catch (err) { console.log('[ ] Appmattus (CertificateTransparencyTrustManager)'); } console.log("Unpinning setup completed"); console.log("---"); }); }, 0); Java.perform(function() { var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu", "com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager", "com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch", "com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus", "de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot", "com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser", "eu.chainfire.supersu.pro", "com.kingouser.com", "com.topjohnwu.magisk" ]; var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk"]; var RootProperties = { "ro.build.selinux": "1", "ro.debuggable": "0", "service.adb.root": "0", "ro.secure": "1" }; var RootPropertiesKeys = []; for (var k in RootProperties) RootPropertiesKeys.push(k); var PackageManager = Java.use("android.app.ApplicationPackageManager"); var Runtime = Java.use('java.lang.Runtime'); var NativeFile = Java.use('java.io.File'); var String = Java.use('java.lang.String'); var SystemProperties = Java.use('android.os.SystemProperties'); var BufferedReader = Java.use('java.io.BufferedReader'); var ProcessBuilder = Java.use('java.lang.ProcessBuilder'); var StringBuffer = Java.use('java.lang.StringBuffer'); var loaded_classes = Java.enumerateLoadedClassesSync(); send("Loaded " + loaded_classes.length + " classes!"); var useKeyInfo = false; var useProcessManager = false; send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager')); if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) { try { //useProcessManager = true; //var ProcessManager = Java.use('java.lang.ProcessManager'); } catch (err) { send("ProcessManager Hook failed: " + err); } } else { send("ProcessManager hook not loaded"); } var KeyInfo = null; if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) { try { //useKeyInfo = true; //var KeyInfo = Java.use('android.security.keystore.KeyInfo'); } catch (err) { send("KeyInfo Hook failed: " + err); } } else { send("KeyInfo hook not loaded"); } PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) { var shouldFakePackage = (RootPackages.indexOf(pname) > -1); if (shouldFakePackage) { send("Bypass root check for package: " + pname); pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it"; } return this.getPackageInfo.overload('java.lang.String', 'int').call(this, pname, flags); }; NativeFile.exists.implementation = function() { var name = NativeFile.getName.call(this); var shouldFakeReturn = (RootBinaries.indexOf(name) > -1); if (shouldFakeReturn) { send("Bypass return value for binary: " + name); return false; } else { return this.exists.call(this); } }; var exec = Runtime.exec.overload('[Ljava.lang.String;'); var exec1 = Runtime.exec.overload('java.lang.String'); var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;'); var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;'); var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File'); var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File'); exec5.implementation = function(cmd, env, dir) { if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } if (cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } return exec5.call(this, cmd, env, dir); }; exec4.implementation = function(cmdarr, env, file) { for (var i = 0; i < cmdarr.length; i = i + 1) { var tmp_cmd = cmdarr[i]; if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmdarr + " command"); return exec1.call(this, fakeCmd); } if (tmp_cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmdarr + " command"); return exec1.call(this, fakeCmd); } } return exec4.call(this, cmdarr, env, file); }; exec3.implementation = function(cmdarr, envp) { for (var i = 0; i < cmdarr.length; i = i + 1) { var tmp_cmd = cmdarr[i]; if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmdarr + " command"); return exec1.call(this, fakeCmd); } if (tmp_cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmdarr + " command"); return exec1.call(this, fakeCmd); } } return exec3.call(this, cmdarr, envp); }; exec2.implementation = function(cmd, env) { if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } if (cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } return exec2.call(this, cmd, env); }; exec.implementation = function(cmd) { for (var i = 0; i < cmd.length; i = i + 1) { var tmp_cmd = cmd[i]; if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } if (tmp_cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } } return exec.call(this, cmd); }; exec1.implementation = function(cmd) { if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") { var fakeCmd = "grep"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } if (cmd == "su") { var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"; send("Bypass " + cmd + " command"); return exec1.call(this, fakeCmd); } return exec1.call(this, cmd); }; String.contains.implementation = function(name) { if (name == "test-keys") { send("Bypass test-keys check"); return false; } return this.contains.call(this, name); }; var get = SystemProperties.get.overload('java.lang.String'); get.implementation = function(name) { if (RootPropertiesKeys.indexOf(name) != -1) { send("Bypass " + name); return RootProperties[name]; } return this.get.call(this, name); }; Interceptor.attach(Module.findExportByName("libc.so", "fopen"), { onEnter: function(args) { var path = Memory.readCString(args[0]); path = path.split("/"); var executable = path[path.length - 1]; var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1) if (shouldFakeReturn) { Memory.writeUtf8String(args[0], "/notexists"); send("Bypass native fopen"); } }, onLeave: function(retval) { } }); Interceptor.attach(Module.findExportByName("libc.so", "system"), { onEnter: function(args) { var cmd = Memory.readCString(args[0]); send("SYSTEM CMD: " + cmd); if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") { send("Bypass native system: " + cmd); Memory.writeUtf8String(args[0], "grep"); } if (cmd == "su") { send("Bypass native system: " + cmd); Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"); } }, onLeave: function(retval) { } }); /* TO IMPLEMENT: Exec Family int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0); int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]); int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0); int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]); int execv(const char *path, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[], char *const envp[]); */ BufferedReader.readLine.overload('boolean').implementation = function() { var text = this.readLine.overload('boolean').call(this); if (text === null) { // just pass , i know it's ugly as hell but test != null won't work :( } else { var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1); if (shouldFakeRead) { send("Bypass build.prop file read"); text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys"); } } return text; }; var executeCommand = ProcessBuilder.command.overload('java.util.List'); ProcessBuilder.start.implementation = function() { var cmd = this.command.call(this); var shouldModifyCommand = false; for (var i = 0; i < cmd.size(); i = i + 1) { var tmp_cmd = cmd.get(i).toString(); if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) { shouldModifyCommand = true; } } if (shouldModifyCommand) { send("Bypass ProcessBuilder " + cmd); this.command.call(this, ["grep"]); return this.start.call(this); } if (cmd.indexOf("su") != -1) { send("Bypass ProcessBuilder " + cmd); this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]); return this.start.call(this); } return this.start.call(this); }; if (useProcessManager) { var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean'); var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean'); ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) { var fake_cmd = cmd; for (var i = 0; i < cmd.length; i = i + 1) { var tmp_cmd = cmd[i]; if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") { var fake_cmd = ["grep"]; send("Bypass " + cmdarr + " command"); } if (tmp_cmd == "su") { var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]; send("Bypass " + cmdarr + " command"); } } return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr); }; ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) { var fake_cmd = cmd; for (var i = 0; i < cmd.length; i = i + 1) { var tmp_cmd = cmd[i]; if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") { var fake_cmd = ["grep"]; send("Bypass " + cmdarr + " command"); } if (tmp_cmd == "su") { var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]; send("Bypass " + cmdarr + " command"); } } return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect); }; } if (useKeyInfo) { KeyInfo.isInsideSecureHardware.implementation = function() { send("Bypass isInsideSecureHardware"); return true; } } }); const commonPaths = [ "/data/local/bin/su", "/data/local/su", "/data/local/xbin/su", "/dev/com.koushikdutta.superuser.daemon/", "/sbin/su", "/system/app/Superuser.apk", "/system/bin/failsafe/su", "/system/bin/su", "/su/bin/su", "/system/etc/init.d/99SuperSUDaemon", "/system/sd/xbin/su", "/system/xbin/busybox", "/system/xbin/daemonsu", "/system/xbin/su", "/system/sbin/su", "/vendor/bin/su", "/cache/su", "/data/su", "/dev/su", "/system/bin/.ext/su", "/system/usr/we-need-root/su", "/system/app/Kinguser.apk", "/data/adb/magisk", "/sbin/.magisk", "/cache/.disable_magisk", "/dev/.magisk.unblock", "/cache/magisk.log", "/data/adb/magisk.img", "/data/adb/magisk.db", "/data/adb/magisk_simple", "/init.magisk.rc", "/system/xbin/ku.sud", "/data/adb/ksu", "/data/adb/ksud" ]; const ROOTmanagementApp = [ "com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu", "com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager", "com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch", "com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.topjohnwu.magisk", "me.weishu.kernelsu" ]; function stackTraceHere(isLog){ var Exception = Java.use('java.lang.Exception'); var Log = Java.use('android.util.Log'); var stackinfo = Log.getStackTraceString(Exception.$new()) if(isLog){ console.log(stackinfo) }else{ return stackinfo } } function stackTraceNativeHere(isLog){ var backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress) .join("\n\t"); console.log(backtrace) } function bypassJavaFileCheck(){ var UnixFileSystem = Java.use("java.io.UnixFileSystem") UnixFileSystem.checkAccess.implementation = function(file,access){ var stack = stackTraceHere(false) const filename = file.getAbsolutePath(); if (filename.indexOf("magisk") >= 0) { console.log("Anti Root Detect - check file: " + filename) return false; } if (commonPaths.indexOf(filename) >= 0) { console.log("Anti Root Detect - check file: " + filename) return false; } return this.checkAccess(file,access) } } function bypassNativeFileCheck(){ var fopen = Module.findExportByName("libc.so","fopen") Interceptor.attach(fopen,{ onEnter:function(args){ this.inputPath = args[0].readUtf8String() }, onLeave:function(retval){ if(retval.toInt32() != 0){ if (commonPaths.indexOf(this.inputPath) >= 0) { console.log("Anti Root Detect - fopen : " + this.inputPath) retval.replace(ptr(0x0)) } } } }) var access = Module.findExportByName("libc.so","access") Interceptor.attach(access,{ onEnter:function(args){ this.inputPath = args[0].readUtf8String() }, onLeave:function(retval){ if(retval.toInt32()==0){ if(commonPaths.indexOf(this.inputPath) >= 0){ console.log("Anti Root Detect - access : " + this.inputPath) retval.replace(ptr(-1)) } } } }) } function setProp(){ var Build = Java.use("android.os.Build") var TAGS = Build.class.getDeclaredField("TAGS") TAGS.setAccessible(true) TAGS.set(null,"release-keys") var FINGERPRINT = Build.class.getDeclaredField("FINGERPRINT") FINGERPRINT.setAccessible(true) FINGERPRINT.set(null,"google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys") // Build.deriveFingerprint.inplementation = function(){ // var ret = this.deriveFingerprint() //该函数无法通过反射调用 // console.log(ret) // return ret // } var system_property_get = Module.findExportByName("libc.so", "__system_property_get") Interceptor.attach(system_property_get,{ onEnter(args){ this.key = args[0].readCString() this.ret = args[1] }, onLeave(ret){ if(this.key == "ro.build.fingerprint"){ var tmp = "google/crosshatch/crosshatch:10/QQ3A.200805.001/6578210:user/release-keys" var p = Memory.allocUtf8String(tmp) Memory.copy(this.ret,p,tmp.length+1) } } }) } //android.app.PackageManager function bypassRootAppCheck(){ var ApplicationPackageManager = Java.use("android.app.ApplicationPackageManager") ApplicationPackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(str,i){ // console.log(str) if (ROOTmanagementApp.indexOf(str) >= 0) { console.log("Anti Root Detect - check package : " + str) str = "ashen.one.ye.not.found" } return this.getPackageInfo(str,i) } //shell pm check } function bypassShellCheck(){ var String = Java.use('java.lang.String') var ProcessImpl = Java.use("java.lang.ProcessImpl") ProcessImpl.start.implementation = function(cmdarray,env,dir,redirects,redirectErrorStream){ if(cmdarray[0] == "mount"){ console.log("Anti Root Detect - Shell : " + cmdarray.toString()) arguments[0] = Java.array('java.lang.String',[String.$new("")]) return ProcessImpl.start.apply(this,arguments) } if(cmdarray[0] == "getprop"){ console.log("Anti Root Detect - Shell : " + cmdarray.toString()) const prop = [ "ro.secure", "ro.debuggable" ]; if(prop.indexOf(cmdarray[1]) >= 0){ arguments[0] = Java.array('java.lang.String',[String.$new("")]) return ProcessImpl.start.apply(this,arguments) } } if(cmdarray[0].indexOf("which") >= 0){ const prop = [ "su" ]; if(prop.indexOf(cmdarray[1]) >= 0){ console.log("Anti Root Detect - Shell : " + cmdarray.toString()) arguments[0] = Java.array('java.lang.String',[String.$new("")]) return ProcessImpl.start.apply(this,arguments) } } return ProcessImpl.start.apply(this,arguments) } } console.log("Attach") bypassNativeFileCheck() bypassJavaFileCheck() setProp() bypassRootAppCheck() bypassShellCheck()