Sketch!一次悸动的小逆向尝试

作者: Uri | 来源:发表于2015-10-24 19:55 被阅读3160次

丙戌月 癸酉日

故事从一开始应该是这样的:最近一直在使用Sketch,然而呢,直到某一天弹出这个着实让我惊叹不已:

想着今天是1024专属日,于是乎上官网看看然而发现并没有限免,万年不变的价格也是出奇的合理,99美元能买到这样一款优秀到超出想象,好用到违反广告法的软件真的是赚到了。

看看还有没有其它类似的App,要不找找看有木有破解版?故事的结尾刚要如此,然而笔锋一转,情节立马一波三折,没想到用盗版软件的也会有自己破解软件的今天-_-||。因为最近刚看完了一些iOS逆向开发的书,奈何没有越狱的设备,只好在OS X上练练手。正所谓道法自然,虽平台,工具不同,但内功都是一样的。

不忍直视的弹窗

现在先让我们为这个万恶的弹窗默哀一分钟,接着就开始仔细关注分析一下有哪些入手点。仔细一看就会发现,那个welcome界面依然还在的,也就是说主程序仍然是可以使用的,只是在其上多出了一个如下图的提示注册的弹窗,获取了当前的焦点,以至于我们无法进行其他的操作。

所以我们的任务很简单啦,要么在register上做文章,弄清楚注册流程和算法(第一次我就不要不要试这个了,顿时压力好大);要么在quit按钮上做文章,使其只关闭弹窗但不退出整个程序;或者在判断是否Trial Expired的过程中做手脚;最后,还有最简单的,但是却不优雅的,就是直接去掉弹窗就好了。

工具嘛,IDA或Hopper Disassembler按自己的喜欢就可以了,这里我就用Hopper Disassembler就可以了。开始前也可以class dump一下头文件看看,会有助于后面的分析,这里我就不用了。

那就开始咯

进入Sketch.app目录,找到Sketch二进制文件把它丢进Hopper里然后坐等分析,分析完后如下图:

Hopper这个软件很强大,不过是收费的,但提供免费试用的,试用版的每30分钟会退出一次(咳咳,用自己来破解自己,想想就可怕)。

我们在左边搜索一下弹窗出现的相关关键字Trial

从字面上,我们一眼就能看出每个类每个方法的作用,其中BCTrialCountdown这个类我猜就是负责计算剩余试用天数的,里面的trialPopUpWithNumberOfDays方法应该就是那个不厌其烦每次弹出提示我们还有多少天过期。

BCTrialExpiredWindowController应该就是我们要找的弹窗的controller,有showquitvisitStoreregisterLicense等方法,嗯,没错,就是它了。这样我们就很快定位到相关函数了。

下面我们来仔细看看show方法的汇编代码:

                     +[BCTrialExpiredWindowController show]:
