学习AppleStore版本的 Bandzip365 版本
下载
点击恢复购买项目,提示无购买内容。
破解分析
-
首先找到本土化语言"无购买内容"文件:/Applications/Bandizip365.app/Contents/Resources/Localizable.cn.strings
拿到TEXT.ERROR_NO_PURCHASES去搜一下字符串
-
你会发现没修改文件 第二次直接打不开了 只是重新签了个名 因为要修改代码
但是用一个空的_MASReceipt授权文件替换掉原来的5KB大小的文件即可绕过
- 现在app已经可以正常运行了,进入下一步 绕过这个登录窗口
ida搜索入口NSApplicationMain
进入发现start函数有一个exit(173) 查看Apple官方文档得知173是告诉系统授权验证失败,要求登录
所以我们直接十六进制修改函数入口代码为6A 01 58 C3让这个函数一直返回1
保存
即可。
替换进原文件重新签名:
可以看到直接弹出了窗口 说明绕过登录成功。
-
现在又弹出了
开头的画面 如果搜索无购买内容则很难搜索到有效的数据
我这里用成功恢复购买来搜索 发现这里有一个嫌疑很大的判断:
__int64 sub_100079070()
{
void *v0; // rax
id v1; // rax
id v2; // rax
void *v3; // rbx
unsigned __int8 v4; // r14
v0 = (void *)objc_opt_self(&OBJC_CLASS___LicenseManager);
v1 = objc_msgSend(v0, "shared");
v2 = objc_retainAutoreleasedReturnValue(v1);
if ( !v2 )
BUG();
v3 = v2;
v4 = (unsigned __int8)objc_msgSend(v2, "isSubscriptionEdition");
objc_release(v3);
if ( v4 )
return sub_100076CC0(v3);
else
return sub_100077040(0xD000000000000010LL, "TEXT.COMPLETE_RESTORE_PURCHASES" + 0x8000000000000000LL);
}
用Hopper Disassembler看一下代码
v2 = objc_retainAutoreleasedReturnValue(v1)
objc_retainAutoreleasedReturnValue函数它的作用是检视稍后执行的代码是否会执行retain方法,如果有,会把某个专用于检测的变量,或者说数据结构的标志位置位,并直接返回对象(上例array),不执行autorelease方法;否则,对对象(上例array)执行autorelease方法。简单来说 应该是获取v1的值 如果对象存在则自动释放内存指针,如果不存在则直接得到对象 也就是OBJC_CLASS___LicenseManager的实例。由于我从未开发过MacOS X应用 也不知道理解的对不对。先对付着看吧。
那么v2就等价于OBJC_CLASS_LicenseManager实例, objc_msgSend好像是发消息 其实不是:
objc_class(Class对象)结构简介
熟悉OC语言的Runtime(运行时)机制以及对象方法调用机制的开发者都知道,所有OC方法调用在编译时都会转化为对C函数objc_msgSend的调用。
所以我们可以理解为v4 = ((&OBJCCLASSLicenseManager)v2).isSubscriptionEdition,如果为0则表示恢复购买成功,否则直接进入下一步(直接绕过购买页面 实现内购)。
搜一下
我们返回1(也就是True 因为非0即True)即可成功破解。
返回0因为根本走不到这一步 所以返回0没有意义。如果需要走恢复购买完成 需要去无购买内容的判断分支修改跳转到这里 没有太大意义。
总结
macOS的入口函数是NSApplicationMain,搜索之。
if (!validateReceiptAtPath(pathToReceipt))
exit(173); //receipt did not validate 无授权直接终止应用程序
- AppleStore商店下载的app有_MASReceipt目录保存了购买信息,不一致的话会被拒绝执行。
- 通过用空的_MASReceipt文件来让app继续执行让用户登录重新获取购买信息。
- nop掉检查购买信息的函数让app跳过系统登录用户界面继续执行。
- 在内购页面查找入口修改关键函数isSubscriptionEdition让他一直返回True即可破解。
|