当前位置: 首页 > news >正文

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');}
}

img

http://www.lryc.cn/news/608956.html

相关文章:

  • CCF-GESP 等级考试 2025年6月认证C++一级真题解析
  • wordpress登陆前登陆后显示不同的顶部菜单
  • 最简单的零基础软件测试学习路线
  • Libevent(5)之使用教程(4)工具
  • k8s黑马教程笔记
  • 快速搭建一个非生产k8s环境
  • 【运维基础】Linux 硬盘分区管理
  • k8s+isulad 国产化技术栈云原生技术栈搭建4-添加worker节点
  • Hyper-V + Centos stream 9 搭建K8s集群(二)
  • k8s+isulad 国产化技术栈云原生技术栈搭建3-master节点安装
  • [硬件电路-148]:数字电路 - 什么是CMOS电平、TTL电平?还有哪些其他电平标准?发展历史?
  • Go语言实战案例:TCP服务器与客户端通信
  • 案例介绍|JSON数据格式的转换|pyecharts模块简介
  • Kafka——怎么重设消费者组位移?
  • 构建企业级Web应用:AWS全栈架构深度解析
  • AtCoder Beginner Contest 417
  • [硬件电路-147]:模拟电路 - DC/DC电压的三种架构:升压(Boost)、降压(Buck)或升降压(Buck-Boost)
  • 跨语言模型中的翻译任务:XLM-RoBERTa在翻译任务中的应用
  • 界面规范4-按钮
  • IntelliJ IDEA开发编辑器摸鱼看股票数据
  • Parcel 使用详解:零配置的前端打包工具
  • 关于车位引导及汽车乘梯解决方案的专业性、系统性、可落地性强的综合设计方案与技术实现说明,旨在为现代智慧停车楼提供高效、安全、智能的停车体验。
  • electron-多线程
  • 嵌入式——数据结构:单向链表的函数创建
  • 常见的深度学习模块/操作中的维度约定(系统性总结)
  • Docker-03.快速入门-部署MySQL
  • 介绍JAVA语言、介绍greenfoot 工具
  • 北邮:LLM强化学习架构Graph-R1
  • 【机器学习】线性回归算法详解:线性回归、岭回归、Lasso回归与Elastic Net
  • 02.Redis 安装