mobile-ssl-pinning-bypass

>-

INSTALLATION
npx skills add https://github.com/yaklang/hack-skills --skill mobile-ssl-pinning-bypass
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

Pinning Type

What Is Pinned

Resilience

Common In

Certificate pinning

Exact leaf certificate (DER/PEM)

Low (breaks on cert rotation)

Legacy apps

Public key pinning

Subject Public Key Info

Medium (survives cert renewal if key unchanged)

Modern apps

SPKI hash pinning

SHA-256 of SPKI

Medium (same as public key)

OkHttp, AFNetworking

CA pinning

Intermediate or root CA cert

High (any cert from that CA works)

Enterprise apps

Multi-pin (backup pins)

Primary + backup pins

High (fallback pins)

HPKP-aware apps

How Pinning Works

TLS Handshake

│

├── Server presents certificate chain

│

├── Standard validation (system trust store)

│   └── Passes? continue : connection fails

│

└── Pin validation (app-level check)

    ├── Extract server cert/pubkey/SPKI hash

    ├── Compare against embedded pins

    └── Match found? → allow : → reject connection

2. ANDROID BYPASS METHODS

2.1 Frida Universal SSL Bypass

// Hooks TrustManager, OkHttp, Volley, Retrofit, Conscrypt

Java.perform(function() {

    // ── TrustManagerImpl (Android system) ──

    try {

        var TMI = Java.use('com.android.org.conscrypt.TrustManagerImpl');

        TMI.verifyChain.implementation = function() {

            console.log('[Bypass] TrustManagerImpl.verifyChain');

            return arguments[0]; // return untouched chain

        };

    } catch(e) {}

    // ── X509TrustManager (custom implementations) ──

    var TrustManager = Java.registerClass({

        name: 'com.bypass.TrustManager',

        implements: [Java.use('javax.net.ssl.X509TrustManager')],

        methods: {

            checkClientTrusted: function() {},

            checkServerTrusted: function() {},

            getAcceptedIssuers: function() { return []; }

        }

    });

    var SSLContext = Java.use('javax.net.ssl.SSLContext');

    SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;',

        '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom')

        .implementation = function(km, tm, sr) {

        console.log('[Bypass] SSLContext.init');

        this.init(km, [TrustManager.$new()], sr);

    };

    // ── OkHttp3 CertificatePinner ──

    try {

        var CP = Java.use('okhttp3.CertificatePinner');

        CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {

            console.log('[Bypass] OkHttp3 CertificatePinner.check: ' + arguments[0]);

        };

        // check$okhttp variant (OkHttp 4.x)

        try { CP['check$okhttp'].implementation = function() {}; } catch(e) {}

    } catch(e) {}

    // ── Retrofit / OkHttp interceptor ──

    try {

        var OkHttpClient = Java.use('okhttp3.OkHttpClient$Builder');

        OkHttpClient.certificatePinner.implementation = function(pinner) {

            console.log('[Bypass] OkHttpClient.Builder.certificatePinner');

            return this; // return builder without pinner

        };

    } catch(e) {}

    // ── Volley (HurlStack) ──

    try {

        var HurlStack = Java.use('com.android.volley.toolbox.HurlStack');

        HurlStack.createConnection.implementation = function(url) {

            console.log('[Bypass] Volley HurlStack: ' + url);

            var conn = this.createConnection(url);

            // Remove hostname verifier

            conn.setHostnameVerifier(Java.use(

                'javax.net.ssl.HttpsURLConnection').getDefaultHostnameVerifier());

            return conn;

        };

    } catch(e) {}

    // ── Conscrypt / BoringSSL (modern Android) ──

    try {

        var Conscrypt = Java.use('org.conscrypt.ConscryptFileDescriptorSocket');

        Conscrypt.verifyCertificateChain.implementation = function() {

            console.log('[Bypass] Conscrypt verifyCertificateChain');

        };

    } catch(e) {}

    // ── Apache HttpClient (legacy) ──

    try {

        var AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');

        AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String;',

            '[Ljava.lang.String;', 'boolean').implementation = function() {

            console.log('[Bypass] Apache AbstractVerifier');

        };

    } catch(e) {}

    // ── HostnameVerifier ──

    try {

        var HV = Java.use('javax.net.ssl.HttpsURLConnection');

        HV.setDefaultHostnameVerifier.implementation = function(v) {

            console.log('[Bypass] Ignoring custom HostnameVerifier');

        };

    } catch(e) {}

    console.log('[+] Android universal SSL bypass loaded');

});

