RE env for inspecting APKs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

731 lines
29 KiB

  1. /* Android ssl certificate pinning bypass script for various methods
  2. by Maurizio Siddu
  3. Run with:
  4. frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause
  5. */
  6. setTimeout(function() {
  7. Java.perform(function() {
  8. console.log('');
  9. console.log('======');
  10. console.log('[#] Android Bypass for various Certificate Pinning methods [#]');
  11. console.log('======');
  12. var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
  13. var SSLContext = Java.use('javax.net.ssl.SSLContext');
  14. // TrustManager (Android < 7) //
  15. ////////////////////////////////
  16. var TrustManager = Java.registerClass({
  17. // Implement a custom TrustManager
  18. name: 'dev.asd.test.TrustManager',
  19. implements: [X509TrustManager],
  20. methods: {
  21. checkClientTrusted: function(chain, authType) {},
  22. checkServerTrusted: function(chain, authType) {},
  23. getAcceptedIssuers: function() {return []; }
  24. }
  25. });
  26. // Prepare the TrustManager array to pass to SSLContext.init()
  27. var TrustManagers = [TrustManager.$new()];
  28. // Get a handle on the init() on the SSLContext class
  29. var SSLContext_init = SSLContext.init.overload(
  30. '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
  31. try {
  32. // Override the init method, specifying the custom TrustManager
  33. SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
  34. console.log('[+] Bypassing Trustmanager (Android < 7) pinner');
  35. SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
  36. };
  37. } catch (err) {
  38. console.log('[-] TrustManager (Android < 7) pinner not found');
  39. //console.log(err);
  40. }
  41. // OkHTTPv3 (quadruple bypass) //
  42. /////////////////////////////////
  43. try {
  44. // Bypass OkHTTPv3 {1}
  45. var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
  46. okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
  47. console.log('[+] Bypassing OkHTTPv3 {1}: ' + a);
  48. return;
  49. };
  50. } catch (err) {
  51. console.log('[-] OkHTTPv3 {1} pinner not found');
  52. //console.log(err);
  53. }
  54. try {
  55. // Bypass OkHTTPv3 {2}
  56. // This method of CertificatePinner.check is deprecated but could be found in some old Android apps
  57. var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
  58. okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
  59. console.log('[+] Bypassing OkHTTPv3 {2}: ' + a);
  60. return;
  61. };
  62. } catch (err) {
  63. console.log('[-] OkHTTPv3 {2} pinner not found');
  64. //console.log(err);
  65. }
  66. try {
  67. // Bypass OkHTTPv3 {3}
  68. var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
  69. okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(a, b) {
  70. console.log('[+] Bypassing OkHTTPv3 {3}: ' + a);
  71. return;
  72. };
  73. } catch(err) {
  74. console.log('[-] OkHTTPv3 {3} pinner not found');
  75. //console.log(err);
  76. }
  77. try {
  78. // Bypass OkHTTPv3 {4}
  79. var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
  80. //okhttp3_Activity_4['check$okhttp'].implementation = function(a, b) {
  81. okhttp3_Activity_4.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(a, b) {
  82. console.log('[+] Bypassing OkHTTPv3 {4}: ' + a);
  83. return;
  84. };
  85. } catch(err) {
  86. console.log('[-] OkHTTPv3 {4} pinner not found');
  87. //console.log(err);
  88. }
  89. // Trustkit (triple bypass) //
  90. //////////////////////////////
  91. try {
  92. // Bypass Trustkit {1}
  93. var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
  94. trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
  95. console.log('[+] Bypassing Trustkit {1}: ' + a);
  96. return true;
  97. };
  98. } catch (err) {
  99. console.log('[-] Trustkit {1} pinner not found');
  100. //console.log(err);
  101. }
  102. try {
  103. // Bypass Trustkit {2}
  104. var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
  105. trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
  106. console.log('[+] Bypassing Trustkit {2}: ' + a);
  107. return true;
  108. };
  109. } catch (err) {
  110. console.log('[-] Trustkit {2} pinner not found');
  111. //console.log(err);
  112. }
  113. try {
  114. // Bypass Trustkit {3}
  115. var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
  116. trustkit_PinningTrustManager.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function(chain, authType) {
  117. console.log('[+] Bypassing Trustkit {3}');
  118. //return;
  119. };
  120. } catch (err) {
  121. console.log('[-] Trustkit {3} pinner not found');
  122. //console.log(err);
  123. }
  124. // TrustManagerImpl (Android > 7) //
  125. ////////////////////////////////////
  126. try {
  127. // Bypass TrustManagerImpl (Android > 7) {1}
  128. var array_list = Java.use("java.util.ArrayList");
  129. var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
  130. TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
  131. console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host);
  132. return array_list.$new();
  133. };
  134. } catch (err) {
  135. console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found');
  136. //console.log(err);
  137. }
  138. try {
  139. // Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary)
  140. var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
  141. TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
  142. console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check: ' + host);
  143. return untrustedChain;
  144. };
  145. } catch (err) {
  146. console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found');
  147. //console.log(err);
  148. }
  149. // Appcelerator Titanium PinningTrustManager //
  150. ///////////////////////////////////////////////
  151. try {
  152. var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
  153. appcelerator_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
  154. console.log('[+] Bypassing Appcelerator PinningTrustManager');
  155. return;
  156. };
  157. } catch (err) {
  158. console.log('[-] Appcelerator PinningTrustManager pinner not found');
  159. //console.log(err);
  160. }
  161. // Fabric PinningTrustManager //
  162. ////////////////////////////////
  163. try {
  164. var fabric_PinningTrustManager = Java.use('io.fabric.sdk.android.services.network.PinningTrustManager');
  165. fabric_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
  166. console.log('[+] Bypassing Fabric PinningTrustManager');
  167. return;
  168. };
  169. } catch (err) {
  170. console.log('[-] Fabric PinningTrustManager pinner not found');
  171. //console.log(err);
  172. }
  173. // OpenSSLSocketImpl Conscrypt (double bypass) //
  174. /////////////////////////////////////////////////
  175. try {
  176. var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
  177. OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, JavaObject, authMethod) {
  178. console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {1}');
  179. };
  180. } catch (err) {
  181. console.log('[-] OpenSSLSocketImpl Conscrypt {1} pinner not found');
  182. //console.log(err);
  183. }
  184. try {
  185. var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
  186. OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certChain, authMethod) {
  187. console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {2}');
  188. };
  189. } catch (err) {
  190. console.log('[-] OpenSSLSocketImpl Conscrypt {2} pinner not found');
  191. //console.log(err);
  192. }
  193. // OpenSSLEngineSocketImpl Conscrypt //
  194. ///////////////////////////////////////
  195. try {
  196. var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
  197. OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function(a, b) {
  198. console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
  199. };
  200. } catch (err) {
  201. console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');
  202. //console.log(err);
  203. }
  204. // OpenSSLSocketImpl Apache Harmony //
  205. //////////////////////////////////////
  206. try {
  207. var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
  208. OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function(asn1DerEncodedCertificateChain, authMethod) {
  209. console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');
  210. };
  211. } catch (err) {
  212. console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');
  213. //console.log(err);
  214. }
  215. // PhoneGap sslCertificateChecker //
  216. ////////////////////////////////////
  217. try {
  218. var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
  219. phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
  220. console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a);
  221. return true;
  222. };
  223. } catch (err) {
  224. console.log('[-] PhoneGap sslCertificateChecker pinner not found');
  225. //console.log(err);
  226. }
  227. // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) //
  228. ////////////////////////////////////////////////////////////////////
  229. try {
  230. // Bypass IBM MobileFirst {1}
  231. var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
  232. WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function(cert) {
  233. console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);
  234. return;
  235. };
  236. } catch (err) {
  237. console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found');
  238. //console.log(err);
  239. }
  240. try {
  241. // Bypass IBM MobileFirst {2}
  242. var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
  243. WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function(cert) {
  244. console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);
  245. return;
  246. };
  247. } catch (err) {
  248. console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found');
  249. //console.log(err);
  250. }
  251. // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) //
  252. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  253. try {
  254. // Bypass IBM WorkLight {1}
  255. var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
  256. worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function(a, b) {
  257. console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a);
  258. return;
  259. };
  260. } catch (err) {
  261. console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found');
  262. //console.log(err);
  263. }
  264. try {
  265. // Bypass IBM WorkLight {2}
  266. var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
  267. worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
  268. console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a);
  269. return;
  270. };
  271. } catch (err) {
  272. console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found');
  273. //console.log(err);
  274. }
  275. try {
  276. // Bypass IBM WorkLight {3}
  277. var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
  278. worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function(a, b) {
  279. console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a);
  280. return;
  281. };
  282. } catch (err) {
  283. console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found');
  284. //console.log(err);
  285. }
  286. try {
  287. // Bypass IBM WorkLight {4}
  288. var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
  289. worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
  290. console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a);
  291. return true;
  292. };
  293. } catch (err) {
  294. console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found');
  295. //console.log(err);
  296. }
  297. // Conscrypt CertPinManager //
  298. //////////////////////////////
  299. try {
  300. var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
  301. conscrypt_CertPinManager_Activity.checkChainPinning.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
  302. console.log('[+] Bypassing Conscrypt CertPinManager: ' + a);
  303. //return;
  304. return true;
  305. };
  306. } catch (err) {
  307. console.log('[-] Conscrypt CertPinManager pinner not found');
  308. //console.log(err);
  309. }
  310. // Conscrypt CertPinManager (Legacy) //
  311. ///////////////////////////////////////
  312. try {
  313. var legacy_conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
  314. legacy_conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
  315. console.log('[+] Bypassing Conscrypt CertPinManager (Legacy): ' + a);
  316. return true;
  317. };
  318. } catch (err) {
  319. console.log('[-] Conscrypt CertPinManager (Legacy) pinner not found');
  320. //console.log(err);
  321. }
  322. // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager //
  323. ///////////////////////////////////////////////////////////////////////////////////
  324. try {
  325. var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
  326. cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
  327. console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a);
  328. return true;
  329. };
  330. } catch (err) {
  331. console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');
  332. //console.log(err);
  333. }
  334. // Worklight Androidgap WLCertificatePinningPlugin //
  335. /////////////////////////////////////////////////////
  336. try {
  337. var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
  338. androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
  339. console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
  340. return true;
  341. };
  342. } catch (err) {
  343. console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');
  344. //console.log(err);
  345. }
  346. // Netty FingerprintTrustManagerFactory //
  347. //////////////////////////////////////////
  348. try {
  349. var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
  350. //NOTE: sometimes this below implementation could be useful
  351. //var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');
  352. netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function(type, chain) {
  353. console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');
  354. };
  355. } catch (err) {
  356. console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');
  357. //console.log(err);
  358. }
  359. // Squareup CertificatePinner [OkHTTP<v3] (double bypass) //
  360. ////////////////////////////////////////////////////////////
  361. try {
  362. // Bypass Squareup CertificatePinner {1}
  363. var Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
  364. Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
  365. console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + a);
  366. return;
  367. };
  368. } catch (err) {
  369. console.log('[-] Squareup CertificatePinner {1} pinner not found');
  370. //console.log(err);
  371. }
  372. try {
  373. // Bypass Squareup CertificatePinner {2}
  374. var Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
  375. Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
  376. console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + a);
  377. return;
  378. };
  379. } catch (err) {
  380. console.log('[-] Squareup CertificatePinner {2} pinner not found');
  381. //console.log(err);
  382. }
  383. // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) //
  384. /////////////////////////////////////////////////////////////
  385. try {
  386. // Bypass Squareup OkHostnameVerifier {1}
  387. var Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
  388. Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
  389. console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + a);
  390. return true;
  391. };
  392. } catch (err) {
  393. console.log('[-] Squareup OkHostnameVerifier check not found');
  394. //console.log(err);
  395. }
  396. try {
  397. // Bypass Squareup OkHostnameVerifier {2}
  398. var Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
  399. Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
  400. console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + a);
  401. return true;
  402. };
  403. } catch (err) {
  404. console.log('[-] Squareup OkHostnameVerifier check not found');
  405. //console.log(err);
  406. }
  407. // Android WebViewClient (quadruple bypass) //
  408. //////////////////////////////////////////////
  409. try {
  410. // Bypass WebViewClient {1} (deprecated from Android 6)
  411. var AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
  412. AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
  413. console.log('[+] Bypassing Android WebViewClient check {1}');
  414. };
  415. } catch (err) {
  416. console.log('[-] Android WebViewClient {1} check not found');
  417. //console.log(err)
  418. }
  419. try {
  420. // Bypass WebViewClient {2}
  421. var AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
  422. AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
  423. console.log('[+] Bypassing Android WebViewClient check {2}');
  424. };
  425. } catch (err) {
  426. console.log('[-] Android WebViewClient {2} check not found');
  427. //console.log(err)
  428. }
  429. try {
  430. // Bypass WebViewClient {3}
  431. var AndroidWebViewClient_Activity_3 = Java.use('android.webkit.WebViewClient');
  432. AndroidWebViewClient_Activity_3.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(obj1, obj2, obj3, obj4) {
  433. console.log('[+] Bypassing Android WebViewClient check {3}');
  434. };
  435. } catch (err) {
  436. console.log('[-] Android WebViewClient {3} check not found');
  437. //console.log(err)
  438. }
  439. try {
  440. // Bypass WebViewClient {4}
  441. var AndroidWebViewClient_Activity_4 = Java.use('android.webkit.WebViewClient');
  442. AndroidWebViewClient_Activity_4.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
  443. console.log('[+] Bypassing Android WebViewClient check {4}');
  444. };
  445. } catch (err) {
  446. console.log('[-] Android WebViewClient {4} check not found');
  447. //console.log(err)
  448. }
  449. // Apache Cordova WebViewClient //
  450. //////////////////////////////////
  451. try {
  452. var CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
  453. CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
  454. console.log('[+] Bypassing Apache Cordova WebViewClient check');
  455. obj3.proceed();
  456. };
  457. } catch (err) {
  458. console.log('[-] Apache Cordova WebViewClient check not found');
  459. //console.log(err);
  460. }
  461. // Boye AbstractVerifier //
  462. ///////////////////////////
  463. try {
  464. var boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
  465. boye_AbstractVerifier.verify.implementation = function(host, ssl) {
  466. console.log('[+] Bypassing Boye AbstractVerifier check: ' + host);
  467. };
  468. } catch (err) {
  469. console.log('[-] Boye AbstractVerifier check not found');
  470. //console.log(err);
  471. }
  472. // Apache AbstractVerifier //
  473. /////////////////////////////
  474. try {
  475. var apache_AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
  476. apache_AbstractVerifier.verify.implementation = function(a, b, c, d) {
  477. console.log('[+] Bypassing Apache AbstractVerifier check: ' + a);
  478. return;
  479. };
  480. } catch (err) {
  481. console.log('[-] Apache AbstractVerifier check not found');
  482. //console.log(err);
  483. }
  484. // Chromium Cronet //
  485. /////////////////////
  486. try {
  487. var CronetEngineBuilderImpl_Activity = Java.use("org.chromium.net.impl.CronetEngineBuilderImpl");
  488. // Setting argument to TRUE (default is TRUE) to disable Public Key pinning for local trust anchors
  489. CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.overload('boolean').implementation = function(a) {
  490. console.log("[+] Disabling Public Key pinning for local trust anchors in Chromium Cronet");
  491. var cronet_obj_1 = CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
  492. return cronet_obj_1;
  493. };
  494. // Bypassing Chromium Cronet pinner
  495. CronetEngine_Activity.addPublicKeyPins.overload('java.lang.String', 'java.util.Set', 'boolean', 'java.util.Date').implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {
  496. console.log("[+] Bypassing Chromium Cronet pinner: " + hostName);
  497. var cronet_obj_2 = CronetEngine_Activity.addPublicKeyPins.call(this, hostName, pinsSha256, includeSubdomains, expirationDate);
  498. return cronet_obj_2;
  499. };
  500. } catch (err) {
  501. console.log('[-] Chromium Cronet pinner not found')
  502. //console.log(err);
  503. }
  504. // Flutter Pinning packages http_certificate_pinning and ssl_pinning_plugin (double bypass) //
  505. //////////////////////////////////////////////////////////////////////////////////////////////
  506. try {
  507. // Bypass HttpCertificatePinning.check {1}
  508. var HttpCertificatePinning_Activity = Java.use('diefferson.http_certificate_pinning.HttpCertificatePinning');
  509. HttpCertificatePinning_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
  510. console.log('[+] Bypassing Flutter HttpCertificatePinning : ' + a);
  511. return true;
  512. };
  513. } catch (err) {
  514. console.log('[-] Flutter HttpCertificatePinning pinner not found');
  515. //console.log(err);
  516. }
  517. try {
  518. // Bypass SslPinningPlugin.check {2}
  519. var SslPinningPlugin_Activity = Java.use('com.macif.plugin.sslpinningplugin.SslPinningPlugin');
  520. SslPinningPlugin_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
  521. console.log('[+] Bypassing Flutter SslPinningPlugin: ' + a);
  522. return true;
  523. };
  524. } catch (err) {
  525. console.log('[-] Flutter SslPinningPlugin pinner not found');
  526. //console.log(err);
  527. }
  528. // Dynamic SSLPeerUnverifiedException Patcher //
  529. // An useful technique to bypass SSLPeerUnverifiedException failures raising //
  530. // when the Android app uses some uncommon SSL Pinning methods or an heavily //
  531. // code obfuscation. Inspired by an idea of: https://github.com/httptoolkit //
  532. ///////////////////////////////////////////////////////////////////////////////
  533. function rudimentaryFix(typeName) {
  534. // This is a improvable rudimentary fix, if not works you can patch it manually
  535. if (typeName === undefined){
  536. return;
  537. } else if (typeName === 'boolean') {
  538. return true;
  539. } else {
  540. return null;
  541. }
  542. }
  543. try {
  544. var UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
  545. UnverifiedCertError.$init.implementation = function (str) {
  546. console.log('\x1b[36m[!] Unexpected SSLPeerUnverifiedException occurred, trying to patch it dynamically...\x1b[0m');
  547. try {
  548. var stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
  549. var exceptionStackIndex = stackTrace.findIndex(stack =>
  550. stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
  551. );
  552. // Retrieve the method raising the SSLPeerUnverifiedException
  553. var callingFunctionStack = stackTrace[exceptionStackIndex + 1];
  554. var className = callingFunctionStack.getClassName();
  555. var methodName = callingFunctionStack.getMethodName();
  556. var callingClass = Java.use(className);
  557. var callingMethod = callingClass[methodName];
  558. console.log('\x1b[36m[!] Attempting to bypass uncommon SSL Pinning method on: '+className+'.'+methodName+'\x1b[0m');
  559. // Skip it when already patched by Frida
  560. if (callingMethod.implementation) {
  561. return;
  562. }
  563. // Trying to patch the uncommon SSL Pinning method via implementation
  564. var returnTypeName = callingMethod.returnType.type;
  565. callingMethod.implementation = function() {
  566. rudimentaryFix(returnTypeName);
  567. };
  568. } catch (e) {
  569. // Dynamic patching via implementation does not works, then trying via function overloading
  570. //console.log('[!] The uncommon SSL Pinning method has more than one overload);
  571. if (String(e).includes(".overload")) {
  572. var splittedList = String(e).split(".overload");
  573. for (let i=2; i<splittedList.length; i++) {
  574. var extractedOverload = splittedList[i].trim().split("(")[1].slice(0,-1).replaceAll("'","");
  575. // Check if extractedOverload has multiple arguments
  576. if (extractedOverload.includes(",")) {
  577. // Go here if overloaded method has multiple arguments (NOTE: max 6 args are covered here)
  578. var argList = extractedOverload.split(", ");
  579. console.log('\x1b[36m[!] Attempting overload of '+className+'.'+methodName+' with arguments: '+extractedOverload+'\x1b[0m');
  580. if (argList.length == 2) {
  581. callingMethod.overload(argList[0], argList[1]).implementation = function(a,b) {
  582. rudimentaryFix(returnTypeName);
  583. }
  584. } else if (argNum == 3) {
  585. callingMethod.overload(argList[0], argList[1], argList[2]).implementation = function(a,b,c) {
  586. rudimentaryFix(returnTypeName);
  587. }
  588. } else if (argNum == 4) {
  589. callingMethod.overload(argList[0], argList[1], argList[2], argList[3]).implementation = function(a,b,c,d) {
  590. rudimentaryFix(returnTypeName);
  591. }
  592. } else if (argNum == 5) {
  593. callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4]).implementation = function(a,b,c,d,e) {
  594. rudimentaryFix(returnTypeName);
  595. }
  596. } else if (argNum == 6) {
  597. callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4], argList[5]).implementation = function(a,b,c,d,e,f) {
  598. rudimentaryFix(returnTypeName);
  599. }
  600. }
  601. // Go here if overloaded method has a single argument
  602. } else {
  603. callingMethod.overload(extractedOverload).implementation = function(a) {
  604. rudimentaryFix(returnTypeName);
  605. }
  606. }
  607. }
  608. } else {
  609. console.log('\x1b[36m[-] Failed to dynamically patch SSLPeerUnverifiedException '+e+'\x1b[0m');
  610. }
  611. }
  612. //console.log('\x1b[36m[+] SSLPeerUnverifiedException hooked\x1b[0m');
  613. return this.$init(str);
  614. };
  615. } catch (err) {
  616. //console.log('\x1b[36m[-] SSLPeerUnverifiedException not found\x1b[0m');
  617. //console.log('\x1b[36m'+err+'\x1b[0m');
  618. }
  619. });
  620. }, 0);