9.苹果ios逆向-FridaHook-ios中的算法(CCCrypt)
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
工具下载:
链接:https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwd=zy89
提取码:zy89
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:8.苹果ios逆向-安装frida
ios中的app很少有加密的,大厂的app会有加密
苹果系统(ios和macOS)中提供了CCCrypt函数,它是一个用来加解密的函数,它提供了AES、DES、3DES、RC4、MD5等算法,就提供了一个函数可以很方便的,让开发者使用
CCCrypt函数说明
CCCryptorStatus CCCrypt(CCOperation op, // 操作类型:加密/解密CCAlgorithm alg, // 加密算法(如 AES)CCOptions options, // 加密选项(如填充模式、加密模式)const void *key, // 密钥size_t keyLength, // 密钥长度const void *iv, // 初始化向量(IV)const void *dataIn, // 输入数据(明文/密文)size_t dataInLength, // 输入数据长度void *dataOut, // 输出数据缓冲区(密文/明文)size_t dataOutAvailable, // 输出缓冲区大小size_t *dataOutMoved // 实际输出数据长度 );
首先使用Charles抓一个包,如下图它有一个sign参数,一般有sign参数和一个时间戳这样组合的sign都是加密的,查找加密参数的方式,再请求一次,对比两次请求不一样的参数,只要不一样然后数据还看不懂,看着像加密数据,那它就是加密数据,如下图红框就是它的值就看不懂,然后看着也想加密数据,然后每次请求它都会变化,这就符合加密参数的特征
然后复制一下curl
然后直接让ai大模型把curl转成Python代码,如下图
然后这里有一个加解密网址:
https://gchq.github.io/CyberChef/
![]()
然后复制一下sign的数据,对它进行Base64解密,有些数据加密完会进行base64加密,如下图红框base64解密后以十六进制展示
使用frida-trace指令 hook CCCrypt算法,它要使用app的进程id
查看进程id
frida-ps -Ua
下图红框是我们需要的进程id
![]()
然后使用 frida-trace -Up 24699 -i CCCrypt,拦截CCCrypt,指令执行后刷一下手机,让app执行加密操作也就是调用CCCrypt函数,如下图有CCCrypt的打印说明,注入成功
然后它还会给我创建一个文件,如下图红框,上图红框的内容也是由下图红框的文件进行打印的
CCCrypt文件默认内容,然后我们需要完善它的内容,来查看真实的算法内容,onEnter用来查看入参,onLeave用来查看加密之后的数据(结果)
下图红框里的就是CCCrypt的入参
也就是下图红框的十个数据,args[0] 一直到 args[9]
效果图:拦截加密入参、加密方式
最终的代码
/*** 完整的十六进制+文本显示的CCCrypt监控脚本* 数据同时展示十六进制和可打印文本,不包含二进制格式*/
{onEnter(log, args, state) {// 解析基础参数const op = args[0].toInt32();const alg = args[1].toInt32();const options = args[2].toInt32();const keyAddr = args[3];const keyLen = args[4].toInt32();const ivAddr = args[5];const dataInAddr = args[6];const dataInLen = args[7].toInt32();// 解析算法名称let algorithmName;switch (alg) {case 0: algorithmName = 'AES(kCCAlgorithmAES)'; break;case 1: algorithmName = 'DES(kCCAlgorithmDES)'; break;case 2: algorithmName = '3DES(kCCAlgorithm3DES)'; break;case 3: algorithmName = 'CAST(kCCAlgorithmCAST)'; break;case 4: algorithmName = 'RC4(kCCAlgorithmRC4)'; break;case 5: algorithmName = 'RC2(kCCAlgorithmRC2)'; break;default: algorithmName = `未知算法(${alg})`;}// 解析选项参数const mode = options & 0x0F;let modeName;switch (mode) {case 1: modeName = 'CBC(kCCOptionModeCBC)'; break;case 2: modeName = 'ECB(kCCOptionModeECB)'; break;case 3: modeName = 'CFB(kCCOptionModeCFB)'; break;case 4: modeName = 'OFB(kCCOptionModeOFB)'; break;case 5: modeName = 'CTR(kCCOptionModeCTR)'; break;case 6: modeName = 'GCM(kCCOptionModeGCM)'; break;default: modeName = `未知模式(0x${mode.toString(16)})`;}const padding = options & 0xF0;const paddingName = padding === 0x10 ? 'PKCS7填充(kCCPaddingPKCS7)' : padding === 0x00 ? '无填充(kCCPaddingNone)' : `未知填充(0x${padding.toString(16)})`;// 打印函数调用基本信息log('=== CCCrypt 调用开始 ===');log(`操作类型: ${op === 0 ? '加密(kCCEncrypt)' : '解密(kCCDecrypt)'}`);log(`算法类型: ${algorithmName}`);log(`选项参数: 0x${options.toString(16)}`);log(` 加密模式: ${modeName}`);log(` 填充方式: ${paddingName}`);log(`密钥长度: ${keyLen}字节`);log(`输入长度: ${dataInLen}字节`);// 打印密钥(十六进制+文本)if (keyAddr && !keyAddr.isNull() && keyLen > 0) {log('\n[密钥数据] (十六进制+可打印文本)');log(hexdump(keyAddr, {length: keyLen,header: false,ansi: true,format: 'hex+ascii' // 同时显示十六进制和ASCII文本}));}// 打印IV(十六进制+文本)if (ivAddr && !ivAddr.isNull()) {log('\n[IV数据] (十六进制+可打印文本)');log(hexdump(ivAddr, {length: 16,header: false,ansi: true,format: 'hex+ascii'}));}// 打印输入数据(十六进制+文本)if (dataInAddr && !dataInAddr.isNull() && dataInLen > 0) {const showLen = Math.min(dataInLen, 256);log(`\n[输入数据] (共${dataInLen}字节,显示前${showLen}字节)`);log(hexdump(dataInAddr, {length: showLen,header: false,ansi: true,format: 'hex+ascii'}));}// 保存输出参数引用this.dataOutAddr = args[8];this.dataOutLenPtr = args[10];},onLeave(log, retval, state) {// 打印执行结果const status = retval.toInt32();log(`\n[执行结果] 状态码: ${status} (${status === 0 ? '成功' : '失败'})`);// 打印输出数据(十六进制+文本)if (this.dataOutAddr && !this.dataOutAddr.isNull() && this.dataOutLenPtr) {const outLen = this.dataOutLenPtr.readUInt();if (outLen > 0) {const showLen = Math.min(outLen, 256);log(`\n[输出数据] (共${outLen}字节,显示前${showLen}字节)`);log(hexdump(this.dataOutAddr, {length: showLen,header: false,ansi: true,format: 'hex+ascii'}));log(`输出长度: ${outLen}字节`);}}log('=== CCCrypt 调用结束 ===\n');}
}