2.2 Objection (One Command)

objection -g com.target.app explore --startup-command "android sslpinning disable"

2.3 Network Security Config (Debug Override)

<!-- AndroidManifest.xml: android:networkSecurityConfig="@xml/network_security_config" -->

<!-- res/xml/network_security_config.xml -->

<network-security-config>

  <base-config>

    <trust-anchors>

      <certificates src="system" />

      <certificates src="user" />     <!-- Trust user-installed CAs -->

    </trust-anchors>

  </base-config>

</network-security-config>

Workflow: decompile APK → add/modify config → repackage → re-sign → install.

apktool d target.apk -o target_dir

# Edit res/xml/network_security_config.xml

# Add reference in AndroidManifest.xml if missing

apktool b target_dir -o target_patched.apk

zipalign -v 4 target_patched.apk target_aligned.apk

apksigner sign --ks my-key.keystore target_aligned.apk

adb install target_aligned.apk

2.4 Xposed / LSPosed Modules

Module

Method

Scope

Root Required

JustTrustMe

Hooks TrustManager + OkHttp

Per-app

Yes (Xposed)

SSLUnpinning

Hooks certificate validation

Per-app

Yes (LSPosed)

TrustMeAlready

Global TrustManager bypass

System-wide

Yes (LSPosed)

2.5 Magisk + System CA Installation

# Install proxy CA as system cert (Android 7+ requires this for system-level trust)

# Method 1: MagiskTrustUserCerts module

# Moves user CAs to /system/etc/security/cacerts/ via Magisk overlay

# Method 2: Manual (requires root)

adb push burp_ca.pem /sdcard/

adb shell

su

mount -o remount,rw /system

cp /sdcard/burp_ca.pem /system/etc/security/cacerts/9a5ba575.0  # hash-named

chmod 644 /system/etc/security/cacerts/9a5ba575.0

mount -o remount,ro /system

# Get correct hash filename:

openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | head -1

# Output: 9a5ba575 → filename is 9a5ba575.0

2.6 Manual Decompile → Patch → Repackage

# Step 1: Decompile

jadx -d decompiled/ target.apk

# Step 2: Find pinning code

grep -r "CertificatePinner\|X509TrustManager\|checkServerTrusted\|ssl" decompiled/

# Step 3: Identify pinning implementation and patch

# Use smali editing for precise control:

apktool d target.apk

# Edit smali files to NOP out pinning checks

# Look for invoke-virtual {checkServerTrusted} and replace with return-void

# Step 4: Repackage and sign

apktool b target_dir -o patched.apk

apksigner sign --ks debug.keystore patched.apk

3. iOS BYPASS METHODS

3.1 Frida (SecTrust Hooks)

// Hook core iOS SSL validation functions

var SecTrustEvaluateWithError = Module.findExportByName('Security', 'SecTrustEvaluateWithError');

Interceptor.attach(SecTrustEvaluateWithError, {

    onLeave: function(retval) {

        retval.replace(ptr(1));

    }

});

var SecTrustEvaluate = Module.findExportByName('Security', 'SecTrustEvaluate');

Interceptor.attach(SecTrustEvaluate, {

    onLeave: function(retval) {

        retval.replace(ptr(0));

    }

});

// Hook SSLHandshake (lower-level)

var SSLHandshake = Module.findExportByName('Security', 'SSLHandshake');

if (SSLHandshake) {

    Interceptor.attach(SSLHandshake, {

        onLeave: function(retval) {

            if (retval.toInt32() === -9807) { // errSSLXCertChainInvalid

                retval.replace(ptr(0));

            }

        }

    });

}

// Hook NSURLSession delegate method

try {

    var cls = ObjC.classes.NSURLSession;

    // Hook URLSession:didReceiveChallenge:completionHandler: on delegates

    ObjC.enumerateLoadedClasses({

        onMatch: function(name) {

            try {

                var methods = ObjC.classes[name].$ownMethods;

                for (var i = 0; i < methods.length; i++) {

                    if (methods[i].indexOf('didReceiveChallenge') !== -1 &#x26;&#x26;

                        methods[i].indexOf('completionHandler') !== -1) {

                        console.log('[SSL] Found delegate: ' + name + ' ' + methods[i]);

                    }

                }

            } catch(e) {}

        },

        onComplete: function() {}

    });

} catch(e) {}

3.2 Objection (One Command)

