逆向工程SizeUp

这几天把《汇编语言》好好复习一遍,心里痒痒,就想找个软件来逆向破解一发。破啥好呢?网上逆向工程的教程一大堆,主要都是Sketch啦,Reveal啦,那我照着做一遍也没啥意思啊,体现不出我中国iOS第12人的特点啊。干脆我找个小众一点的软件破解吧。于是,我就盯上了我每天都非常喜欢使用的SizeUp,这是一款非常快速的窗口管理软件,可以通过快捷键将窗口扩展到指定的大小和位置,配合外接显示屏简直酷炫到飞起。

但是这个App有个很大的问题,虽然它是免费的,但是它每次启动的时候,包括你使用的过程中,都会时不时蹦出一个提示你购买的弹框,而且弹框上的取消按钮一定要过5秒才能点击关闭,真是让人蛋疼。

所以,我就讲逆向的目标定在了将这个可恶的弹窗给干掉。

准备工作

首先破解必须要准备的就是逆向工具了,由于这是个Mac app,所以我们无需使用到iPhone。所以,我简单的将SizeUp进行了一次备份就开始了。

逆向一个app,我们当然要去分析其汇编代码,因此必不可少的工具就是IDA或者Hopper。在这里,请允许我个人强烈推荐Hopper,那傻瓜式的操作,非常适合我这种高智商人才,哇哈哈。Hopper也是支持免费的,但是免费版不能重新生成可执行文件,所以我先从网上下载了一个破解版的Hopper。

逆向开始

首先我们将SizeUp拖入Hopper,得到一系列的汇编代码。这么多的代码我们从哪里下手呢? 答案是关键字。在弹窗提示我们购买的界面中,出现了很多关键字,比如license抑或是demo。首先让我们从license开始尝试。我们在Hopper界面左上侧的搜索框中输入license,会得到如下结果:

从结果来看,我们大致猜测SizeUp的逻辑如下:

  1. 初始化程序
  2. 检查存储的license
  3. (如果有)多个,检查最好的一个(可能是有效期最长的)
  4. 和服务器进行验证

上述这段逻辑主要来自于高亮的+[License xxx]函数调用。

从上述这段逻辑,我们可以看出,想要伪造license是不可能的了,这是因为牵涉了服务器验证。所以我们只能把想法转变成,干掉本地相关的逻辑。本地逻辑不外乎判断某种分支条件,根据结果进行某些页面的跳转,比如弹出Demo界面

好,现在我们来试试Demo关键字,搜索结果如下:

从这个关键字的搜索结果来看,我们得到了不少有价值的信息,比如DemoDialogController。哈哈哈哈,苹果经典的MVC设计模式这时候起了很大的作用,搞过开发的人一般都会知道Controller一般对应的就是一个ViewController。如果你不信,我们继续往下看,可以看到一个-[DemoDialogController showDemoDialog],这个提示够明显了吧,这分明就是说:老子就是那个界面,你快来把我干掉吧。

好,大功告成一半了,我们已经找到了我们要干掉的界面,现在我们只要干掉分支判断逻辑就好了。于是,我们继续跟着Demo关键字走,不久,我们发现了+[License isDemo]这个嫌疑犯。卧槽,这时候,我这天赋异禀的大脑中形成了这样一段代码:

if ([License isDemo]) {
    [[[DemoDialogController alloc] init] showDemoDialog]
} else {
    // Follow your heart
}

是不是和我猜测的一样呢?

去掉前面的函数压栈,我们来着重看看这段代码:

mov edx, 0x1
test al, al
je 0x1000008bd9
....
....
mov eax, edx

这段代码不熟悉汇编的人可能不太懂,我将其转换一下。

edx = true(YES)
if al == 0
{
    goto 0x1000008bd9
}

... 0x1000008bd9:
val = edx(true)
return val

理解了吧,就是首先将0x1(即YES)放入edx寄存器,然后判断al代表的某种分支条件是不是0,如果是0,通过je命令跳转到0x1000008bd9地址。这个地址后面的指令就是讲edx的值塞入eax中,而eaxx86指令集中默认存放函数返回值的寄存器

事情到这,是不是基本理清思路了?我们只需要将je跳转的条件极其后面语句干掉就好了。我在这里采用了更暴力的做法,直接在函数一开始就讲false塞入eax寄存器,然后直接调用ret进行返回。

结语

是不是逆向工程看起来也没那么难呢?其实,SizeUp这种利用函数返回至做文章的逆向是最简单的,下次我们来挑战下更难的逆向目标!