简单介绍
DaisyDisk是一款用于显示文件在磁盘中占比的软件,功能类似于Windows上的TreeSize Free,但稍微弱些,每次打开都需要选择磁盘并扫描,对于1T的盘大概需要近一分钟。软件采用一次性付费模式,通过授权码验证身份。

截屏2025-07-08_00.33.55.png (596.61 KB, 下载次数: 0)
下载附件
2025-7-8 03:07 上传
破解这个是因为刚开始学习逆向,随便抓了个程序过来练手,记录一下自己的工作和思考的过程
破解过程
首先打开软件,观察到功能界面闪烁了一下就被开始试用界面覆盖,

截屏2025-07-07_21.39.21.png (545.43 KB, 下载次数: 0)
下载附件
2025-7-8 03:08 上传
点击我有激活码会弹出一个完成激活的窗口,输入错误的激活码之后完成激活窗口会抖动

截屏2025-07-07_21.39.30.png (190.13 KB, 下载次数: 0)
下载附件
2025-7-8 03:08 上传
准备先用lldb得到”注册激活”这个按钮触发的函数是什么,这边直接重新签名让hardened runtime失效之后发现程序会立马退出,并且在日志输出“invalid code signature”,拖入IDA,通过字符串搜索发现程序启动时做了签名校验,先狠狠NOP掉

start.png (295.73 KB, 下载次数: 0)
下载附件
2025-7-8 03:08 上传
然后用lldb attach上去,从窗口开始找到button,再找到action,最终定位目标函数
(lldb) po [[NSApplication sharedApplication] windows]
(
,
,
,
,
,
)
(lldb) po [0x14478d860 title]
注册激活 DaisyDisk
(lldb) po [(NSWindow *)0x14478d860 windowController]
(lldb) po [[(NSWindow *)0x14478d860 contentView] _subtreeDescription]
...
[ AF w ] h=&-- v=&-- SimpleButton 0x144761030 "注册激活" f=(381.5,10,77.5,26) b=(-) =>
...
(lldb) po (SEL)[0x144761030 action]
"completeRegistration:"
在IDA中找到函数狠狠按下F5开读

complete-registration.png (393.81 KB, 下载次数: 0)
下载附件
2025-7-8 03:09 上传
大致梳理下逻辑
def completeRegistration():
l1 = loadLicenseFromDisk()
l2 = makeLicenseHeadFromInput()
l3 = buildLicense(l2)
if not l3 or isLicenseBlackListed(l3) or isLicenseCompormised(l3):
raise Error("E")
else:
saveLicenseAndSetup(l3)
def buildLicense(license: Option[License]) -> Optional[License]:
if not license:
return None
name = license.name
licenseKey = license.key
decodedLicensekey = base32_decode(licenseKey)
valid = verify(decodedLicensekey, name, publicKey())
if not valid:
return None
return _buildLicense()
这里发现程序使用的publicKey仅有55字节,结构是一个DER的RSA publicKey

PixPin_2025-07-08_01-36-25.png (54.63 KB, 下载次数: 0)
下载附件
2025-7-8 03:09 上传

PixPin_2025-07-08_01-36-59.png (42.1 KB, 下载次数: 0)
下载附件
2025-7-8 03:10 上传
先尝试算私钥,这边确实算出来了,但是由于学艺不精构造出的license key总是无法通过,遂失去耐心,准备开始爆破,思路是让buildLicense也就是sub_10010F8D8认可所有的license key,直接返回一个完整的license对象,completeRegistration这个函数没有用到从磁盘上读取的license,所以猜测程序在启动时一定会检测磁盘上的license做设置,最简单的方式就是在磁盘上先构建好一个license文件,然后等待他的设置函数帮我们设置好激活
回到mainWindow刚创建的时候主界面被覆盖的时刻,发现有一个函数 -[MainWindowController updateLicenseBehaviorAndShowNotification:]: ,仔细看发现这个应该就是我们需要的函数

