下载
16712060568227.jpg (104.93 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
点击恢复购买项目,提示无购买内容。
破解分析
[ol]
首先找到本土化语言"无购买内容"文件:/Applications/Bandizip365.app/Contents/Resources/Localizable.cn.strings
16712062737919.jpg (222.49 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
拿到TEXT.ERROR_NO_PURCHASES去搜一下字符串
你会发现没修改文件 第二次直接打不开了 只是重新签了个名 因为要修改代码
16712066860397.jpg (42.17 KB, 下载次数: 1)
下载附件
2023-1-3 16:32 上传
[/ol]
但是用一个空的_MASReceipt授权文件替换掉原来的5KB大小的文件即可绕过
16712075858032.jpg (71.03 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
ida搜索入口NSApplicationMain
进入发现start函数有一个exit(173) 查看Apple官方文档得知173是告诉系统授权验证失败,要求登录
16712077754638.jpg (697.58 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
[/ol]
16712076619337.jpg (628.49 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
所以我们直接十六进制修改函数入口代码为6A 01 58 C3让这个函数一直返回1
16712078398391.jpg (92.84 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
保存
16712078932727.jpg (188.75 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
16712079088416.jpg (106.39 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
即可。
替换进原文件重新签名:
16712079717239.jpg (415.24 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
可以看到直接弹出了窗口 说明绕过登录成功。
现在又弹出了
16712080160532.jpg (115.99 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
开头的画面 如果搜索无购买内容则很难搜索到有效的数据
16712083512860.jpg (712.53 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
我这里用成功恢复购买来搜索 发现这里有一个嫌疑很大的判断:
__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);
}
[/ol]
用Hopper Disassembler看一下代码
16712085110598.jpg (623.69 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
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则表示恢复购买成功,否则直接进入下一步(直接绕过购买页面 实现内购)。
搜一下
16712090825304.jpg (601.9 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
我们返回1(也就是True 因为非0即True)即可成功破解。
返回0因为根本走不到这一步 所以返回0没有意义。如果需要走恢复购买完成 需要去无购买内容的判断分支修改跳转到这里 没有太大意义。
16712094487544.jpg (171.03 KB, 下载次数: 0)
下载附件
2023-1-3 16:32 上传
总结
macOS的入口函数是NSApplicationMain,搜索之。
if (!validateReceiptAtPath(pathToReceipt))
exit(173); //receipt did not validate 无授权直接终止应用程序
[ol]
[/ol]