从对抗到出洞:某金融APP 实战渗透与 Frida 反检测绕过(Rpc + Flask + AutoDecoder)
字数 4054 2025-10-18 11:17:50

某金融APP通信协议逆向分析与自动化加解密实战教学文档

文档概述

本教学文档基于一篇实战技术文章,详细讲解了如何对一个采取了高强度加密和反调试措施的金融类Android APP进行渗透测试。核心挑战在于破解其自定义的通信加密协议,并绕过其基于Frida的检测机制。最终目标是实现一个自动化的加解密服务(RPC Server),便于安全研究人员进行接口重放、漏洞挖掘和安全性评估。

技术栈关键词: Android逆向FridaRPCFlaskAESHMACTLS握手反调试绕过


第一章:挑战与目标

1.1 面临的挑战

  1. 反Frida检测: APP内置了检测机制,当Frida注入后,一旦调用Java.use等关键API,应用会立即闪退。
  2. 复杂的通信加密: 请求和响应体均为加密的JSON格式,加密算法位于Native层(C/C++),而非Java层,增加了分析难度。
  3. 动态密钥: 加密所用的密钥(AES密钥、IV等)并非硬编码在代码中,而是通过一个类似TLS握手的过程动态生成,每次启动APP都会变化。

1.2 渗透目标

  1. 绕过反Frida检测,成功将Frida注入到目标APP中。
  2. 逆向分析出完整的通信数据加解密流程。
  3. 定位并提取动态生成的加密密钥。
  4. 构建一个自动化RPC服务,提供加密和解密接口,支持对抓取的数据包进行解密分析和对修改后的数据进行加密重放。

第二章:技术分析与破解流程

2.1 阶段一:绕过Frida反调试检测

问题现象: Frida可以注入,但执行Java.use()时APP崩溃。

解决方案(二选一):

方案A:编译Frida Java Bridge

  1. 原理: 官方的Frida Java.use等API特征明显,容易被检测。通过编译Frida的frida-java-bridge模块,可以改变这些API的底层实现方式,从而绕过基于特征码的检测。
  2. 操作步骤:
    • 参考提供的视频教程,搭建Node.js环境。
    • 使用frida-compile工具将自定义的Agent脚本(包含对Java层的操作)编译成一个单独的、优化过的_agent.js文件。
    • 注入时,直接加载这个编译后的_agent.js文件,而非原始的、特征明显的Frida API脚本。

方案B:使用ZygiskFrida

  1. 原理: 这是一个开源项目,它将Frida集成到Magisk的Zygisk模块中。它通过修改Android系统底层(Zygote进程)的加载方式,实现了更深层次的注入和更隐蔽的存在,从而有效规避了常规的Frida检测。
  2. 操作步骤:
    • 确保手机已解锁Bootloader并刷入Magisk(支持Zygisk)。
    • 安装ZygiskFrida模块并重启手机。
    • 之后即可像正常使用Frida一样进行注入,检测功能已被绕过。

推荐: 对于新手,方案B(ZygiskFrida) 更为简单可靠。

2.2 阶段二:逆向分析加密流程

1. 抓包初步分析

  • 请求/响应体格式:{"key": "Base64EncodedEncryptedData"}
  • 关键请求头:X-Emp-Signature,用于数据签名验证。

2. 定位签名算法(突破口)

  • 使用逆向工具(如Jadx-GUI)反编译APP,全局搜索字符串X-Emp-Signature
  • 定位到initHttpRequest方法,发现其调用了encryptHMAC方法。
  • 分析encryptHMAC,确认其使用HmacSha1(或可配置的国密SM3)算法对数据进行签名。

3. 定位请求体加密入口

  • 由于加密可能在Native层,直接阅读Java代码逻辑更高效。在Jadx中查找initHttpRequest方法的调用者,向上追溯。
  • 最终定位到sendRequest方法,其中调用了handleRequestBody方法来处理请求体加密。
  • 关键代码逻辑分析(handleRequestBody):
    • byte[] rnc = new byte[16]; ... new SecureRandom().nextBytes(rnc); 生成一个16字节的随机数(RNC)。
    • 将RNC与原始的JSON请求体字节数组合并(RNC + RequestBody)。
    • 调用 AESCipher.encrypt(rncAndBody) 对合并后的数据进行AES加密。
    • 将加密结果与一个序列号(mSequence)拼接,然后计算HMAC签名。
    • 最终结构为:HMAC签名 || 序列号 || AES加密结果
    • 将整个结果进行Base64编码,并封装成{"key": "base64String"}的格式。

4. 解密流程推理
响应体的解密是加密的逆过程:

  • Base64解码响应体。
  • 分离出HMAC签名(用于验证数据完整性)、序列号和AES加密数据。
  • 使用正确的AES密钥和IV解密数据。
  • 解密后的数据前16字节是RNC,后面才是真正的JSON响应体。

