ssl pinning是抓包https流量的主要障碍,需用frida等工具绕过;加密流量多为aes/cbc/base64或rsa+aes混合加密,密钥常源于初始化流程、本地存储或服务端配置;python解密须严格匹配java的iv、密钥长度、编码及pkcs5填充,动态密钥需结合frida hook与算法复现。

抓包前先确认App是否用了SSL Pinning
绝大多数金融、社交类App都启用了SSL Pinning,直接用Fiddler或Charles抓HTTPS流量会失败,表现为连接被重置或证书错误。此时ssl_pinning是拦路虎,不是代理配置问题——得先绕过它。
常见现象:javax.net.ssl.SSLHandshakeException、ERR_SSL_PROTOCOL_ERROR(Android WebView)、iOS上NSURLSessionTaskDidCompleteWithError带-999错误码。
- Android:可用Frida hook
OkHttpClient或TrustManager,注入脚本禁用证书校验,例如hookX509TrustManager.checkServerTrusted并直接return - iOS:需越狱后用Frida或Cycript patch
SecTrustEvaluate,或使用Objection运行ios sslpinning disable - 静态分析更稳妥:用JADX反编译APK,搜索
setPinnedCertificates、trustManager、NetworkSecurityConfig,确认pinning是否硬编码在assets或raw目录
抓到加密流量后识别加解密逻辑位置
抓包得到的data字段通常是AES/CBC/Base64或RSA+AES混合加密结果,但密钥和IV几乎不会明文出现在请求里——它们来自App启动时的初始化流程或本地存储。
关键定位点:
- 搜索Java/Kotlin代码中的
AES/CBC/PKCS5Padding、SecretKeySpec、IvParameterSpec调用链,重点关注网络请求封装类(如ApiService、RequestInterceptor) - 检查
SharedPreferences(Android)或NSUserDefaults(iOS)是否存了session_key、device_id_encrypted等键名,这些常是动态生成的对称密钥来源 - 留意App首次启动时的
/init或/config接口响应,服务端常返回RSA公钥或AES密钥种子,后续所有请求用它派生
用Python还原Java的AES/CBC解密逻辑
Android常用Cipher.getInstance("AES/CBC/PKCS5Padding"),但Python的pycryptodome默认用PKCS7填充,直接解密会报ValueError: Padding is incorrect。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
实操要点:
- 确保IV长度为16字节,且与Java中
new IvParameterSpec(ivBytes)完全一致(注意Java byte[]是signed,Python bytes是unsigned,但解密时无需转换符号) - 密钥必须是16/24/32字节,若Java用
SecretKeySpec(keyString.getBytes(), "AES"),需确认其getBytes()编码——通常是UTF-8,不是系统默认编码 - Base64解码后要先去除PKCS5填充:用
unpad(cipher.decrypt(data), block_size=16),别用strip(b'\x00')这类粗暴方式
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64
<p>key = b'your_32_byte_aes_key_here' # 必须严格32字节
iv = b'16_bytes_iv_here' # 必须严格16字节
encrypted_b64 = "U2FsdGVkX1+..." # 抓包拿到的data字段</p><p>cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(base64.b64decode(encrypted_b64)), 16)
print(decrypted.decode('utf-8'))</p>
动态密钥场景下别硬编码密钥字符串
很多App每次启动生成新AES密钥,通过RSA公钥加密后传给服务器,再由服务端用私钥解出——这意味着你抓到的每个请求可能用不同密钥,且密钥本身被RSA加密过。
这时候Python解密不能只靠静态分析:
- 用Frida hook Java层的
RSAEngine.processBlock或Cipher.doFinal,把输入输出dump出来,逆向出密钥生成逻辑 - 若密钥来自设备指纹(如
Build.SERIAL+ANDROID_ID),需在Python里复现相同哈希算法(注意Java的MessageDigest.getInstance("SHA-256")和Pythonhashlib.sha256()结果一致,但拼接顺序和编码必须完全相同) - 别忽略时间因子:有些App把
System.currentTimeMillis() / 60000(分钟级时间戳)参与密钥派生,抓包时间差几分钟就解不开
真正难的从来不是解密算法本身,而是密钥怎么来——它往往藏在JNI层的.so文件里,或者由硬件级API(如Android Keystore)生成,这种情况下Python只能模拟整个App的密钥派生流程,没法单靠一段解密代码搞定。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