PixPin_2025-07-08_02-01-12.png (69.52 KB, 下载次数: 0)
下载附件
2025-7-8 03:10 上传
然后通过查看licenseKeyFromDiskOutIsPortable函数确定license文件结构

PixPin_2025-07-08_02-02-41.png (285.17 KB, 下载次数: 0)
下载附件
2025-7-8 03:10 上传
文件是一个NSUserDefaults, 也就是plist,里面两个值一个name一个key
再找到文件路径

PixPin_2025-07-08_02-09-43.png (117.43 KB, 下载次数: 0)
下载附件
2025-7-8 03:11 上传
构造文件
License_CustomerName
WO
License_RegistrationKey
WOOOOOOOOOOOOO0000oOOOOO0oOOO0OOOooO0OOO0
patch sub_10010F8D8 让他变成这样
def buildLicense(license: Option[License]) -> Optional[License]:
return License(
license.name,
licenes.key,
0, #签发日期
1, #版本
9, #副本数
)
也就是等他拿到参数之后狠狠跳到生成license的部分

PixPin_2025-07-08_02-18-49.png (182.77 KB, 下载次数: 0)
下载附件
2025-7-8 03:12 上传

PixPin_2025-07-08_02-19-19.png (148.96 KB, 下载次数: 0)
下载附件
2025-7-8 03:12 上传
最终结果伪代码如下

PixPin_2025-07-08_02-20-51.png (97.5 KB, 下载次数: 0)
下载附件
2025-7-8 03:12 上传
到这里应该就结束了,直接运行,结果弹出了这个

IMG_0135.png (408.96 KB, 下载次数: 0)
下载附件
2025-7-8 03:13 上传

IMG_0136.png (164.96 KB, 下载次数: 0)
下载附件
2025-7-8 03:13 上传
呜呜呜别骂了别骂了好哥哥,回头找到地方打工给你补票还不行嘛
重新进入updateLicenseBehaviorAndShowNotification开始单步调试,发现是之前比较粗,只改了sub_10010F8D8里面isLicenseCompormised的调用,忘了直接把他改了,遂patch掉这个函数

PixPin_2025-07-08_02-28-17.png (59.47 KB, 下载次数: 0)
下载附件
2025-7-8 03:13 上传
再次运行,应该是成功了,不想看他还有没有什么上传key为黑名单啥的操作了,目前的功能也够用,一个磁盘整理工具也不需要联网,所以就直接把它禁止联网了

PixPin_2025-07-08_02-41-00.png (654.79 KB, 下载次数: 0)
下载附件
2025-7-8 03:13 上传
最后
其实更优雅的解决方案可能还是通过推出来的私钥去构造任意的License,这样完全不需要侵入源文件,但是学艺不精实在是没搞出来,这里吧拿到的公钥和我推出来的私钥分享出来给有兴趣的兄弟稍微省点事儿
-----BEGIN PUBLIC KEY-----
MDUwDQYJKoZIhvcNAQEBBQADJAAwIQIaALeN7XjhVyfaLWpCJDR8Ke/6E2KcvAKI
HqMCAwEAAQ==
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIGKAgEAAhoAt43teOFXJ9otakIkNHwp7/oTYpy8AogeowIDAQABAhkVPP/QL8qk
2tLMa7C/mWP+gQlqWLzGuM1xAg0MpeIf+HSxurX+9AgpAg0OgzYo5Qcyt7fph7nr
Ag0IjDc1ChG7Z4bF5iB5Ag0Ft3omMdHcELLJs0VxAg0BhvFKthFCuBMpyM1d
-----END RSA PRIVATE KEY-----
最后的最后
这是我第二次尝试破解应用,第一次是一个iOS App,感觉还是手忙脚乱,很多基础知识都不知道,全靠AI吊着,工具链不熟,整个工作流程也很粗糙。
把过程记录下来,一方面是给自己做个备忘,另一方面也想和大伙交流一下,看看有没有什么更好用的工具,思路有没有问题,或者有什么更好的方法。