objection -g com.target.app explore --startup-command "ios sslpinning disable"

3.3 SSL Kill Switch 2 (Jailbreak Tweak)

# Install via Cydia/Sileo

# Package: com.nablac0d3.sslkillswitch2

# Disables SSL pinning system-wide or per-app via Settings toggle

# Hooks:

# - SecTrustEvaluate

# - SSLHandshake

# - SSLSetSessionOption

# - tls_helper_create_peer_trust

3.4 Library-Specific Hooks

Library

iOS Hook Point

Frida Approach

AFNetworking

AFSecurityPolicy.evaluateServerTrust:forDomain:

Return YES

Alamofire

ServerTrustManager.evaluate(_:forHost:)

Skip evaluation

TrustKit

TSKPinningValidator verifyPublicKeyPin:

Return success

NSURLSession

URLSession:didReceiveChallenge:completionHandler:

Call completionHandler with .useCredential

3.5 Manual Binary Patch

# Find pinning function in binary

strings decrypted_binary | grep -i "pin\|cert\|trust"

# Disassemble and find the validation function

# Replace comparison/branch instruction with NOP or unconditional pass

# LLDB runtime modification

lldb -n TargetApp

(lldb) breakpoint set -n "SecTrustEvaluateWithError"

(lldb) breakpoint command add 1

> thread return 1

> continue

> DONE

4. FRAMEWORK-SPECIFIC BYPASSES

4.1 Flutter

Flutter uses Dart's dart:io library with BoringSSL underneath. Standard Frida hooks on Java/ObjC layers don't work.

// Flutter SSL bypass — must hook BoringSSL directly

// Find ssl_crypto_x509_session_verify_cert_chain in libflutter.so

var libflutter = Process.findModuleByName('libflutter.so');  // Android

// var libflutter = Process.findModuleByName('Flutter');       // iOS

// Hook ssl_verify_peer_cert (BoringSSL function)

// Signature varies by Flutter version — use pattern scanning

var pattern = 'FF C3 ..';  // Example pattern, varies

var matches = Memory.scan(libflutter.base, libflutter.size, pattern, {

    onMatch: function(address, size) {

        console.log('[Flutter] Potential verify function at: ' + address);

        Interceptor.attach(address, {

            onLeave: function(retval) {

                retval.replace(ptr(0));  // SSL_VERIFY_OK

            }

        });

    },

    onComplete: function() {}

});

// Alternative: use reflutter tool for automated patching

// reflutter target.apk

// This patches BoringSSL in the Flutter engine directly

reflutter tool (recommended for Flutter apps):

pip install reflutter

reflutter target.apk

# Outputs patched APK that redirects traffic to your proxy

# Also disables SSL verification in the BoringSSL engine

4.2 React Native

React Native uses platform networking: OkHttp on Android, NSURLSession on iOS.

Platform

Networking Stack

Bypass Method

Android

OkHttp3

Standard OkHttp CertificatePinner hook

iOS

NSURLSession

Standard SecTrust hooks

Android (Hermes)

Same OkHttp

Same hooks, but Hermes JIT may need additional handling

// React Native Android — same as OkHttp bypass

Java.perform(function() {

    try {

        var CP = Java.use('okhttp3.CertificatePinner');

        CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {};

    } catch(e) { console.log('OkHttp3 not found, trying okhttp2...'); }

    try {

        var CP2 = Java.use('com.squareup.okhttp.CertificatePinner');

        CP2.check.overload('java.lang.String', 'java.util.List').implementation = function() {};

    } catch(e) {}

});

4.3 Xamarin

// Xamarin pinning typically via:

// ServicePointManager.ServerCertificateValidationCallback

// or custom HttpClientHandler
// Frida bypass for Xamarin (Mono runtime)

// Hook Mono method: System.Net.ServicePointManager.set_ServerCertificateValidationCallback

var mono_method = Module.findExportByName('libmonosgen-2.0.so',

    'mono_runtime_invoke');

// More practical: hook the managed callback at CIL level

// Use Frida's Mono bridge or objection's built-in Xamarin support

// Objection has built-in Xamarin bypass:

// objection -g com.target.app explore

// > android sslpinning disable   (covers Xamarin on Android)

5. CERTIFICATE TRANSPARENCY &#x26; HPKP

Technology

Status

Impact on Testing

Certificate Transparency (CT)

Active, enforced by browsers

Mobile apps rarely enforce CT; not a bypass obstacle

HPKP (HTTP Public Key Pinning)