00000001002aa6e0         push       rbp                                         ; Objective C Implementation defined at 0x100368688 (class)
00000001002aa6e1         mov        rbp, rsp
00000001002aa6e4         push       r15
00000001002aa6e6         push       r14
00000001002aa6e8         push       r13
00000001002aa6ea         push       r12
00000001002aa6ec         push       rbx
00000001002aa6ed         push       rax
00000001002aa6ee         mov        rbx, rdi
00000001002aa6f1         mov        rdi, qword [ds:objc_cls_ref_BCTrialExpiredWindowController] ; objc_cls_ref_BCTrialExpiredWindowController, argument "instance" for method _objc_msgSend
00000001002aa6f8         mov        rsi, qword [ds:0x1003d2178]                 ; @selector(alloc)
00000001002aa6ff         mov        r12, qword [ds:imp___got__objc_msgSend]     ; imp___got__objc_msgSend
00000001002aa706         call       r12                                         ; _objc_msgSend
00000001002aa709         mov        r14, rax
00000001002aa70c         mov        rsi, qword [ds:0x1003d2230]                 ; @selector(class), argument "selector" for method _objc_msgSend
00000001002aa713         mov        rdi, rbx                                    ; argument "instance" for method _objc_msgSend
00000001002aa716         call       r12                                         ; _objc_msgSend
00000001002aa719         mov        rdi, rax                                    ; argument "aClass" for method imp___stubs__NSStringFromClass
00000001002aa71c         call       imp___stubs__NSStringFromClass
00000001002aa721         mov        rdi, rax                                    ; argument "instance" for method imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa724         call       imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa729         mov        rbx, rax
00000001002aa72c         mov        rsi, qword [ds:0x1003d4100]                 ; @selector(initWithWindowNibName:), argument "selector" for method _objc_msgSend
00000001002aa733         mov        rdi, r14                                    ; argument "instance" for method _objc_msgSend
00000001002aa736         mov        rdx, rbx
00000001002aa739         call       r12                                         ; _objc_msgSend
00000001002aa73c         mov        r14, rax
00000001002aa73f         mov        r13, qword [ds:imp___got__objc_release]     ; imp___got__objc_release
00000001002aa746         mov        rdi, rbx                                    ; argument "instance" for method _objc_release
00000001002aa749         call       r13                                         ; _objc_release
00000001002aa74c         mov        rsi, qword [ds:0x1003d4108]                 ; @selector(window), argument "selector" for method _objc_msgSend
00000001002aa753         mov        rdi, r14                                    ; argument "instance" for method _objc_msgSend
00000001002aa756         call       r12                                         ; _objc_msgSend
00000001002aa759         mov        rdi, rax                                    ; argument "instance" for method imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa75c         call       imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa761         mov        rbx, rax
00000001002aa764         mov        rsi, qword [ds:0x1003d4110]                 ; @selector(center), argument "selector" for method _objc_msgSend
00000001002aa76b         mov        rdi, rbx                                    ; argument "instance" for method _objc_msgSend
00000001002aa76e         call       r12                                         ; _objc_msgSend
00000001002aa771         mov        rdi, rbx                                    ; argument "instance" for method _objc_release
00000001002aa774         call       r13                                         ; _objc_release
00000001002aa777         mov        rax, qword [ds:imp___got__NSApp]            ; imp___got__NSApp
00000001002aa77e         mov        r15, qword [ds:rax]
00000001002aa781         mov        rsi, qword [ds:0x1003d4108]                 ; @selector(window), argument "selector" for method _objc_msgSend
00000001002aa788         mov        rdi, r14                                    ; argument "instance" for method _objc_msgSend
00000001002aa78b         call       r12                                         ; _objc_msgSend
00000001002aa78e         mov        rdi, rax                                    ; argument "instance" for method imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa791         call       imp___stubs__objc_retainAutoreleasedReturnValue
00000001002aa796         mov        rbx, rax
00000001002aa799         mov        rsi, qword [ds:0x1003d4118]                 ; @selector(runModalForWindow:), argument "selector" for method _objc_msgSend
00000001002aa7a0         mov        rdi, r15                                    ; argument "instance" for method _objc_msgSend
00000001002aa7a3         mov        rdx, rbx
00000001002aa7a6         call       r12                                         ; _objc_msgSend
00000001002aa7a9         mov        rdi, rbx                                    ; argument "instance" for method _objc_release
00000001002aa7ac         call       r13                                         ; _objc_release
00000001002aa7af         mov        rdi, r14                                    ; argument "instance" for method _objc_release
00000001002aa7b2         mov        rax, r13
00000001002aa7b5         add        rsp, 0x8
00000001002aa7b9         pop        rbx
00000001002aa7ba         pop        r12
00000001002aa7bc         pop        r13
00000001002aa7be         pop        r14
00000001002aa7c0         pop        r15
00000001002aa7c2         pop        rbp
00000001002aa7c3         jmp        rax                                         ; _objc_release
                        ; endp
00000001002aa7c5         nop        qword [cs:rax+rax+0x0]

其实也没什么可看的,看最后的一个call,传给_objc_msgSend的两个参数,一个是自身的实例,另一个是runModalForWindow的selector,也就是说这里才弹出窗口:

你可以下个断点确认下,我已经确认了,也就是说,在0x1002aa7a6处将这个call r12置成nop不让它调用就可以了。

这样弹窗就不会出现了。到这里,尽管目的达到了,可是感觉不怎么优雅,明明是考验开锁技巧的,却偏偏用锤子直接把锁砸开了。尽管我现在做不到写注册机这种地步,可是还是让我们把修改还原,还是再多看看吧。

