IOS逆向之某APP解密

移动安全 2年前 (2022) admin
912 0 0

0x00 前言

前段时间有这样一个需求,需要抓一下IOS端下appsflyer这个平台的数据,于是就帮忙看了一下。这里其实和APP没多大关系,需要接入appsflyer这个平台的APP就可以,然后将抓包获取的加密数据进行解密。

0x01 准备

给我的并不是一个ipa文件,而是一个压缩包文件。

IOS逆向之某APP解密

Payload.zip其实就是ipa文件进行解压后再压缩而来的,但是修改文件名直接安装是不行的,需要重新签名。

这里将文件重命名为1.ipa,不进行签名,然后使用命令ideviceinstaller -i 1.ipa进行安装,结果安装失败。

IOS逆向之某APP解密

可以使用命令安装,也可以借助其他工具安装,如Xcode、爱思助手等。

签名的话也有多种方法,我这里使用IOS App Signer进行签名。

IOS逆向之某APP解密

签名后重新安装

1ideviceinstaller -i 1-sign.ipa
IOS逆向之某APP解密

签名后安装成功,对比源文件与签名后文件的签名。

IOS逆向之某APP解密

接下来就是进行抓包分析了。

0x02 分析

运行app并抓包,会发现有很多请求,但每次打开APP与appsflyer有关的请求一般有三个,可以直接过滤出来。

IOS逆向之某APP解密

可以看到请求的内容是乱码,应该是采用了某种加密。接下来使用ida对文件进行分析。

一般都是进行关键字的搜索,然后慢慢定位找到加密相关的函数,例如这里搜索的关键字是iosevent

IOS逆向之某APP解密

对比一下请求的URL,可能是第一个。

一直查找引用,直到发现-[AppsFlyerLib __validateAndLogInAppPurchase:price:currency:transactionId:additionalParameters:success:failure:]进行了调用。

IOS逆向之某APP解密

使用frida-trace进行追踪

frida-trace -U -f cn.fuping.hhrx -m "-[AppsFlyerLib __validateAndLogInAppPurchase:price:currency:transactionId:additionalParameters:success:failure:]"

IOS逆向之某APP解密

这里仍有三个appsflyer相关的请求,但是发现并没有对该方法进行调用,因此可能是找错了。

通过查看请求,可以看到Content-Typeapplication/octet-stream,所以也可去搜索application/octet-stream

IOS逆向之某APP解密

搜索application/octet-stream

IOS逆向之某APP解密

一直查找引用,最终定位在-[AppsFlyerHTTPClient sendEvent:completionHandler:]方法中。

IOS逆向之某APP解密

在其中也可以看到调用了与加密相关的内容-[AFSDKEvent encryptWithData:]

使用frida-trace进行追踪

关键代码:

 1{
2  onEnter(log, args, state) {
3    var arg2ObjC = ObjC.Object(args[2]);
4    var arg2 = Memory.readUtf8String(arg2ObjC.bytes(), arg2ObjC.length());
5    log(`-[AFSDKEvent encryptWithData:${arg2}]`);
6  },
7
8  onLeave(log, retval, state) {
9    log(`-[AFSDKEvent encryptWithData:->result->${ObjC.Object(retval)}]`);
10  }
11}

可以成功获取加密前的数据

IOS逆向之某APP解密

加密后的结果也是一致的。接下来就是看加密是如何实现的,另外能否进行解密。

IOS逆向之某APP解密

进入到-[AFSDKEvent encryptWithData:]方法,看是如何进行加密的。

IOS逆向之某APP解密

通过分析发现其调用了-[AFSDKEvent key]获取key,这里key是固定的,为X3sgfYhYXWhDoD8DhW2aaJ。然后调用+[AppsFlyerAES128Crypto encrypt:withObject:]进行加密。继续跟进加密的方法。

IOS逆向之某APP解密

1CCCrypt(0LL, 0LL, 1LL, v19, v20, v22, v24, v25, v27, v28, &v35)

这里看到了CCCrypt函数的调用,可以先了解一下该函数,然后分析加密流程。

使用CCCrypt进行加密时,需要引入CommonCrypto/CommonCryptor.h框架。

其中CCCrypt函数定义:

 1CCCryptorStatus CCCrypt(
2    CCOperation op,         /* kCCEncrypt, etc. */
3    CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
4    CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
5    const void *key,
6    size_t keyLength,
7    const void *iv,         /* optional initialization vector */
8    const void *dataIn,     /* optional per op and alg */
9    size_t dataInLength,
10    void *dataOut,          /* data RETURNED here */
11    size_t dataOutAvailable,
12    size_t *dataOutMoved)

一共有11个参数,参数简要说明如下:

