ishot_crack -- OSX M1(Apple Sillcon) 逆向工程实践

坚决抵制盗版行为,本文仅作 OSX 软件逆向分析及 OSX 软件安全相关的研究目的。


背景

前段时间遇到款相当实用的国产截图工具–ishot,大致翻看了下是AppStore内购。
正好没尝试过分析AppStore内购应用,遂拿起把玩一番。

工作环境

  • macos Monterey 12.3 (21E230) (M1)
  • iShot 2.0.7 (980)
  • IDA Pro (7.6)
  • Proxyman 3.3.0 (30300)

收集信息

打开软件,看到有恢复购买字样,这是很好的开始。

目标

这意味着,如果软件校验不是足够复杂,只需要让其恢复购买步入正确逻辑即可达成目标。
即便是它不能一步到位,也能作为一个切入点。
用IDA打开,遵循上述逻辑,将restore作为关键字搜索相关函数。

restore

一眼看去,印象最深的便是BuyFromAppStoreController restoreBtnClick:,也就是按键对应的函数。

restoreBtnClick

简单看一下逻辑,大概就是访问网络后处理结果。
对应的处理函数为ApplePurchaseManager restorePurchaseWithCompleteBlock:

restorePurchaseWithCompleteBlock

继续深入restorePurchaseWithCompleteBlock,最终会调用restoreCompletedTransactions相关函数处理。

搜索restoreCompletedTransactions

restoreCompletedTransactions

从符号名上看
1.paymentQueueRestoreCompletedTransactionsFinished为处理成功。
2.paymentQueue:restoreCompletedTransactionsFailedWithError为处理失败。

通常失败逻辑比较简单的话,可以做个笔记,有助于后续分析。

restoreCompletedTransactionsFailedWithError

当调用-[ApplePurchaseManager handleActionWithType:data:](self, "handleActionWithType:data:", 1LL, 0LL);时即为失败。

继续看成功部分

paymentQueueRestoreCompletedTransactionsFinished

它的功能仅仅是转入
verifyPurchaseWithPaymentTransaction:isTestServer:Compl:
继续深入

verifyPurchaseWithPaymentTransaction

看到一处类似完成函数注册的代码,对函数sub_10004299D需要特别关注。

结合上下文,可以得到一个大致流程。

  1. 请求https://buy.itunes.apple.com/verifyReceipt
  2. sub_10004299D处理返回数据
  3. 校验数据完成恢复

深入浅出

跟入函数sub_10004299D一探究竟。

sub_10004299D

其中AES的字样格外醒目,通常验证算法都会伴随加解密。也就是说,进到AES加密流程更符合猜想。
这里的AES只有一个加密部分,同样后续还需要分析解密部分。

之前分析过
-[ApplePurchaseManager handleActionWithType:data:](self, "handleActionWithType:data:", 1LL, 0LL);为失败。

此处可以得到一个初步结论,当参数为(1,??) (3,0)....为失败,(4,0)为成功。

为了能进入到AES算法步骤,必须让sub_100048A6D(v30)返回真。

其中v30来自receipt, 这个实际上是之前返回的数据包。

打开Proxyman验证。

response

进入sub_100048A6D函数

sub_100048A6D

其中dbl_1000D6BF0 dq 2.6784e9, 3.1536e10

逻辑上一目了然。为了让返回值为1,即v34必须为1。
若要保持v34为1,也就必须让v33>v31成立,v31来自request_date_ms(比较长没贴出),
v34purchase_date_ms

也就是purchase_date_ms>request_date_ms

至此恢复逻辑全部完成。

梳理逻辑

之前AES部分只看到了加密,通过交叉引用可以定位到解密函数位于入口函数start中。

出于篇幅限制,这里就不贴代码了。简单口述一下。

当点击恢复按钮时,会从AppStore获取凭证数据并进行时间等校验,之后再将获取的数据加密保存到文件中。

实际上是通过standardUserDefaults保存,其路径为:
/System/Volumes/Data/Users/$USER/Library/Containers/cn.better365.ishot/Data/Library/Preferences/cn.better365.ishot.plist

当应用启动时,入口函数start根据保存的信息,解密并校验。另外试用逻辑也是在此处校验。

还值得一提的是AES的密钥是根据设备信息生成的,所以理论上这个注册文件不能直接发往其它机器。

猜想验证

构造数据包(只保留关键部分):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"receipt": {
// ....
"request_date_ms": "0",
"in_app": [
{
"product_id":"ishotfeixuqidingyue20220212",
// ....
"purchase_date_ms":"9747829370000",
}
]
},
"status": 0
}

启用map local tool

map_local

再次恢复购买

restore

总结

来自AppStore的应用的安全性实际上和传统的软件安全性一样。

本文中软件存在最大的问题在于轻信了AppStore的返回凭证而未进行二次校验,这就给了一些不法之徒可趁之机。

最后提一壶,ishot确实非常不错,建议有能力的朋友可以去支持一下这款国产软件发展。