代码辣么长,我想再看看

上面我们是粗鲁的破坏掉了BCTrialExpiredWindowControllershow方法,使其失去了弹窗的作用。与其破坏,还不如不让其调用。我们找找看看是在哪调用的。

可以看到,从0x1002a8834处开始调用BCTrialExpiredWindowControllershow方法,往上看看这个sub procedure整体:

整体上这样看就很明白了,0x1002a87f20x1002a8832这段是判断是否有license,如果有,就跳转到0x1002a884c处,然后返回,如果不正确,就往下到0x1002a8834调用BCTrialExpiredWindowControllershow方法弹窗。这样也表明了0x1002a87e7的test是用来判断是否过期,过期的话就跳转去判断是否有license。

看懂了这里,我们就只用修改cmp r14, 0x1这句为cmp r14, 0x0,然后就能无限使用了,这比之前的是不是更好一些呢。

然后Shift+Cmd+E将其保存为二进制文件,将原来的二进制文件备份,然后相应的替换即可。

至此,弹窗已去,万佛朝宗,大功告成,天下我有。

最美的永远是意外

悲剧往往发生在你双击的那一刻,因为你永远都不会知道打开的是什么。当我们双击运行看看,咦,怎么打不开,而且是闪退有木有,难道是我们打开的方式不对?

没错,真的是打开方式不对。这次我们不点击应用图标,而是进入其目录直接运行二进制文件看看:

这下就明白了。程序自己退出了,并打印了一些信息,说明程序内部有对自身进行检测,如果发现代码,签名等被修改了就强制退出。嗯,我猜应该是这样。

没办法,看来活还没干完,打开Hopper接着干。这次,我们查找Invalid Signing这个字符串,看是哪里输出的。

00000001001bffbf         lea        rdi, qword [ds:cfstring_Invalid_Signing]    ; @"Invalid Signing", argument "format" for method imp___stubs__NSLog, XREF=sub_1001bfe40+357
00000001001bffc6         xor        eax, eax
00000001001bffc8         call       imp___stubs__NSLog
00000001001bffcd         mov        edi, 0xae                                   ; argument "status" for method imp___stubs__exit
00000001001bffd2         call       imp___stubs__exit

嗯,没错,就是这里。调用NSLog输出@"Invalid Signing",然后就退出程序。

再来看看全部代码,下图会更直观一些:

可以看到,不管上面进行了什么操作,都要经过0x1001bff7a这里,然后通过test r13d, r13d判断是直接返回呢,还是跳到0x1001bffbf这里退出呢。既然这样,我们将下面的jne 0x1001bffbf置为nop就可以了。

修改后保存成二进制文件,再运行就没有问题了。

最后放出链接,http://pan.baidu.com/s/1qWmXcTm

打完收工。

相关文章

  • Sketch!一次悸动的小逆向尝试

    丙戌月 癸酉日 故事从一开始应该是这样的:最近一直在使用Sketch,然而呢,直到某一天弹出这个着实让我惊叹不已:...

  • sketch的第一次尝试

    开始学习sketch啦,今天练个手画了一个锤子时钟的计时器界面。 加油! 还有一张登录页面

  • 第二次逆向学习总结

    春节期间尝试了第二次英语逆向学习法,第一次逆向学习总结详见:https://www.jianshu.com/p/2...

  • 尝试逆向思考

    今天又是工作到没有多余脑细胞思考的一天。 所以我又从松浦信太郎的100个基本中摘抄一则来这里,共勉。 只从一个方向...

  • 关于 Sketch 4.0 提高模糊性能

    Sketch 4.0提高了模糊的性能, 于是尝试一下使用Sketch绘制拟物的图形. 附带源文件下载以供分享:)S...

  • 小悸动

    我遗憾的,不是我们没有在一起,而是年少的我,没有足够的勇气去面对你,还有我自己。 这个故事,发生在他们的中学时期,...

  • 小悸动

    都说,喜欢是一个人的兵荒马乱。可是从苏妍妍遇见江楠的那一刻起,我便被她拉入了她的战争中。 我身处在她的战场中,看着...

  • 小悸动

    这个周末内心某个地方被连续击中, 第一是昨天和602室友饭饱后,浑浑噩噩在午觉的后半段迷糊的听了《2017产品经理...

  • 【小悸动】

    时常看着你离去的背影发呆, 思虑着我们将会有一个什么样的未来; 时常对我们再次的相遇充...

  • 小悸动

    文:火小姐 洛希熙,女,25岁,花香菇娱乐公司幕后人员,已婚,婚后生...

