Well, since you are here, you are probably planning to spy on traffic generated by the apps on your phone, probably looking to find out what apps are leaking your private information !
How this all works: When an application on your phone contacts a website/web-server over a secure connection, your phone checks the certificate, and checks whether or not that certificate was issued by an authority the phone trusts, what we are doing is telling the phone to add YOU to the list of trusted authorities, then, we create a proxy that the phone connects through (mitmproxy). Now, the proxy contacts the website on behalf of the application that sent the request, gets the response / contents of that page, saves a copy of that response, and repackages it using our own security certificate, then sends it to the phone, at this stage, the phone thinks the certificate belongs to the website it was contacting (Because now it trusts you), and everything works as it normally would. This does not work if the app has a pinned certificate, a pinned certificate is when an app does not trust the list of authorities the system maintains and requires a certain certificate, but this too has a workaround !
here is what you need to do.
I am assuming you already have a rooted virtual android device (AVD), if not, here are the instructions, in my case, even though it is mid 2026, i decided to go with a Google Pixel 6 with android 12 (The pixel six has updates up to the most current Android 17, but i decided to go with Android 12)
You need to create a root certificate, and install it in both mitmproxy and android, the mitmproxy gets the pem file with the certificate and private key (So that it can create certificates for websites on the fly), while android gets the one with the certificate (Obviously)
1- Gnerate the private key
openssl genrsa -out android-mitm-ca.key 4096
2 – Create the CA certificate
openssl req -x509 -new -sha256 -key android-mitm-ca.key -out android-mitm-ca.crt -days 3650 -subj "/C=JO/O=Android Traffic Analysis/CN=Android MITM Analysis CA" -addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign,cRLSign"
3- Installing mitmproxy (On your debian machine)
install Prerequisites:
sudo apt install python3-dev libffi-dev libssl-dev libxml2-dev libxslt1-dev libjpeg-dev zlib1g-dev
Debian 13 does not have it in repositories (12, and 14 do !), so we need to install from binaries downloaded from the website ! so i put them in /opt/mitmproxy and symlinked the files in /usr/local/bin
4- Concatinate/combine key and cert into 1 file for the mitmproxy
cat android-mitm-ca.key android-mitm-ca.crt > ~/.mitmproxy/mitmproxy-ca-my.pem
chmod 600 ~/.mitmproxy/mitmproxy-ca-my.pem
5- running and check that mitmproxy is using our cert
First, run mitmproxy.
NO-GO: mitmproxy –listen-host 192.168.7.119 –listen-port 8080 –certs “*=$HOME/.mitmproxy/mitmproxy-ca-my.pem” (No go because certs is for individual domains)
NO-GO:
mitmproxy --certs "*=$HOME/.mitmproxy/mitmproxy-ca-my.pem"
Or if needed
mitmproxy --listen-host 192.168.7.119 --listen-port 8080 --set confdir="$HOME/.mitmproxy-my"
Or if you want access from outside your network
mitmproxy --listen-host 192.168.7.129 --listen-port 8080 --set block_global=false --set confdir="$HOME/.mitmproxy-my"
From another terminal, let us try to get the contents of example.com through the proxy:
openssl s_client -proxy 192.168.7.119:8080 -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject
Now, if the proxy works as intended, and is correctly signing our requests with our own certificate, we should see something like isuer: Android MITM Analysis CA (The name we chose)
So, now our proxy is ready and serving, all that remains is relevant to Android, we have already made the android certificate to add (OUR_HASH.0)
Installing the certificate on the android phone
The only thing that is confusing about this section is that not all android phones work in the same way ! I am deliberately using Android 12 (Will install most software while being somewhat easier to tinker with), you on the other hand may be using android 16 or 17 (The latest at the time of writing).
Also, I am using a virtual android phone (With Android Studio), you may be using an actual rooter physical phone !
So, I will outline when something is going to be different on other android versions, and you will have to figure it out (Use Google, or gemini or something)
6- Certificate File Name for android
figure out the hash for the filename of the Android file (The file name should be “hash.0”, replace hash with the actual hash resulting from the below) this is how android expects the file name to be
HASH=$(openssl x509 -inform PEM -subject_hash_old -in android-mitm-ca.crt | head -1)
echo "$HASH"
Now, copy the file android-mitm-ca.crt and name the copy the same as the resulting hash with an added .0 at the end (THEHASH.0)
7- If android 16+ (I am using 12, but if you have 16+)
If your rootAVD image is Android 16 or above, don’t blindly follow the old /system/etc/security/cacerts/ procedure. Android 16 changed the system certificate location, and current mitmproxy documentation has a separate procedure involving a Magisk certificate-moving module.
check your android version
adb shell getprop ro.build.version.release
adb shell getprop ro.build.version.sdk
adb shell getprop ro.product.cpu.abi
adb shell su -c 'id'
$ adb shell getprop ro.build.version.release
12
$ adb shell getprop ro.build.version.sdk
31
$ adb shell getprop ro.product.cpu.abi
x86_64
$ adb shell su -c ‘id’
uid=0(root) gid=0(root) groups=0(root) context=u:r:magisk:s0
So, in my case, I am running android 12 ! Software development kit 31 (API level), X86 cpu, and (context=u:r:magisk:s0)
8- Explore the filesystem
Let us check and explore the files and folders on filesystem
> adb shell su -c 'ls -ld /system/etc/security/cacerts'
drwxr-xr-x 2 root root 4096 2023-07-26 23:02 /system/etc/security/cacerts
> adb shell su -c 'mount | grep -E " /system | / "'
/dev/block/dm-4 on / type ext4 (ro,seclabel,relatime)
> adb shell su -c 'ls -l /system/etc/security/cacerts | head'
total 952
-rw-r--r-- 1 root root 2871 2023-07-26 23:02 01419da9.0
-rw-r--r-- 1 root root 2914 2023-07-26 23:02 04f60c28.0
-rw-r--r-- 1 root root 2345 2023-07-26 23:02 0d69c7e1.0
-rw-r--r-- 1 root root 4622 2023-07-26 23:02 10531352.0
-rw-r--r-- 1 root root 4724 2023-07-26 23:02 111e6273.0
-rw-r--r-- 1 root root 4308 2023-07-26 23:02 12d55845.0
-rw-r--r-- 1 root root 2599 2023-07-26 23:02 1ae85e5e.0
-rw-r--r-- 1 root root 4931 2023-07-26 23:02 1df5a75f.0
-rw-r--r-- 1 root root 4535 2023-07-26 23:02 1e1eab7c.0
So, we do have the path /system/etc/security/cacerts on the phone, system (See second command above) is mounted read only, there are 952 certificate files in the /system/etc/security/cacerts folder.
Reminder: On Android 12, the traditional system CA location we’re interested in is: /system/etc/security/cacerts/ , The certificates are stored there using the OpenSSL subject-hash filename convention, e.g.: xxxxxxxx.0
The plan at this stage is to use magisk to add our certificate as an overlay, this way, we don’t need to modify the actual system, meaning, we will not be mounting system in read-write mode, read-only is fine by us
9- Explore Magisk
So let us start by checking what version of MAGISK is installed on the phone, and where it lives
> adb shell su -c 'magisk -v'
26.4:MAGISK:R
> adb shell su -c 'magisk --path'
/debug_ramdisk
> adb shell su -c 'ls -la /data/adb/modules'
total 24
drwxr-xr-x 3 root root 4096 2026-08-26 12:05 .
drwx------ 6 root root 4096 2026-08-26 12:11 ..
drwxr-xr-x 3 root root 4096 2026-08-26 12:07 hosts
Since this is rootAVD/Magisk, the clean approach is to use a Magisk overlay so we don’t modify the underlying system image.
10- Create the Magisk module with the certificate in it !
we can create our own small Magisk module specifically for the CA without touching the original system image. (the only existing module is hosts)
To create a magisk module we need to do the following
10.1- Create an identical folder structure on my debian machine *(Yours can be windows)
mkdir -p ~/.mitmproxy/module/system/etc/security/cacerts
Move your certificate (xxxxx.0) to the cacerts folder we created above
Now create the module file (Module dfinition file), obviously you can create it with a text editor as well if you wish.
cat > ~/.mitmproxy/module/module.prop <<'EOF'
id=android-mitm-ca
name=Android MITM Analysis CA
version=1.0
versionCode=1
author=Voodoo
description=Custom CA certificate for controlled Android traffic analysis
EOF
Now, put the contents of the module directory (Without the module directory itself) in a zip file
cd ~/.mitmproxy/module
zip -r ../android-mitm-ca.zip .
Now, open the zip file in fileroller (or 7-zip or winrar, whatever suits you) and make sure we have
module.prop
system/
system/etc/
system/etc/security/
system/etc/security/cacerts/
system/etc/security/cacerts/XXXXXXXX.0
If all looks good, super, we have the zip file for android…. go ahead and push it to the android virtual machine
> adb push ~/.mitmproxy/android-mitm-ca.zip /data/local/tmp/
Now, when the above works, install the zip file with magisk
> adb shell su -c 'magisk --install-module /data/local/tmp/android-mitm-ca.zip'
- Device is system-as-root
**************************
Android MITM Analysis CA
by Voodoo
**************************
*******************
Powered by Magisk
*******************
- Extracting module files
- Done
If you get an error above DO NOT REBOOT, only reboot if you get a message like the one i got. if not, Sorry man, you need to reverse the steps above ! something with the rootAVD restore command should do
Now, after rebooting (adb shell reboot), run this to see if our certificate appears !
adb shell su -c 'ls -l /system/etc/security/cacerts/'
Looks fine to me, but let us double check (replace the xxx with your actual file name)
adb shell su -c “ls -l /system/etc/security/cacerts/xxxxxx.0”
-rw-r–r– 1 root root 2000 2026-08-27 20:28 /system/etc/security/cacerts/xxxx.0
And if everything was done correctly, “adb shell su -c ‘mount | grep ” / “‘” should still show read-only
Now, let us play, I am very skeptical that this would work (Unless your android has openssl), but it can’t hurt to try… anyway, failiure here means nothing is the error is that “openssl: inaccessible or not found”, it is expected, and means nothing
adb shell su -c "openssl x509 -in /system/etc/security/cacerts/fea8a918.0 -noout -subject -issuer"
Pinned certificates
there are ways to get around this, ways from things as simple as using apk-mitm to remove the pinning, all the way to more serious stuff such as using jadx to modify the software before playing this game.
Here are some tools that can come in handy for this
- FRIDA: Lets you inject snippets of JavaScript or your own library into native apps + simple tools built on top of the Frida API.
- APK-MITM: (https://github.com/shroudedcode/apk-mitm): Remove certificate pinning from APK files
- objection is a runtime mobile exploration toolkit powered by Frida, which supports certificate pinning bypasses on iOS and Android.
- ssl-kill-switch2 blackbox tool to disable certificate pinning within iOS and macOS applications.
- android-unpinner : From the same people who make the MITMPROXY, it modifies Android APKs to inject Frida and HTTP Toolkit’s unpinning scripts.
apk-mitm
node --version
npm --version
sudo apt install zip unzip
npm install -g apk-mitm
Now, to remove the pinning in your app
apk-mitm <path-to-apk>