Skip to content

游戏数据加解密识别与绕过 ​

场景 ​

游戏对通信数据、内存关键值、存档文件进行了加密保护。需要识别加密算法、定位 Key/IV、写出解密脚本。

输入信号 ​

  • 抓包数据全是乱码,无明显 JSON/Protobuf 结构
  • 内存中关键数值(血量/金币)在 CheatEngine 中搜不到直接值
  • SharedPreferences 中存的是 Base64+乱码
  • native 层有大量 javax.crypto.Cipher 调用

加密层次识别 ​

层次 1: 网络层 TLS/SSL Pinning ​

bash
# 检测: 抓包失败、Burp 看不到请求
# Frida 一键绕过 (通用):
frida -U -f com.target.app -l ssl_pinning_bypass.js
javascript
// SSL Pinning bypass 通用模板
Java.perform(function() {
    var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager')
    // Hook checkServerTrusted 返回 void (信任所有证书)
    var SSLContext = Java.use('javax.net.ssl.SSLContext')
    SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;',
        '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom')
        .implementation = function(km, tm, sr) {
            // 注入自定义 TrustManager
        }
})

层次 2: 应用层加密 (AES/DES/RSA) ​

java
// 目标代码模式
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(plaintext);

层次 3: 内存层 XOR/混淆 ​

c
// native 层直接操作 int/float
int realGold = storedGold ^ 0xDEADBEEF;  // 简单 XOR
float realX = storedX * magicMultiplier;  // 乘性混淆

Frida 抓加密参数模板 ​

javascript
// Hook Java Cipher
Java.perform(function() {
    var Cipher = Java.use("javax.crypto.Cipher")
    var orig_init = Cipher.init.overload(
        'int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec')

    orig_init.implementation = function(opmode, key, params) {
        console.log("[Cipher.init] mode:", opmode,
            "algo:", this.getAlgorithm())
        if (key) {
            var keyBytes = key.getEncoded()
            console.log("[KEY]", bytesToHex(keyBytes))
        }
        if (params) {
            var IvSpec = Java.use("javax.crypto.spec.IvParameterSpec")
            if (params.$className === 'javax.crypto.spec.IvParameterSpec') {
                console.log("[IV]", bytesToHex(params.getIV()))
            }
        }
        return orig_init.call(this, opmode, key, params)
    }
})

function bytesToHex(bytes) {
    return Array.from(bytes, b => ('0'+b.toString(16)).slice(-2)).join('')
}
javascript
// Hook native 加密 (libcrypto/libssl)
var AES_set_encrypt_key = Module.findExportByName("libcrypto.so", "AES_set_encrypt_key")
Interceptor.attach(AES_set_encrypt_key, {
    onEnter: function(args) {
        console.log("[AES key]", hexdump(args[0], {length: args[1].toInt32()}))
    }
})

常见算法特征速查 ​

算法特征Key 长度IV 长度
AES-128-CBCSecretKeySpec + IvParameterSpec16 bytes16 bytes
AES-256-GCMGCMParameterSpec32 bytes12 bytes
DESDESKeySpec / "DES"8 bytes8 bytes
RSA/ECBCipher.getInstance("RSA")128-512 bytes无
HMAC-SHA256Mac.getInstance("HmacSHA256")任意无
自定义 XOR内存中反复 xor 常量1-4 bytes无

实战: 从内存 dump 到解密验证 ​

python
# 拿到 key/iv/ciphertext 后的离线验证
from Crypto.Cipher import AES

key = bytes.fromhex("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6")
iv = bytes.fromhex("0102030405060708090a0b0c0d0e0f10")
ciphertext = bytes.fromhex("...")

cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
# 验证: 看解密结果是否是合法的 JSON/Protobuf/文本

攻击链 ​

抓包乱码 → 确认非标准协议 → jadx 搜索 Cipher/encrypt/SecretKey →
Frida hook Cipher.init → 提取 key/iv/算法 → Python 离线解密验证
→ 内存中也异或: Frida hook XOR 点 → 确定 XOR key → 解密内存字段

MCP 工具映射 ​

AI Agent 可调用以下 MCP 工具自动完成或加速上述攻击链步骤:

攻击链步骤MCP 工具说明
Frida 抓 Cipher.init → key/iv/算法 → logcat 汇总android_crypto_unpack_recipe一键:Frida 抓 Cipher.init → key/iv/算法 → logcat 汇总
从 key/IV/input/output 自动解密验证solve_crypto_from_evidence从 key/IV/input/output 自动解密验证
生成可运行的 Python 解密复现脚本make_crypto_replay_scaffold生成可运行的 Python 解密复现脚本
一键 parse → solve → replay scaffold → buffer carvepostprocess_frida_crypto_result一键 parse → solve → replay scaffold → buffer carve

GPL-3.0 · 仅供授权环境下的学习与防御性研究使用