【APP测试】使用Frida-trace进行解密初体验

admin 2026-01-14 23:52:50 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍了iOS逆向中利用frida-trace动态hook系统加密库CommonCrypto的CCCrypt函数进行解密的方法。文章详细解析了CCCrypt函数参数含义,演示了如何使用frida-trace捕获加密算法、密钥、IV及密文数据,并通过提取的参数模拟加解密验证结果,为APP抓包解密提供了实用操作指南。 综合评分: 84 文章分类: 移动安全,逆向分析,实战经验,安全工具


cover_image

【APP测试】使用Frida-trace进行解密初体验

原创

d0n9x1e

蝉SEC

2026年1月13日 18:21 江苏

各位看官,我们平时遇到的一些有加密操作的APP,不少是直接使用的苹果官方提供的系统加密库进行加密操作。接下来就简单的了解一下iOS使用的系统加密库:CommonCrypto以及如何对APP调用系统加密库加密的数据包内容进行解密。

CommonCrypto库简介

CommonCrypto的中文直译是”通用加密”。苹果提供的系统加密库,有原生的对称加密算法和Hash算法,支持iOS和Mac开发。其支持加密算法有:AES、DES、3DES、CAST、RC2、RC4、Blowfish、MD5、SHA1/224/256/384/512等加密算法。

https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/

可以看到,在CommonCrypto文件夹中,我们看到有以下三个文件:

  • CommonCryptor.h

对称加密算法相关,包含了块加密和流加密两种类型。它们分别是AESDES3DESCASTBLOWFISHRC2以及RC4

  • CommonDigest.h

摘要算法相关,包括如MD5,SHA家族等哈希摘要算法。

  • CommonHMAC.h

HMAC算法算法相关,包含是HMAC+MD5HMAC+SHA1等,是HMAC算法利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。

相关加密算法苹果基本上已经给我们封装好了,可以直接使用,接下来,主要了解一下相关加密算法的方法接口涉及的参数的意义,以便在对APP通信数据包解密的时候能有效的获取到加密算法信息,进行解密。

CCCrypt

函数定义

CCCryptorStatus CCCrypt(
  CCOperation op,      /* kCCEncrypt, etc. */
  CCAlgorithm alg,    /* kCCAlgorithmAES128, etc. */
  CCOptions options,    /* kCCOptionPKCS7Padding, etc. */
  const void *key,
  size_t keyLength,
  const void *iv,      /* optional initialization vector */
  const void *dataIn,    /* optional per op and alg */
  size_t dataInLength,
  void *dataOut,      /* data RETURNED here */
  size_t dataOutAvailable,
  size_t *dataOutMoved)

参数说明

CCOperation op

  • kCCEncrypt = 0 → 调用CCCrypt方法传入此值时表示加密;
  • kCCDecrypt = 1 → 调用CCCrypt方法传入此值时表示解密;
enum {
  kCCEncrypt = 0,
  kCCDecrypt = 1,
};
typedef uint32_t CCOperation;

CCAlgorithm alg

此参数决定选择使用什么加密算法

enum {
  kCCAlgorithmAES128 = 0,
  kCCAlgorithmDES = 1,
  kCCAlgorithm3DES = 2,
  kCCAlgorithmCAST = 3,
  kCCAlgorithmRC4 = 4,
  kCCAlgorithmRC2 = 5
};
typedef uint32_t CCAlgorithm;

CCOptions options

此参数的作用是决定选择的补码方式,以及是否选择ECB模式,默认是CBC模式

enum {
  /* options for block ciphers */
  kCCOptionPKCS7Padding  = 0x0001,
  kCCOptionECBMode    = 0x0002
  /* stream ciphers currently have no options */
};
typedef uint32_t CCOptions;

const void *key

密钥: 加密和解密的密钥必须一致。必须和选择的算法相匹配,不同的算法要求的密钥长度不一样

size_t keyLength

密钥的大小,这里是真正决定密钥长度的地方

1个字节 = 8个比特;1个字节 = 2个16进制字符

enum {
  kCCKeySizeAES128  = 16,
  kCCKeySizeAES192  = 24,
  kCCKeySizeAES256  = 32,
  kCCKeySizeDES    = 8,
  kCCKeySize3DES    = 24,
  kCCKeySizeMinCAST  = 5,
  kCCKeySizeMaxCAST  = 16,
  kCCKeySizeMinRC4  = 1,
  kCCKeySizeMaxRC4  = 512,
  kCCKeySizeMinRC2  = 1,
  kCCKeySizeMaxRC2  = 128
};

const void *iv

偏移向量,CBC模式下需要;不传默认16位0,只有在ECB模式下不需要

*const void dataIn

要加解密的数据data.bytes

size_t dataInLength

要加解密的数据的大小

*void dataOut

输出的数据,加解密后的数据写在这里

size_t dataOutAvailable

输出数据时需要的可用空间大小。数据缓冲区的大小(字节)

size_t dataOutMoved

操作成功之后,被写入dataout的字节长度。如果由于提供的缓冲区空间不足而返回kCCBufferTooSmall,则在这里返回所需的缓冲区空间。

CC_MD2

函数定义

unsigned char *CC_MD4(const void *data, CC_LONG len, unsigned char *md);

参数说明

  • const void *data:加密明文
  • CC_LONG len:内容长度
  • unsigned char *md:加密结果

CC_MD5

函数定义

unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md);

参数说明

  • const void *data:加密明文
  • CC_LONG len:内容长度
  • unsigned char *md:加密结果

CC_MD4

函数定义

unsigned char *CC_MD4(const void *data, CC_LONG len, unsigned char *md);