2.3 阶段三:追踪动态密钥生成

核心问题: AES加密所需的clientKey_clientIv_是动态的。

1. 密钥生成点定位

  • 在Jadx中追踪AESCipher类,发现其clientKey_clientIv_的赋值在一个initSecret方法中。
  • initSecret方法的核心是这行代码:
    byte[] allSecret = PRFCipher.PRF(ms2, HMac.TLS_MD_CLIENT_SERVER_KEYIVMAC_CONST(), ms2RncRnsSeed, R2.attr.arrowHeadLength);
    
  • 这行代码是标准的TLS-PRF(Pseudo-Random Function) 实现,用于从主密钥(ms2)和随机数种子(ms2RncRnsSeed)派生出会话所需的多个密钥。

2. 逆向TLS握手流程

  • 继续追溯ms2(主密钥)的来源,最终定位到handleServerKeyExchange方法。该方法处理服务器发送的密钥交换信息(如RSA公钥加密的预主密钥)。
  • 进一步向上追溯,发现一个关键的HTTP请求(例如 /api/facility/serverHello),该请求的响应数据被用于计算主密钥ms2
  • 结论: APP启动时,会与服务器进行一次自定义的、简化版的TLS握手。通过这次握手,客户端和服务器协商出共享的主密钥ms2,然后双方使用相同的PRF函数,派生出完全一致的AES密钥、IV和HMAC密钥。

2.4 阶段四:Frida RPC实现自动化

由于密钥动态生成,硬编码密钥到Python脚本是不可行的。因此,采用Frida RPC(Remote Procedure Call)技术,在APP内存中直接调用其Java加密/解密方法。

1. Frida脚本核心任务
编写一个Frida脚本(agent.js),暴露(export)几个RPC函数给外部调用:

  • getKeys(): 获取当前会话的动态密钥(clientKey, clientIv, serverKey, serverIv, hmacKey)。
  • encryptData(data): 接收明文字符串,调用APP自身的handleRequestBody逻辑,返回加密后的Base64字符串。
  • decryptData(encryptedBase64): 接收加密的Base64字符串,调用APP自身的解密逻辑,返回明文字符串。

示例代码片段(概念性):

Java.perform(function () {
    var AESCipher = Java.use("com.xxx.AESCipher");
    var CryptoManager = Java.use("com.xxx.CryptoManager");

    // RPC函数:获取密钥
    rpc.exports.getKeys = function () {
        return {
            clientKey: Array.from(AESCipher.clientKey_.value),
            clientIv: Array.from(AESCipher.clientIv_.value),
            // ... 其他密钥
        };
    };

    // RPC函数:加密
    rpc.exports.encryptData = function (plainText) {
        var result = CryptoManager.handleRequestBody(plainText);
        return result;
    };
});

2. Python端与Flask服务器

  • 使用Python的frida库连接到设备上的APP进程,并加载上述agent.js脚本。
  • 利用flask框架创建一个轻量级的Web服务器。
  • 为每个RPC函数创建一个对应的API端点(endpoint)。

示例Flask端点:

import frida
from flask import Flask, request, jsonify

app = Flask(__name__)
session = None
script = None

@app.route('/encrypt', methods=['POST'])
def encrypt():
    data = request.json.get('data')
    encrypted_data = script.exports.encrypt(data)
    return jsonify({'encrypted_data': encrypted_data})

@app.route('/decrypt', methods=['POST'])
def decrypt():
    encrypted_data = request.json.get('data')
    decrypted_data = script.exports.decrypt(encrypted_data)
    return jsonify({'decrypted_data': decrypted_data})

if __name__ == '__main__':
    # 连接Frida并加载脚本的代码...
    device = frida.get_usb_device()
    pid = device.spawn(["com.xxx.financialapp"])
    session = device.attach(pid)
    with open("agent.js", "r") as f:
        script_code = f.read()
    script = session.create_script(script_code)
    script.load()
    device.resume(pid)
    app.run(host='0.0.0.0', port=5000)

第三章:实战操作流程总结

  1. 环境准备: 安装Frida、Python、ADB。Root手机并配置ZygiskFrida以绕过检测。
  2. 逆向分析: 使用Jadx静态分析APP,理清handleRequestBodyAESCipherPRFCipher等关键类的调用关系。
  3. 编写Frida RPC脚本: 根据分析结果,编写agent.js,暴露getKeysencryptData, decryptData等RPC函数。
  4. 部署Flask RPC服务器: 编写Python脚本,连接Frida,加载JS脚本,并启动Flask服务。
  5. 渗透测试:
    • 抓包: 使用Burp Suite或Charles抓取APP流量,得到加密的数据包。
    • 解密: 将抓到的加密数据({"key": "..."}中的值)发送到本地Flask服务器的/decrypt接口,即可获得明文。
    • 分析/修改: 分析明文JSON,发现潜在漏洞(如参数污染、越权等)。
    • 加密重放: 将修改后的明文发送到/encrypt接口,获得新的加密数据,替换原数据包中的内容,进行重放攻击。

