破解 SmoothScroll v1.1.5

对于我们黑苹果机器来说,没有原生的触摸板和MM鼠标,就没有顺滑的滚动体验,无意中看pcbeta有人推荐这个改善体验,试了一下,还真的不错,我的罗技M325在macOS下是没有驱动的,配合它还不错。
本次的目标是v1.1.5这个版本,我看威锋论坛有人已经放出破解版了,所以我只是凑凑热闹而已。

要破解一个App,首先你肯定得有基本功,然后就是把这个App使用一段时间,了解一下试用期间和过了试用期之后有什么不同。

这里SmoothScroll很良心,有20多天的试用期,试用期间注册的话,注册是立即生效的,然后你就可以随便用啦,但是它会定时联网检查你的License是否有效,无效的话,它会弹出License页面,显示Invalid License字眼,然后自动关闭自己的功能(勾上了Disable for all apps),然后你必须退出再开启才能继续正常使用。

好了,废话少说,祭出我们的大杀器Hopper(macOS下似乎没有靠谱的IDA Pro……唉)

首先当然是字符串定位啦,找到了一处实例变量,按x查看引用,有两个,destruct的我就不去看了:

直接看上面的这个引用,发现它在-[xlwc423412 sls33553]:方法内,按流程图查看一下,明显像个switch-case,判断你是过期了呢,还是License不对呢,还是License对了呢……

在这里我试了一下改成强跳到LicenseView这个分支(0x1000108db),发现没什么用,App在使用一段时间之后依然会跳出来提示框,不过不再是Invalid License了,而是Thank you……可是滚动功能依然是被自动禁用了,看来另有地方判断,这个sls33553方法只是事后用来弹授权不正确的提示框的。

那就顺藤摸瓜,看看哪里调用了这个sls33553方法,对着它按Option+Shift+x,有了3个调用。

第一个awakeFromNib方法,老熟人了,加载完xib的时候系统调用的方法,我觉得应该不是它,因为SmoothScroll不是一打开就提示我Invalid License,而是到了时间自动跳出来提示。

第三个registerApp方法我也觉得不是,这个看上去像是我点击注册,输入了东西之后才触发的行为。

于是跳到第二个调用点,发现也是一个很小的方法-[xlwc423412 setIlc83736:]

继续Option+Shift+x看看哪里调用了这个setIlc83736方法,又有3个,最后一个忽略,上面讨论过了:

来看第一个-[SSAppDelegate slw32448]:,看了一下方法里提到的字符串,有点像是监听用户点击License菜单按钮的行为:

我再Option+Shift+x看看哪里调用了这个slw32448,发现是两个createStatusMenu方法,所以断定这里是创建菜单,并且监听菜单点击的地方,不是我们的重点,回头。

我们返回到上次寻找setIlc83736调用的地方,是-[SSAppDelegate lkc65645354]:方法内。
往上往下看看,竟然有个关键跳转,似乎是判断setIlc83736的返回值,不等于1则跳过显示License Invalid Screen的地方,等于1则显示。

这个时候我就可以试试改下jnejmp什么的……不过我一般是懒,先看看这个setIlc83736是不是控制弹出Invalid License的地方,所以我直接把方法的第一行:

000000010000fce5 push rbp

按Option+A(编辑汇编指令),输入ret,让方法(函数)直接返回调用点,相当于没执行这个方法。

然后在Hopper的菜单File - Produce New Executable…,保存修改后的执行文件到桌面,然后显示SmoothScroll应用的包内容,把MacOS文件夹里面的原始文件改名,然后把桌面的修改后的可执行文件复制进来,重新运行应用程序里面的SmoothScroll。

在我满怀希望的目光下,弹了这么一个框,告诉我更新错误,文件DSA校验失败,需要重新code sign……


噢,有自我检测是吧,首先要确定这个检测是来自自身还是外部程序,看看SmoothScroll的包结构,发现有个Frameworks,里面有Google分析,LetsMove,Sparkle……嘿,就是你了,我为啥知道?Google一下啊,这是个开源的软件更新框架。

展开Sparkle的框架目录 - Versions - A - Sparkle,新建一个Hopper窗口,把Sparkle可执行文件拖进去分析下,首先当然是搜索下insecure字眼啦,还真有结果,看看调用……

两个都是SUUpdater initForBundle:方法调用,据老夫多年的Objective-C经验,init开头的都是实例初始化方法呢,也就是说,这个SUUpdater类整个就是为了更新而生的,一初始化完就要检查二进制文件的code sign和DSA校验……那么,让它init的时候失败会怎样?是不是就废了它了呢?

先看看-[SUUpdater initForBundle:]:被哪里调用了,发现有两个:

一个是+[SUUpdater updaterForBundle:],另一个是-[SUUpdater init],哇塞,有我们的目标呢!

如果你像老夫这样,有多年的Objective-C经验,那么肯定会知道,这个+号开头的方法,最终还是会用到-号的这个方法的。

那么我们的目标很明确了,【干掉init方法】,我选择在它的第一行就ret……然后生成新的可执行文件到桌面,把Sparkle里的原始文件改名,然后复制桌面的进去……不啰嗦了,看疗效……

进活动监视器强制结束了SmoothScroll,重新运行一次,发现没有了上面那个Insecure的警告框,软件也可以正常使用,然后就耐心等待吧,看看它过段时间还会不会跳出来Invalid License的框框……

测试了一天,平时使用和短时间的睡眠唤醒似乎没有问题,再也没有跳出来提示框,似乎就是随便注册了……但是长时间睡眠(一夜)唤醒后用不了,必须退出再打开。


这就让老夫为难了,难道有漏网之鱼?再看回sls33553方法的三个调用点:

这次我们来看registerApp方法的代码:

按这些方法名的大概猜测,我标注到图上了,这里有个通知很可疑,SSUserLicenseStatusDidChangeNotification,意思是,用户的License状态变化啦,哪个方法关心的话,就来处理吧。那我们得看看是哪个方法对Lincese变化关心,搜索SSUserLicenseStatusDidChangeNotification,5处引用。

除了第4个,其他逐个看看,发现只有一个地方是addObserver的,它就是-[SSAppDelegate registerForNotifications]

拥有多年iOS开发经验的老夫一看就知道是怎么回事啦,收到通知就调用rch53134:方法嘛,让我们看看这个方法有什么:

正所谓久旱逢甘雨,他乡遇故知;洞房花烛夜,金榜题名时……这lkc65645354:不是我们的故知吗?
纵观整个rch53134:方法,尽是没干好事,可能它把我们的菜单弄成勾选Disable了,然后把Invalid License跳出来给我们看……对于这种故知,我都是痛下杀手的,直接让它第一行就ret

然后生成新的可执行文件,覆盖到MacOS目录,退出APP再运行,试试长时间睡眠看有没有疗效。老夫这里测试了两天发现再也不会唤醒后滚动失灵啦!


但是,我发现它有时候一启动就失灵啦!岂有此理!肯定是最后一个地方作怪!awakeFromNib!把这个call干掉就好了,三个字节,用三个nop填充刚刚好。

然后功能就完全没问题了……不过License界面的文字信息也没有了……嘿嘿,管它呢,能用就好。


本文只是做了简单的爆破,真正的破解还要涉及动态跟踪,分析到最关键的逻辑……我还是靠运气吧!

如果你没有老夫这样逆天的运气,误打误撞就破解了,还是购买正版吧,对文章内容,不作任何讨论回复哟。