参数说明

  • const void *data:加密明文
  • CC_LONG len:内容长度
  • unsigned char *md:加密结果

CC_SHA1

函数定义

unsigned char *CC_SHA1(const void *data, CC_LONG len, unsigned char *md);

参数说明

  • const void *data:加密明文
  • CC_LONG len:内容长度
  • unsigned char *md:加密结果

剩下的其他的SHA512 、SHA256、HMAC等算法相关的说明与之前的大同小异,此处就不再一一列举。

frida-trace基本使用方法

frida-trace是一个基于Frida框架的命令行工具,用于跟踪和拦截指定进程中的函数调用。它可以帮助安全研究人员和开发人员快速定位目标函数的调用位置和参数,方便后续的漏洞利用和代码调试工作。

frida-trace常用参数说明

-U →表示当前设备使用USB连接

-p →指定要附加的APP进程的pid

-i →对C函数进行追踪,可以进行模糊匹配

-m →对object-c方法进行追踪,可以进行模糊匹配

数据包解密案例

抓包

抓包发现APP数据包已加密

frida-trace hook

PC上usb连接iOS设备,设备上打开目标APP后,PC上执行命令如下:

#trace前台APP进程调用的CCCrypt
frida-trace -UF -i "CCCrypt"

当frida-trace工具命中APP调用的名为CCCrypt的函数后,会在控制台打印命中函数的名称,并且会在本地自动生成一个js文件

{
  /**
   * Called synchronously when about to call CCCrypt.
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onEnter(log, args, state) {
    log('CCCrypt()');
  },

  /**
   * Called synchronously when about to return from CCCrypt.
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
  }
}

我们想要通过frida-trace获取到APP调用的加密方法的更多有用信息,就需要基于此js文件进行修改。通过前面对CCCrypt方法的基本了解,我们主要获取一下此方法传入以下内容:

  • 加密操作/解密操作
  • 加密算法类型
  • 加密算法填充模式
  • 加密算法密钥
  • 加密算法密钥长度
  • 加密算法iv
  • 待加密内容/待解密内容
  • 加密结果/解密结果

编写Hook脚本

第一次修改Hook脚本,主要是输出一下CCCrypt函数调用时传入的参数信息

{
  /**
   * Called synchronously when about to call CCCrypt.
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onEnter(log, args, state) {
    log('CCCrypt() → 操作类型→', args[0]);
    log('CCCrypt() → 算法类型→', args[1]);
    log('CCCrypt() → 填充模式→', args[2]);
    log('CCCrypt() → 算法密钥→', args[3]);
    log('CCCrypt() → 密钥长度→', args[4]);
    log('CCCrypt() → 算法 IV→', args[5]);
    log('CCCrypt() → 加密/解密内容→', args[6]);
    log('CCCrypt() → 加密/解密结果→', args[8]);
  },

  /**
   * Called synchronously when about to return from CCCrypt.
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
  }
}

frida-trace输出结果

以上输出结果,主要是将CCCrypt传入的参数值打印了出来,但是参数值分别代表什么意思呢?

  • 操作类型 → 对应的参数:CCOperation op → 输出的值:0x0 → 表示加密
  • 算法类型 → 对应的参数:CCAlgorithm alg → 输出的值:0x0 → 表示调用的加密算法是:kCCAlgorithmAES128
  • 填充模式 → 对应的参数:CCOptions options → 输出的值:0x1 → 表示填充模式是:kCCOptionPKCS7Padding
  • 算法密钥 → 对应的参数:CCOptions options → 输出的值:0x16de325a0 → 表示密钥存储的内存地址,需要调用hexdump()方法获取具体的值
  • 密钥长度 → 对应的参数:size_t keyLength → 输出的值:0x20 → 表示密钥长度,16进制表示,0x20转换成十进制就是32
  • 后面的以此类推

继续修改hook脚本,输出我们需要的必要算法信息,实现数据包加解密

{
  /**
   * Called synchronously when about to call CCCrypt.
   *
   * @this {object} - Object allowing you to store state for use in onLeave.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {array} args - Function arguments represented as an array of NativePointer objects.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onEnter(log, args, state) {
    log('CCCrypt() → 操作类型→', args[0]);
    log('CCCrypt() → 算法类型→', args[1]);
    log('CCCrypt() → 填充模式→', args[2]);
    log('CCCrypt() → 算法密钥→', hexdump(args[3]));
    log('CCCrypt() → 密钥长度→', args[4]);
    log('CCCrypt() → 算法 IV→', hexdump(args[5]));
    log('CCCrypt() → 加密/解密内容→', hexdump(args[6]));
    log('CCCrypt() → 加密/解密结果→', hexdump(args[8]));
  },

  /**
   * Called synchronously when about to return from CCCrypt.
   *
   * See onEnter for details.
   *
   * @this {object} - Object allowing you to access state stored in onEnter.
   * @param {function} log - Call this function with a string to be presented to the user.
   * @param {NativePointer} retval - Return value represented as a NativePointer object.
   * @param {object} state - Object allowing you to keep state across function calls.
   */
  onLeave(log, retval, state) {
  }
}

加解密验证

使用frida-trace输出的加密算法等信息,进行模拟加密,看是否和抓包的加密结果相同

抓包结果和使用frida-trace输出的加密算法信息进行模拟加密的结果相同

以上就是使用frida-trace对iOS调用的系统加密库进行hook的基本使用方法,使用frida-trace 对CC_MD5等其他消息摘要算法进行追踪的操作类似。

frida-trace -UF -i "CC_MD5"

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:蝉SEC d0n9x1e《【APP测试】使用Frida-trace进行解密初体验》

评论:0   参与:  0