参数 说明 备注
CCOperation op 加密(kCCEncrypt=0)解密(kCCDecrypt=1) 这里是加密
CCAlgorithm alg 加解密算法标准kCCAlgorithmAES128=0,kCCAlgorithmAES=0 这里为kCCAlgorithmAES128或者kCCAlgorithmAES加密
CCOptions options 加密方式的选项
kCCOptionPKCS7Padding表示CBC
kCCOptionECBMode表示ECB
kCCOptionPKCS7Padding|kCCOptionECBMode表示ECB且PKCS7Padding填充
这里为CBC加密,用PKCS7Padding进行填充
const void *key 加密密钥 固定值
size_t keyLength 密钥长度
const void *iv iv 初始化向量,ECB 不需要指定 随机值
const void *dataIn 加密的数据
size_t dataInLength 加密的数据长度
void *dataOut 缓冲区(地址),存放密文的
size_t dataOutAvailable 缓冲区的大小
size_t *dataOutMoved 加密结果大小

然后转过头来分析加密的流程。首先调用了+[AppsFlyerAES128Crypto randomDataOfLength:]生成了一个16byte的随机字符作为iv。

接着调用+[AppsFlyerAES128Crypto AESKeyForPassword:salt:]对key进行解密,解密后的的结果作为加密的key值,为84adf6ec41acb6cbeb349d0a7078f0d2

最后调用CCCrypt进行加密,加密方法是AES-CBC。

IOS逆向之某APP解密

加密完成后将IV和8位00与加密数据进行拼接。所以可以直接根据请求的数据进行解密。

IOS逆向之某APP解密

例如上面的请求包共分为三部分,第一部分为加密后的内容,第二部分为IV,长度为16,这里是b820980ed08844945179a96721bbbcd3,第三部分为0,长度为8。

然后进行解密:

IOS逆向之某APP解密

成功解密数据,到这里任务就完成了。

其实在搜索的时候也可以搜索其他关键字,例如buildnumber

IOS逆向之某APP解密

被圈中的两个字符串与URL进行对比,相似度很高。可以进一步去分析查找引用进行分析。

另外这里的加密用到了CCCrypt函数,所以也可以直接对其进行追踪,例如

1frida-trace -U -f xxxx -i CCCrypt

然后修改libcommonCrypto.dylib下的CCCrypt.js文件,主要代码:

 1{
2
3  onEnterfunction (log, args, state{
4    log('CCCrypt(' +
5        'op=' + args[0] +
6        ', alg=' + args[1] +
7        ', options=' + args[2] +
8        ', key=' + args[3] +
9        ', keyLength=' + args[4] +
10        ', iv=' + args[5] +
11        ', dataIn=' + args[6] +
12        ', dataInLength=' + args[7] +
13        ', dataOut=' + args[8] +
14        ', dataOutAvailable=' + args[9] +
15        ', dataOutMoved=' + args[10] +
16        ')');
17    //保存参数
18    this.operation   = args[0]
19    this.CCAlgorithm = args[1]
20    this.CCOptions   = args[2]
21    this.keyBytes    = args[3]
22    this.keyLength   = args[4]
23    this.ivBuffer    = args[5]
24    this.inBuffer    = args[6]
25    this.inLength    = args[7]
26    this.outBuffer   = args[8]
27    this.outLength   = args[9]
28    this.outCountPtr = args[10]
29    //this.operation == 0 代表是加密
30    if (this.operation == 0) {
31      //打印加密前的原文
32      console.log("In buffer:")
33      console.log(hexdump(ptr(this.inBuffer), {
34        lengththis.inLength.toInt32(),
35        headertrue,
36        ansitrue
37      }))
38      //打印密钥
39      console.log("Key: ")
40      console.log(hexdump(ptr(this.keyBytes), {
41        lengththis.keyLength.toInt32(),
42        headertrue,
43        ansitrue
44      }))
45      //打印 IV
46      console.log("IV: ")
47      console.log(hexdump(ptr(this.ivBuffer), {
48        lengththis.keyLength.toInt32(),
49        headertrue,
50        ansitrue
51      }))
52    }
53  },
54
55  onLeavefunction (log, retval, state{
56  }
57}

效果如下:

IOS逆向之某APP解密

也是可以进行加密数据的解析。

0x03 总结

本文主要涉及部分内容,一是ios APP签名,另外就是加密函数CCCrypt。该函数是IOS加密中常用的函数,在分析的时候可以直接使用frida-trace -U -f xxxx -i CCCrypt来查看加密是否调用了该函数,然后进行数据解密。


原文始发于微信公众号(猎户攻防实验室):IOS逆向之某APP解密

版权声明:admin 发表于 2022年10月13日 上午8:11。
转载请注明:IOS逆向之某APP解密 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...