点击上方蓝字 关注联想全球安全实验室
使用frida辅助分析iOS App加密算法
移动端App为了提升通信过程的安全性,通常会采用加密算法来加密通信数据。例如:在App客户端,使用AES加密算法加密HTTPS请求数据包中的数据后发送给服务器;服务器返回响应包时,也采用AES加密响应包中的数据后再返回给客户端。这种端到端的加密方式使App和服务器之间的通信更加安全,对于渗透测试也增加了一定难度。对于安卓App的加密算法分析,一种通用的方法是使用hook工具hook Java系统库提供的加密算法API(通常开发者会调用Java系统库的加密算法API来实现加密功能),通过hook来动态分析、迅速定位加密算法实现代码。那么对于iOS App,是否也存在类似的通用方法?下面将对此问题展开分析。
通过查阅资料了解到,iOS上也提供了多种加密算法的系统API,接下来一起了解一下具体的API函数。
2.1 对称加密算法——CCCrypt函数
CCCrypt函数提供了对称加密算法功能,该函数可以一次完成对称加密算法的加密或解密操作,是CCCrytor系列函数:CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal() 和CCCryptorRelease()的过程封装。使用该函数时需要引入系统库:
1.函数定义
CCCryptorStatus CCCrypt(
CCOperation op, // 加密还是解密,枚举值
CCAlgorithm alg, /* 定义加密算法类型,枚举值 */
CCOptions options, /* 选择的填充方式,以及是否选择ECB模式,默认是CBC模式 */
const void *key, /* 密钥 */
size_t keyLength, /* 密钥长度 */
const void *iv, /* iv向量,只能用于CBC模式,不传默认为16位0 */
const void *dataIn, /* 要加解密的数据 */
size_t dataInLength, /* 要加解密的数据长度 */
void *dataOut, /* 加解密结果数据 */
size_t dataOutAvailable, /* 结果数据缓存大小 */
size_t *dataOutMoved /* 执行成功后,结果数据实际占用的空间大小 */
)
函数返回值是CCCryptorStatus类型,该类型是枚举值,定义如下:
enum {
kCCSuccess = 0, // 成功
kCCParamError = -4300, // 非法参数
kCCBufferTooSmall = -4301, // 表明dataOut的空间不足
kCCMemoryFailure = -4302, // 内存不足
kCCAlignmentError = -4303, // 输入数据不正确
kCCDecodeError = -4304, // 输入数据未解码或解密出错
kCCUnimplemented = -4305 // 不支持该算法
}
2.主要参数说明
a) op: 加密还是解密,枚举值,定义如下:
enum {
kCCEncrypt = 0, // 加密
kCCDecrypt = 1 // 解密
};
b) alg:加密算法类型,枚举值,定义如下:
enum {
kCCAlgorithmAES128 = 0,
kCCAlgorithmAES = 0,
kCCAlgorithmDES,
kCCAlgorithmRC4,
kCCAlgorithmBlowfish
最常用的是AES、DES、3DES加密算法,说明如下:
-
kCCAlgorithmAES128 和 kCCAlgorithmAES:两个类型是一样的,AES分组加密,固定的加密块是128位,即16个字节,跟密钥长度无关,我们常说的128、192、256主要指的就是密钥长度(当然还有加密轮数也不一样),加密运算操作相同,所以这两个是一样的。
-
kCCAlgorithmDES: DES明文按照64位进行分组,分组后的明文与密钥按位替代或交换的方法形成密文组。密钥的长度是 64 位即8个字节(其实是56位,其中有8位是奇偶校验位)。
-
kCCAlgorithm3DES: 3DES是针对DES算法密钥过短、存在安全性的问题而改进的一个措施,被称为“3DES”。其实只是通过简单的执行3次DES来达到增加密钥长度和安全而已,3DES算法在对明文M进行加密时,采用了三次加密过程,其中第一次和第三次是采用DES的加密算法,第二次采用的则是解密算法,从而得到最终的密文C。这种加密过程为“加密-解密-加密”,所以又称为EDE(Encrypt-Decrypt-Encrypt)方案。
c) options: 填充方式,以及加解密模式,枚举值,定义如下:
enum {
kCCOptionPKCS7Padding = 0x0001, // CBC模式, PKCS7Padding
kCCOptionECBMode = 0x0002 // ECB模式
};
d) const void *key: 加解密算法的密钥
e) keyLength: 密钥长度,可以使用以下枚举值:
enum {
kCCKeySizeAES128 = 16,
kCCKeySizeAES192 = 24,
kCCKeySizeAES256 = 32,
kCCKeySizeDES = 8,
kCCKeySize3DES = 24,
kCCKeySizeMinCAST = 5,
kCCKeySizeMaxCAST = 16,
kCCKeySizeMinRC4 = 1,
kCCKeySizeMaxRC4 = 512,
kCCKeySizeMinRC2 = 1,
kCCKeySizeMaxRC2 = 128,
kCCKeySizeMinBlowfish = 8,
kCCKeySizeMaxBlowfish = 56
};
关于CCCrypt中的key和keyLength
AES数据块长度为128位,所以IV长度需要为16个字符(ECB模式不用IV),密钥根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充' '补足。
f) dataOutMoved:操作成功之后,被写入dataOut的字节长度, 所以最后我们根据dataOutMoved从dataOut截取我们最后获得的数据
2.2 对称加密算法——CCCryptorCreate等函数
除了使用CCCrypt函数一次完成加解密,也可以分步骤调用系列函数:CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal() 和CCCryptorRelease()。使用这些函数时也需要引入系统库:
1.函数定义
分步骤调用对称加解密算法涉及的函数如下:
// 创建加密器CCCryptorRef
CCCryptorStatus CCCryptorCreate(CCOperation op, CCAlgorithm alg, CCOptions options,
const void* key, size_t keyLength, const void* iv, CCCryptorRef* cryptorRef);
// 获取输出数据的最大长度
size_t CCCryptorGetOutputLength(CCCryptorRef cryptorRef, size_t inputLength,bool final)
// 加密处理
CCCryptorStatus CCCryptorUpdate(CCCryptorRef cryptorRef,
const void* dataIn,
size_t dataInLength,
void* dataOut, /*返回数据 */
size_t dataOutAvailable,
size_t *dataOutMoved /* 实际写入的数据长度 */
)
// 处理最后的数据块
CCCryptorStatus CCCryptorFinal(
CCCryptorRef cryptorRef,
void* dataOut, /*返回数据 */
size_t dataOutAvailable,
size_t *dataOutMoved /* 实际写入的数据长度 */
)
// 释放加密器
CCCryptorStatus CCCryptorRelease(CCCryptorRef cryptorRef)
函数参数与CCCrypt函数参数基本一致。
2.3 MD5哈希算法函数——CC_MD5
CC_MD5函数提供了MD5算法功能,该函数可以一次完成MD5算法操作,是系列函数:CC_MD5_Init()、CC_MD5_Update()、CC_MD5_Final()等函数过程的封装。
使用这些函数时需要引入系统库:
1. 函数定义
unsigned char * CC_MD5(
const void *data, // 待处理的字符串
CC_LONG len, // 待处理的字符串长度
unsigned char *md // 接收结果的数组, 也是返回值
);
// 分步骤的MD5算法函数
int CC_MD5_Init(CC_MD5_CTX *c);
int CC_MD5_Update(CC_MD5_CTX *c, const void *data, CC_LONG len);
int CC_MD5_Final(unsigned char *md, CC_MD5_CTX *c);
2.4 其他哈希算法函数
iOS上SHA1、SHA256哈希算法都有对应不同的函数名,系统提供了多个哈希函数:CC_SHA1、CC_SHA224、CC_SHA256、CC_SHA384、CC_SHA512等。函数参数与CC_MD5类似,也有对应的过程函数:CC_XXX_Init、CC_XXX_Update、CC_XXX_Final,这里不再介绍,详细内容见:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_SHA.3cc.html
既然iOS上系统提供了加解密算法的API函数,而且一般开发者使用加解密算法时也是直接调用系统库的这些API函数,所以,可以直接hook这些函数快速分析加解密算法。
这里以CCCrypt函数为例,编写frida hook代码, 实现动态监控该函数调用的效果:当App调用到该函数时输出加解密相关参数、明文、密文、调用堆栈等。主要代码如下:
// hook CCCrypt函数
;
const CCoptions = [
"0",
"1 CBC PKCS7Padding",
"2 ECB",
"3 ECB PKCS7Padding"
];
const CCAlgorithm = [
{ name: "kCCAlgorithmAES128", blocksize: 16 },
{ name: "kCCAlgorithmDES", blocksize: 8 },
{ name: "kCCAlgorithm3DES", blocksize: 8 },
{ name: "kCCAlgorithmCAST", blocksize: 8 },
{ name: "kCCAlgorithmRC4", blocksize: 8 },
{ name: "kCCAlgorithmRC2", blocksize: 8 }
];
const CCMode = ["null",
"kCCModeECB",
"kCCModeCBC",
"kCCModeCFB",
"kCCModeCTR",
"kCCModeF8",
"kCCModeLRW",
"kCCModeOFB",
"kCCModeXTS",
"kCCModeRC4",
"kCCModeCFB8"
];
const CCPadding = ["ccNoPadding", "ccPKCS7Padding"];
const CCModeOptions = ["null", "KCCModeOptionCTR_LE", "kCCModeOptionCTR_BE"];
// 把char* 转换成base64
var charToBase64 = function(input,length){
var NSData = ObjC.classes.NSData;
var data = NSData.dataWithBytes_length_(ptr(input), length);
var base64 = data.base64EncodedStringWithOptions_(32);
return base64;
};
var dumpBytes = function(inBytes, inLength) {
if (inBytes == 0x0) {
console.log("null");
} else {
console.log(
hexdump(ptr(inBytes), {
length: inLength,
header: true,
ansi: true
})
);
console.log("Base64:" + charToBase64(inBytes, inLength));
}
};
var handlers = {
CCCrypt: {
onEnter: function(args) {
var operation = args[0].toInt32();
var alg = CCAlgorithm[args[1].toInt32()].name;
this.options = CCoptions[args[2].toInt32()];
var keyBytes = args[3];
var keyLength = args[4].toInt32();
var ivBuffer = args[5];
var inBuffer = args[6];
this.inLength = args[7].toInt32();
this.outBuffer = args[8];
var outLength = args[9].toInt32();
this.outCountPtr = args[10];
if (operation === 0) {
this.operation = "encrypt"
console.log("***************** encrypt begin **********************");
} else {
this.operation = "decrypt"
console.log("***************** decrypt begin **********************");
}
console.log("CCCrypt(" +
"operation: " + this.operation + ", " +
"CCAlgorithm: " + alg + ", " +
"CCOptions: " + this.options + ", " +
"keyBytes: " + keyBytes + ", " +
"keyLength: " + keyLength + ", " +
"ivBuffer: " + ivBuffer + ", " +
"inBuffer: " + inBuffer + ", " +
"inLength: " + this.inLength + ", " +
"outBuffer: " + this.outBuffer + ", " +
"outLength: " + outLength + ", " +
"outCountPtr: " + this.outCountPtr + ")"
);
console.log("key: ");
dumpBytes(keyBytes, keyLength);
console.log("IV: ");
// ECB模式不需要iv,所以iv是null
dumpBytes(ivBuffer, keyLength);
console.log("In buffer:");
dumpBytes(inBuffer, this.inLength);
},
onLeave: function(retVal) {
console.log("Out buffer:");
dumpBytes(this.outBuffer, Memory.readUInt(this.outCountPtr));
// 输出调用堆栈,会识别类名函数名
console.log('CCCrypt called from:n' +
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('n') + 'n');
}
},
};
if (ObjC.available) {
console.log("frida attach");
for (var func in handlers) {
console.log("hook " + func);
Interceptor.attach(Module.findExportByName("libcommonCrypto.dylib", func), handlers[func]);
}
} else {
console.log("Objective-C Runtime is not available!");
}
某App发送短信验证码的数据包中对手机号进行了加密处理,请求数据包如下图所示:
使用之前编写的hook脚本进行尝试,命令如下图:
hook输出的日志中发现了界面输入的手机号138*88,输出的加密日志如下图:
可以看到,加密算法使用的是AES,加密模式、key、iv、加密结果、调用堆栈都清晰的打印出来了,加密后的Base64字符串正好是请求包中msisdn的值。搞清楚了加密算法及加密参数后,就可以修改明文数据包,然后使用同样的加密方式加密后发给服务器进行渗透测试。
注意,本文中的hook脚本只实现了对CCCrypt函数的hook,实际测试时还会有其他加密函数,还需要不断完善才能更方便的定位常用加密算法,提升渗透测试效率。
-
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CCCrypt.3cc.html
-
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_MD5.3cc.html
-
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_SHA.3cc.html
-
https://www.jianshu.com/p/93466b31f675
-
https://www.cnblogs.com/cocoajin/p/6150203.html
-END-
往期精彩合集
CSL
联想GIC全球安全实验室(中国)
原文始发于微信公众号(联想全球安全实验室):使用frida辅助分析iOS App加密算法
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论