Deprecated (2018)

Legacy apps may still check; remove header from proxy response

Expect-CT header

Deprecated (2024)

Minimal impact on mobile testing

CT in mobile apps

Rare

Only Google apps enforce via custom CT checks

6. TROUBLESHOOTING

6.1 Common Failures

Symptom

Cause

Fix

Bypass script loaded but traffic still fails

Multiple pinning layers

Hook ALL layers: TrustManager + OkHttp + custom checks

"Client certificate required"

Mutual TLS (mTLS)

Extract client cert from app bundle/keychain, import into proxy

Connection works but no HTTP traffic

Non-HTTP protocol (MQTT, gRPC, WebSocket)

Use Wireshark or protocol-specific proxy

App crashes after bypass

Anti-tampering detects hooks

Bypass integrity checks first, then SSL

Proxy CA not trusted

Android 7+ user CA restrictions

Install CA as system cert (Magisk module)

Flutter app ignores hooks

BoringSSL not hooked at native layer

Use reflutter or native BoringSSL hooks

Certificate chain validation timeout

OCSP stapling mismatch

Disable OCSP checks or mock OCSP responder

6.2 Diagnostic Steps

# Verify proxy CA is installed correctly

# Android:

adb shell "ls /system/etc/security/cacerts/ | grep $(openssl x509 -subject_hash_old -in ca.pem | head -1)"

# iOS: Settings → General → About → Certificate Trust Settings

# Check if target app is actually using SSL (vs. plain HTTP)

# Wireshark filter: tcp.port == 443 and ip.addr == <device_ip>

# Check if Frida is hooking the right process

frida-ps -U | grep target

# Verbose Frida output for debugging hooks

frida -U -f com.target.app -l bypass.js --debug

7. SSL PINNING BYPASS DECISION TREE

Need to intercept mobile app HTTPS traffic

│

├── Platform?

│   ├── Android ↓

│   │   ├── Rooted device available?

│   │   │   ├── Yes → Frida universal bypass (§2.1) [FIRST TRY]

│   │   │   │   ├── Works? → done

│   │   │   │   └── Fails? → add Conscrypt + Volley hooks

│   │   │   ├── Still fails? → LSPosed + TrustMeAlready (§2.4)

│   │   │   └── Still fails? → install CA as system cert (§2.5)

│   │   └── No root?

│   │       ├── Debug build? → Network Security Config (§2.3)

│   │       └── Release build? → decompile + patch + repackage (§2.6)

│   │

│   └── iOS ↓

│       ├── Jailbroken device available?

│       │   ├── Yes → Objection ios sslpinning disable (§3.2) [FIRST TRY]

│       │   │   ├── Works? → done

│       │   │   └── Fails? → Frida SecTrust hooks (§3.1)

│       │   ├── Still fails? → SSL Kill Switch 2 (§3.3)

│       │   └── Still fails? → library-specific hooks (§3.4)

│       └── No jailbreak?

│           ├── Re-sign with Frida gadget → run Frida hooks

│           └── Binary patch → sideload (§3.5)

│

├── Framework-specific app?

│   ├── Flutter → reflutter tool or BoringSSL native hooks (§4.1)

│   ├── React Native → standard platform hooks (§4.2)

│   └── Xamarin → Objection or Mono runtime hooks (§4.3)

│

├── Bypass works but issues remain?

│   ├── Client cert required? → extract + import to proxy (§6.1)

│   ├── Non-HTTP protocol? → protocol-specific tooling (§6.1)

│   └── App crashes? → fix anti-tampering first (§6.1)

│

└── All methods fail?

    ├── Analyze traffic at network level (Wireshark/tcpdump)

    ├── Check for custom proprietary protocol

    └── Consider iptables + transparent proxy approach

8. PROXY SETUP QUICK REFERENCE

Proxy Tool

Best For

SSL Bypass Integration

Burp Suite

Full HTTP analysis

Import CA to device

mitmproxy

Scripted interception

mitmproxy --set confdir=~/.mitmproxy

Charles Proxy

macOS-native, easy setup

Built-in CA installation

Proxyman

macOS/iOS native

Direct iOS device support

HTTP Toolkit

Quick Android setup

Automated CA + Frida bypass

# Android proxy setup

adb shell settings put global http_proxy <host_ip>:8080

# Remove proxy

adb shell settings put global http_proxy :0

# iOS proxy: Settings → Wi-Fi → Configure Proxy → Manual
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card