第四章:核心知识点与工具清单

  • 核心知识点:
    • Frida动态插桩与反检测绕过
    • Android Java层与Native层逆向分析
    • TLS握手与密钥交换协议(PRF)
    • AES对称加密与HMAC签名
    • Frida RPC机制
    • Flask Web框架
  • 工具清单:
    • 逆向分析: Jadx-GUI
    • 动态调试: Frida, ZygiskFrida
    • 抓包工具: Burp Suite, Charles
    • 开发环境: Python 3, Flask库, frida-tools
    • Android环境: 已Root的Android手机/模拟器

通过以上步骤,您可以系统地完成对该金融APP的通信协议破解,并建立起一个强大的自动化测试平台。请注意,本文档仅用于安全研究和学习目的,请勿用于非法活动。

某金融APP通信协议逆向分析与自动化加解密实战教学文档 文档概述 本教学文档基于一篇实战技术文章,详细讲解了如何对一个采取了高强度加密和反调试措施的金融类Android APP进行渗透测试。核心挑战在于破解其自定义的通信加密协议,并绕过其基于Frida的检测机制。最终目标是实现一个自动化的加解密服务(RPC Server),便于安全研究人员进行接口重放、漏洞挖掘和安全性评估。 技术栈关键词: Android逆向 、 Frida 、 RPC 、 Flask 、 AES 、 HMAC 、 TLS握手 、 反调试绕过 第一章:挑战与目标 1.1 面临的挑战 反Frida检测: APP内置了检测机制,当Frida注入后,一旦调用 Java.use 等关键API,应用会立即闪退。 复杂的通信加密: 请求和响应体均为加密的JSON格式,加密算法位于Native层(C/C++),而非Java层,增加了分析难度。 动态密钥: 加密所用的密钥(AES密钥、IV等)并非硬编码在代码中,而是通过一个类似TLS握手的过程动态生成,每次启动APP都会变化。 1.2 渗透目标 绕过反Frida检测 ,成功将Frida注入到目标APP中。 逆向分析 出完整的通信数据加解密流程。 定位并提取 动态生成的加密密钥。 构建一个自动化RPC服务 ,提供加密和解密接口,支持对抓取的数据包进行解密分析和对修改后的数据进行加密重放。 第二章:技术分析与破解流程 2.1 阶段一:绕过Frida反调试检测 问题现象: Frida可以注入,但执行 Java.use() 时APP崩溃。 解决方案(二选一): 方案A:编译Frida Java Bridge 原理: 官方的Frida Java.use 等API特征明显,容易被检测。通过编译Frida的 frida-java-bridge 模块,可以改变这些API的底层实现方式,从而绕过基于特征码的检测。 操作步骤: 参考提供的视频教程,搭建Node.js环境。 使用 frida-compile 工具将自定义的Agent脚本(包含对Java层的操作)编译成一个单独的、优化过的 _agent.js 文件。 注入时,直接加载这个编译后的 _agent.js 文件,而非原始的、特征明显的Frida API脚本。 方案B:使用ZygiskFrida 原理: 这是一个开源项目,它将Frida集成到Magisk的Zygisk模块中。它通过修改Android系统底层(Zygote进程)的加载方式,实现了更深层次的注入和更隐蔽的存在,从而有效规避了常规的Frida检测。 操作步骤: 确保手机已解锁Bootloader并刷入Magisk(支持Zygisk)。 安装 ZygiskFrida 模块并重启手机。 之后即可像正常使用Frida一样进行注入,检测功能已被绕过。 推荐: 对于新手, 方案B(ZygiskFrida) 更为简单可靠。 2.2 阶段二:逆向分析加密流程 1. 抓包初步分析 请求/响应体格式: {"key": "Base64EncodedEncryptedData"} 关键请求头: X-Emp-Signature ,用于数据签名验证。 2. 定位签名算法(突破口) 使用逆向工具(如Jadx-GUI)反编译APP,全局搜索字符串 X-Emp-Signature 。 定位到 initHttpRequest 方法,发现其调用了 encryptHMAC 方法。 分析 encryptHMAC ,确认其使用 HmacSha1 (或可配置的国密SM3)算法对数据进行签名。 3. 定位请求体加密入口 由于加密可能在Native层,直接阅读Java代码逻辑更高效。在Jadx中查找 initHttpRequest 方法的调用者,向上追溯。 最终定位到 sendRequest 方法,其中调用了 handleRequestBody 方法来处理请求体加密。 关键代码逻辑分析( handleRequestBody ): byte[] rnc = new byte[16]; ... new SecureRandom().nextBytes(rnc); 生成一个16字节的随机数(RNC)。 将RNC与原始的JSON请求体字节数组合并( RNC + RequestBody )。 调用 AESCipher.encrypt(rncAndBody) 对合并后的数据进行AES加密。 将加密结果与一个序列号( mSequence )拼接,然后计算HMAC签名。 最终结构为: HMAC签名 || 序列号 || AES加密结果 。 将整个结果进行Base64编码,并封装成 {"key": "base64String"} 的格式。 4. 解密流程推理 响应体的解密是加密的逆过程: Base64解码响应体。 分离出HMAC签名(用于验证数据完整性)、序列号和AES加密数据。 使用正确的AES密钥和IV解密数据。 解密后的数据前16字节是RNC,后面才是真正的JSON响应体。 2.3 阶段三:追踪动态密钥生成 核心问题: AES加密所需的 clientKey_ 和 clientIv_ 是动态的。 1. 密钥生成点定位 在Jadx中追踪 AESCipher 类,发现其 clientKey_ 和 clientIv_ 的赋值在一个 initSecret 方法中。 initSecret 方法的核心是这行代码: 这行代码是标准的 TLS-PRF(Pseudo-Random Function) 实现,用于从主密钥( ms2 )和随机数种子( ms2RncRnsSeed )派生出会话所需的多个密钥。 2. 逆向TLS握手流程 继续追溯 ms2 (主密钥)的来源,最终定位到 handleServerKeyExchange 方法。该方法处理服务器发送的密钥交换信息(如RSA公钥加密的预主密钥)。 进一步向上追溯,发现一个关键的HTTP请求(例如 /api/facility/serverHello ),该请求的响应数据被用于计算主密钥 ms2 。 结论: APP启动时,会与服务器进行一次自定义的、简化版的TLS握手。通过这次握手,客户端和服务器协商出共享的主密钥 ms2 ,然后双方使用相同的PRF函数,派生出完全一致的AES密钥、IV和HMAC密钥。 2.4 阶段四:Frida RPC实现自动化 由于密钥动态生成,硬编码密钥到Python脚本是不可行的。因此,采用Frida RPC(Remote Procedure Call)技术,在APP内存中直接调用其Java加密/解密方法。 1. Frida脚本核心任务 编写一个Frida脚本( agent.js ),暴露(export)几个RPC函数给外部调用: getKeys() : 获取当前会话的动态密钥( clientKey , clientIv , serverKey , serverIv , hmacKey )。 encryptData(data) : 接收明文字符串,调用APP自身的 handleRequestBody 逻辑,返回加密后的Base64字符串。 decryptData(encryptedBase64) : 接收加密的Base64字符串,调用APP自身的解密逻辑,返回明文字符串。 示例代码片段(概念性): 2. Python端与Flask服务器 使用Python的 frida 库连接到设备上的APP进程,并加载上述 agent.js 脚本。 利用 flask 框架创建一个轻量级的Web服务器。 为每个RPC函数创建一个对应的API端点(endpoint)。 示例Flask端点: 第三章:实战操作流程总结 环境准备: 安装Frida、Python、ADB。Root手机并配置ZygiskFrida以绕过检测。 逆向分析: 使用Jadx静态分析APP,理清 handleRequestBody 、 AESCipher 、 PRFCipher 等关键类的调用关系。 编写Frida RPC脚本: 根据分析结果,编写 agent.js ,暴露 getKeys , encryptData , decryptData 等RPC函数。 部署Flask RPC服务器: 编写Python脚本,连接Frida,加载JS脚本,并启动Flask服务。 渗透测试: 抓包: 使用Burp Suite或Charles抓取APP流量,得到加密的数据包。 解密: 将抓到的加密数据( {"key": "..."} 中的值)发送到本地Flask服务器的 /decrypt 接口,即可获得明文。 分析/修改: 分析明文JSON,发现潜在漏洞(如参数污染、越权等)。 加密重放: 将修改后的明文发送到 /encrypt 接口,获得新的加密数据,替换原数据包中的内容,进行重放攻击。 第四章:核心知识点与工具清单 核心知识点: Frida动态插桩与反检测绕过 Android Java层与Native层逆向分析 TLS握手与密钥交换协议(PRF) AES对称加密与HMAC签名 Frida RPC机制 Flask Web框架 工具清单: 逆向分析: Jadx-GUI 动态调试: Frida, ZygiskFrida 抓包工具: Burp Suite, Charles 开发环境: Python 3, Flask库, frida-tools Android环境: 已Root的Android手机/模拟器 通过以上步骤,您可以系统地完成对该金融APP的通信协议破解,并建立起一个强大的自动化测试平台。请注意,本文档仅用于安全研究和学习目的,请勿用于非法活动。