My goal was to take a look at the HTTP requests that Instagram was making but, after setting an HTTP proxy, I couldn’t see anything. Turns out that Instagram is protected against MITM attacks using a technique called certificate validation (SSL Pinning) which compares the certificate provided by server in the TLS handshake with a trusted one embedded in APK.

This article is based on Instagram APK version 78.0.0.11.104 (x86) which you can download here. I am also using an Android 8.0 emulator with adb running as root.
Disclaimer
The sole purpose of this article is educational and for testing of your own applications. This is not intended for piracy or any other non-legal use.
Setting up Burp to work with TLS 1.3
Facebook deployed TLS 1.3 at very large scale with their open source library Fizz. It doesn’t surprise me that they decided to use it on their Instagram application to make internet traffic more secure.
This time I decided to use Burp to capture requests that Instagram app is making. After setting up the proxy, some weird alert appears in the Alerts tab.

What is this weird “no cipher suites in common” message? Looks like this version of Burp does not support TLSv1.3 cipher suites. We can verify this by going to Project Options > SSL and list all ciphers.
A simple solution to this problem is to run Burp with the latest version of JDK. At that point, you can run burpsuite_community.jar with the newly extracted java binary taken from JDK:
./Downloads/jdk-11.0.2.jdk/Contents/Home/bin/java -jar burpsuite_community.jar
This time after opening Instagram app we get a different message from Alerts tab.

Now we get a different (fatal) alert: bad_certificate which tells us that the certificate provided by Burp is not accepted by the client. We have to dig deeper into the app internals to get around this issue.
Patching Native Layer
Android applications can interact with native (C/C++) code using Java Native Interface (JNI). You can read more about it here. Instagram loads many native libraries from /data/data/com.instagram.android/lib-zstd which is created after the first app launch.
~ adb pull /data/data/com.instagram.android/lib-zstd
~ grep lib-zstd -re fizz
Binary file lib-zstd/libliger.so matches
Bingo! Let’s launch IDA Pro to take a look at this shared object file. After reading source code, I spotted the exception which was causing this bad_certificate issue.

Let’s search for strings using IDA (View > Open Subviews > Strings).
At offset 002831F4 on read-only section (.rodata) we can see the constant we were looking for.

IDA is pointing us to the subroutine sub_3C864 which is using it. After analysing the flow, we can apply a simple patch at the offset 0003CD4D patching JNZ to JZ so exception is no longer thrown!

Let’s apply the patches (Edit > Patch Program > Apply patches to input file) and push the newly patched libliger.so to the device.
adb push libliger.so /data/data/com.instagram.android/lib-zstd/libliger.so
Now Burp complains with a weird alert:

That’s weird. Analysing traffic with Wireshark didn’t help much and gave me no additional clues. Next step was to debug Android smali code using Android Studio (you can find an useful article here).
I followed this StackOverflow reply to catch any exception and this shows up shortly after:

This looks interesting. Let’s go back to IDA and search for the string constant “openssl cert verify error“. Match on offset 00295732 used by subroutine sub_176434. Similarly to what we’ve dove before, we can patch this subroutine to avoid throwing this exception.

Patch JNZ to JZ, apply to input file and open Burp.

Jackpot! We can now be the man in the middle and take a look at the “private” Instagram API.
This is the most detailed and most understandable step by step reverse engineering tutorial for instagram apk. Thank you very much Marco!
Thanks, I’m glad you enjoyed it 🙂
hi marco,
“b”.i.instagram.com
“graph”.instagram.com
burp alert = unknown_ca
solve?
thank you.
Hi,
Thanks, but I did everything you did with no success.
Still can’t read all requests
Thanks for your share! really good work!
How do you intercept the request from emulator with burp? The only way I know is with linux and redirecting with iptables
Set up Burp to listen on the LAN interface and set the HTTP proxy on emulator (if you run the emulator with CLI, pass the -http-proxy flag)
wooow. Thanks !!!!
Can you patched APK here ? (Link For Download)
I need patched apk sir.😊😊😊 thank you
Thank you so much for writing this! You have no idea how many months I’ve spent trying to find a solution to bypassing Instagram pinning to no avail. I didn’t even know they use TLS 1.3. I will try this out soon! You should consider making a tool that automatically patches the error message.
Can you upload your patched file?
plz upload libliger.so patched file bro
I have patched it, but it’s not worked
Bump on the upload of patched file ^^
[…] How to bypass Instagram SSL Pinning on Android (v78) […]
I patched same no traffic. Please share your libliger.so.
https://github.com/itsMoji/Instagram_SSL_Pinning
please can you share apk patched? thanks!
Would be awesome if you could share the libliger.so file indeed. Thanks for this tutorial!
Hi Marco Genovese,
This is quite helpful to me. Could you leave a email? I want to have some communicate with you, thanks.
Can you please bypass snapchat’s ssl pinning? I’ve tried everything, but new version is hard af
https://github.com/itsMoji/Instagram_SSL_Pinning
Thanks for this awesome piece of tutorial. I have read all methods available on internet but none worked except yours. Finally a noob is able to view api requests .
For readers …. No article or git repo works except this one. Make sure you follow every step. It took me 2 days since i wasn’t following it exactly. Thanks again Marco
How did you find the Offset 00295732 value, I don’t understand, how can you find it.
https://github.com/mgp25/Instagram-API/wiki/Technical-information
find this https://hydra2020gate.com
Hi, I’m trying with the latest instagram version,
I opened “libliger.so” with IDA and saw the function “verifier failure” but couldn’t find where is using JNZ to compare ssl_cert.
Please help.