网友评论

  • 玩呀玩:每次一看汇编就头疼
  • 大康_百度:42版本有没有修改,讨论一下
  • 58f0b442f46c:请问如何找出BCTrialExpiredWindowController的show方法调用地方?
  • 47457f0e1071:果然厉害,是在下输了
  • 779b68e64744:大神,来个最新破解百度云版 :stuck_out_tongue_closed_eyes:
  • 等这姑娘老在我心里:有直接破解好的版本吗 能发我一份吗
  • 十一岁的加重:技术活啊
  • cdd48b9d36e0:我只能说6666
  • PPAbner:你给的链接打开还是要注册,求个最新地址!!!
  • 龙心之火:请问中间的代码流程图是啥软件绘制的哇:flushed:
    Uri:@龙心之火 还是hooper,能以流程图的形式显示
  • FredGan:汇编代码怎么修改啊。。。看到一个je 0x...... 怎么修改呢?
    Uri:@FredGan :flushed:
    FredGan:我写语句好像说不允许,改二进制文件又不知道怎么改内容...
    Uri:@FredGan 如果是用Hopper的话在modify->assemble instruction,或者也可以直接置为nop。
  • c03a447da691:用自己破解自己,哥们你厉害!
  • 5fbaa919b431:哥,现在的版本已经无Invalid_Signing了。而且只要修改了,不会再进入app去验证了。应该是在外面的framework里做了。从hopper的逆向看修改@"~/Library/Application Support/com.bohemiancoding.sketch3/.license" 里面的json字符串"type":"static" 与 "expiration":int_max 即可。int_max 你懂的:)
    5fbaa919b431:@Uri 3.6.1 搞定了吗?
    5fbaa919b431:@Uri 需要cleanmymac卸载之后再试试呢?我从官网下载的直接安装之后,运行一次退出,修改.license之后就好了。连菜单里面的Registration都没了。不过我还在研究如何破解它对于修改binary包的限制,现在只要已修改就无法启动了。
    Uri:@zhbo1983 我试了下,修改了type和expiration后再打开Sketch依然会改回原来的,我现在用的是的3.6.1版本。
  • 杏仁丶: :joy: 不觉明厉啊,逆向的话必须的掌握汇编咯,汇编小白怎么学,汇编好学嘛
    Uri:@杏仁丶 好学好学,只是不太好学好 :cry:
  • 32fe349bf11f:火前留名,为防止版权问题先保存和下载再说。(我暴露了吗?)
  • 75feb661a58d:学习了 很不错,是否所有的软件都是这样的逆向路数?是否有什么办法避免被这样破解?
    另外请教博主,你的桌面顶部状态栏背景是黑色的 这个怎么搞的?

    谢谢~
    75feb661a58d:@Uri 谢谢解答🌏🌝🌹
    Uri:@shujun_zz 具体问题具体分析。
    混淆加密云服务。
    黑色状态栏:Preference->General->Use dark menu bar and dock
  • 没故事的卓同学:不明觉厉害。
  • selfboot:学习汇编有哪些推荐的书本没有啊。
    Uri:@happyou http://www.zhihu.com/question/23332058
  • Zander:6666666666666666666666666666
  • 南栀倾寒:来发几本 你看过的逆向工程的书
    Uri:@南栀倾寒 书的话,我看的主要是snakeninny的《iOS应用逆向工程》,另外就是一些汇编杂七杂八的。还有两个链接,不过还没看多少 :sweat:
    https://tuts4you.com/download.php?list.17
    http://www.woodmann.com/TiGa/idaseries.html
    然后就是看雪论坛上有好多资源。
  • Cpan_mac_i:牛鼻
  • 痕迹Dev:不赞成发布破解教程!
    Uri:@痕迹BLANK :joy: :joy: :joy:

本文标题:Sketch!一次悸动的小逆向尝试

本文链接:https://www.haomeiwen.com/subject/zzvthttx.html