百趣云 百趣云的博客

自定义加密还原:异或+位移混淆的通用破解思路

自定义加密的本质:混淆而非密码

当 App 不用任何标准算法(AES/RSA/TEA 都不是),而是自己撸一套"加密"——通常是异或、加减、位移、置换的组合。从密码学角度它弱不禁风,从逆向角度它的难度在于"没有特征可循":没有常量可搜,只能硬读逻辑。

好消息是:这类算法的强度上限很低,掌握方法后还原是时间问题。

识别:先确认是自定义算法

排除法确认:

  1. 搜遍密码学常量(AES S 盒、TEA delta、MD5 K 表)无命中
  2. 加密函数里有大量 eor(ARM 异或指令)、lsl/lsr(位移)、查表操作
  3. 输入输出长度关系:等长(流式异或)或按块膨胀(分组+填充)

还原方法论:四步走

第一步:圈定算法边界

hook 加密函数的输入输出,确认:

  • 输入:明文、key(几个?长度?)
  • 输出:密文(长度和明文的关系)
  • 同输入是否同输出(有无随机数/时间戳参与)

第二步:静态读逻辑,画出数据流

IDA 里读函数实现,把每个操作用伪代码记录。自定义加密的代码通常不长(几十到几百行),耐心读完:

// 典型自定义加密的伪代码
for (i = 0; i < len; i++) {
    key_byte = key[i % key_len];
    c[i] = p[i] ^ key_byte;           // 异或
    c[i] = (c[i] + i) & 0xFF;         // 加位置
    c[i] = (c[i] << 3) | (c[i] >> 5); // 循环位移
}

第三步:写加密方向的对拍实现

先实现加密(不是解密),用 App 的输入对拍:

def custom_encrypt(p, key):
    out = []
    for i, b in enumerate(p):
        c = b ^ key[i % len(key)]
        c = (c + i) & 0xFF
        c = ((c << 3) | (c >> 5)) & 0xFF
        out.append(c)
    return bytes(out)

# 对拍:custom_encrypt(已知明文, key) == App 输出?

先写加密再写解密的原因:加密是正向模拟,不容易错;对拍通过后,逆运算推解密(异或的逆是异或,加的逆是减,循环左移的逆是循环右移)。

第四步:逆运算写解密

把每个操作反过来、顺序倒过来:

def custom_decrypt(c, key):
    out = []
    for i, b in enumerate(c):
        p = ((b >> 3) | (b << 5)) & 0xFF   # 循环右移 3
        p = (p - i) & 0xFF                 # 减位置
        p = p ^ key[i % len(key)]          # 异或
        out.append(p)
    return bytes(out)

精髓一:多轮加密的拆解

自定义加密常做 2-4 轮迭代(每轮换个 key 或位移量)。识别多轮:函数里有外层循环套内层操作。拆解技巧:hook 每轮的边界(如果轮间有函数调用边界),或对拍时先只实现第一轮,看输出是否呈现"半成品"特征。

精髓二:key 派生是常见马甲

自定义加密的 key 经常不是传入的原始 key,而是派生的:

// 原始 key "abc123" 派生成 256 字节密钥流
for (i = 0; i < 256; i++) {
    key_stream[i] = raw_key[i % 6] ^ i;
}

识别:hook 到的 key 长度和代码里用的不一致。对策:别还原派生逻辑,hook 派生后的密钥流直接用。

精髓三:什么时候别还原

自定义加密的还原有成本上限。这些信号出现时,放弃还原转 Frida 直调:

  • 算法超过 500 行且多轮嵌套
  • 密钥派生依赖大量设备状态(还原要连设备环境一起模拟)
  • 算法随版本频繁更新(你还原完它换了)

记住第一原则:能调用就不还原

总结

  1. 自定义加密 = 异或/位移/置换组合,无特征常量,靠排除法确认
  2. 还原四步:圈边界 → 读逻辑 → 对拍加密 → 逆运算解密
  3. 多轮拆解靠 hook 轮边界,key 派生直接 hook 派生结果
  4. 超 500 行或频繁更新就放弃还原,Frida 直调

交流微信:run1255

By 百趣云 阅读量:2 On