Charles抓包实战:某APP HTTPS请求解密与接口逻辑还原
免责声明本文所述技术仅用于授权安全测试、接口调试及逆向工程学习。文中“某APP”已做脱敏处理所有分析均在本地测试环境完成。未经授权对生产系统进行抓包、解密或数据提取可能违反《网络安全法》及《数据安全法》请严格遵守法律法规与目标应用的服务条款。0. 为什么你的Charles抓不到有效数据很多开发者在调试移动端APP时都遇到过这样的困境Charles证书已安装、代理已配置但抓到的HTTPS请求要么是乱码要么关键参数被二次加密甚至APP直接拒绝联网。这背后是三重防护在起作用SSL Pinning证书绑定APP内置了服务器证书指纹拒绝信任用户安装的CA证书参数签名/加密即使拿到明文HTTPS流量请求体中的sign、token等字段仍是密文或哈希值协议层混淆部分APP使用自定义Protobuf、FlatBuffers或非标准JSON序列化导致Charles解析失败。本文将以一款电商类APP为例完整演示从绕过SSL Pinning → 解密HTTPS流量 → 定位加密算法 → 还原接口签名逻辑的全链路实战过程。所有工具链均基于2024年主流方案避免过时教程的坑。1. 环境准备搭建可抓包的测试基线1.1 设备与工具选型组件推荐方案避坑说明Android设备Pixel 6 / 7 (Android 13)避免国产ROM魔改网络栈Root方案Magisk Zygisk系统级hook需Zygisk支持SSL UnpinningLSPosed TrustUserCerts比JustTrustMe更稳定抓包工具Charles 4.6.5 / mitmproxy 9.xCharles GUI友好mitmproxy脚本灵活反编译jadx-gui 1.5 / Frida 16.xjadx看Java层Frida动态追踪Native1.2 证书安装关键步骤Android 13Android 13起用户证书默认不被APP信任必须将其转为系统证书# 1. 导出Charles根证书为PEM格式# Charles: Help → SSL Proxying → Save Charles Root Certificate# 2. 计算证书哈希并重命名openssl x509-informPEM-subject_hash_old-incharles-proxy-ssl-proxying-certificate.pem|head-1# 假设输出: a1b2c3d4# 3. 重命名为系统证书格式mvcharles-proxy-ssl-proxying-certificate.pem a1b2c3d4.0# 4. 挂载系统分区并复制需rootadb root adb remount adb push a1b2c3d4.0 /system/etc/security/cacerts/ adb shellchmod644/system/etc/security/cacerts/a1b2c3d4.0 adbreboot⚠️注意若使用Magisk模块TrustUserCerts可跳过手动操作但需确认模块版本适配当前Android版本。2. 突破SSL Pinning让HTTPS流量可见2.1 静态分析定位Pinning点用jadx打开APK全局搜索关键词X509TrustManager SSLSocketFactory CertificatePinner (OkHttp) NetworkSecurityConfig典型发现该APP在com.app.network.SSLHelper中自定义了X509TrustManager并在checkServerTrusted方法中硬编码了证书SHA-256指纹。2.2 Frida动态绕过编写hook脚本解除证书校验// ssl_unpin.jsJava.perform(function(){// Hook OkHttp CertificatePinnervarCertPinnerJava.use(okhttp3.CertificatePinner);CertPinner.check.overload(java.lang.String,java.util.List).implementationfunction(hostname,peerCertificates){console.log([*] Bypassed CertificatePinner for: hostname);return;// 直接返回不抛异常};// Hook 自定义TrustManagervarSSLHelperJava.use(com.app.network.SSLHelper$1);SSLHelper.checkServerTrusted.implementationfunction(chain,authType){console.log([*] Bypassed custom TrustManager);return;};// 通用兜底Hook X509TrustManager接口varX509TMJava.use(javax.net.ssl.X509TrustManager);X509TM.checkServerTrusted.implementationfunction(chain,authType){// 不做任何校验};});执行frida-U-fcom.target.app-lssl_unpin.js --no-pause此时Charles应能正常显示HTTPS请求内容。若仍失败检查是否触发了双向认证客户端证书需额外导出APP内置的client.p12。3. 解密加密参数从密文到明文3.1 识别加密类型观察Charles中捕获的请求体{data:aGVsbG8gd29ybGQ,sign:e10adc3949ba59abbe56e057f20f883e,timestamp:1717200000,version:3.2.1}初步判断data字段Base64解码后为明文业务数据sign为32位十六进制字符串疑似MD5但修改任意参数后重放请求服务端返回{code:403,msg:invalid sign}说明签名逻辑非简单拼接。3.2 定位签名算法入口在jadx中搜索sign赋值位置找到com.app.utils.SignUtil.generate()方法。但其内部调用了Native方法nativeSign()Java层无实现。3.3 Frida追踪Native加密// trace_native_sign.jsvarmoduleNamelibcrypto.so;varbaseAddrModule.findBaseAddress(moduleName);// 通过导出名或特征码定位函数此处以导出名为例varnativeSignAddrModule.findExportByName(moduleName,Java_com_app_utils_SignUtil_nativeSign);Interceptor.attach(nativeSignAddr,{onEnter:function(args){// args[0]JNIEnv, args[1]jclass, args[2]jstring(待签名串), args[3]jstring(key)varenvJava.vm.getEnv();varstrPtrenv.getStringUtfChars(args[2],null);varkeyPtrenv.getStringUtfChars(args[3],null);this.inputStrstrPtr.readCString();this.keykeyPtr.readCString();console.log([NativeSign] Input: this.inputStr);console.log([NativeSign] Key: this.key);},onLeave:function(retval){varenvJava.vm.getEnv();varresultStrenv.getStringUtfChars(retval,null).readCString();console.log([NativeSign] Output: resultStr);}});运行后发现实际签名逻辑为sign MD5( timestamp | version | data_json | secret_key )其中secret_key为硬编码常量a1b2c3#$%且data_json需按key字典序排序后再参与运算。4. 接口逻辑还原与验证4.1 构建签名生成器importhashlibimportjsonimporttimedefgenerate_sign(data_dict:dict,version:str3.2.1)-dict:timestampstr(int(time.time()))secret_keya1b2c3#$%# data按key字典序排序sorted_datajson.dumps(data_dict,sort_keysTrue,separators(,,:))raw_strf{timestamp}|{version}|{sorted_data}|{secret_key}signhashlib.md5(raw_str.encode()).hexdigest()return{data:base64.b64encode(sorted_data.encode()).decode(),sign:sign,timestamp:timestamp,version:version}4.2 重放验证将生成的参数填入Charles Composer或Postman重放请求服务端正常返回业务数据证明逻辑还原正确。5. 完整分析流程图否否是是否否是安装系统级CA证书HTTPS流量可见?Frida Hook SSL Pinning流量解密成功?检查双向认证/自定义协议识别加密参数字段jadx静态定位加密入口Java层有实现?直接还原算法Frida Trace Native函数记录输入输出推导逻辑构建签名生成器重放验证验证通过?补充Hook点/修正排序规则完成接口逻辑还原6. 高阶场景与注意事项6.1 应对动态密钥若secret_key由服务端下发或运行时生成需额外Hook密钥获取点。常见位置SharedPreferences读取Asset文件解密JNI回调返回值6.2 Protobuf/自定义协议解析当Charles显示二进制内容时在APK中搜索.proto文件或Protobuf相关类使用protoc --decode_raw尝试解析或通过Frida Hook序列化/反序列化方法在内存中捕获结构化数据。6.3 法律与伦理边界仅限授权测试未获书面许可的抓包分析属于非法侵入计算机信息系统禁止数据留存测试完成后立即删除所有抓包数据与解密结果不传播漏洞细节发现安全问题应通过官方渠道报告而非公开利用方式尊重知识产权逆向所得逻辑不得用于开发竞品或破解付费功能。7. 总结HTTPS抓包解密只是起点真正的价值在于理解接口设计意图与安全机制。本文展示的是一套可复用的方法论从环境搭建到Pinning绕过从静态分析到动态追踪最终回归到逻辑验证。技术上没有万能钥匙——随着APP加固手段升级如VMProtect、OLLVM分析成本将持续上升。但核心原则不变合法合规是前提最小必要是准则防御思维是归宿。如果你在授权测试中遇到具体问题欢迎评论区交流请勿提供真实APP名称或敏感信息。