Hopper Disassembler v2.8.1 破解笔记

Hopper Disassembler是个非常好用的逆向工具,在其官网上还提供了Demo版,不过有半小时的限制。这次我们要逆向的对象就是Hopper Disassembler v2.8.1,目的有三:

  • 取消半小时时间限制
  • 导出程序
  • 在Hopper内使用GDB

- 仅供逆向研究,不放出任何已破解的程序,Hopper绝对是物超所值的。

- Shut up and take my money!

这个版本的Hopper还没有做太多防范,我们甚至可以直接class-dump出它的头文件。

$ class-dump -H -o Hopper /Applications/Hopper Disassembler.app/Contents/MacOS/Hopper Disassembler

话不多说,先以register做为关键字搜索吧。

屏幕快照 2014-12-18 下午5.12.50

根据文件名,至少能看出HopperAppDelegate应该是比较关键的。打开一看,这一串函数立刻就暴露了:

- (BOOL)checkSavedRegistration;
- (id)registrationOrderID;
- (id)registrationName;
- (id)registrationData;
- (id)registrationOrderID:(id)arg1;
- (id)registrationName:(id)arg1;
- (BOOL)checkRegistrationLicense:(id)arg1;

那么这些利用Objective-C的runtime就能搞定。

搞定后启动Hopper,没有了原来的"Try the demo",可是半小时后还是会弹出试用结束的Alert。这一次我们以expire为关键字搜索。

屏幕快照 2014-12-18 下午5.24.26

看来是HopperDocument呢。果然:

- (id)expired:(id)arg1;

那么这个继续用runtime搞定。再次打开Hopper,半小时后,没有了试用到期的alert了。不过,这还不完美,因为我们还不能保存修改后的可执行文件,也不能在Hopper内使用GDB。

可是我们明明已经把能Hook的都给Hook了啊,还能想到的,那就是在执行「保存」和「GDB」时,还有别的函数在检查,而且很有可能不是Objective-C写的。

这一次就让我们用Hopper来反编译Hopper吧!以子之矛,攻子之盾!

在Hopper的搜索框里输入gdb,可以看到很多相关的函数

屏幕快照 2014-12-18 下午5.33.26

不过这其中有一个和刚才的expired处于同一个类中,也就是toggleGDBWindow. 从字面上来看,切换GDB窗口,应该就是我们想要找的了。

跳到这个方法的汇编中,可以看见它调用了一个C函数,getApplicationStatus

屏幕快照 2014-12-18 下午5.38.41

这个C函数返回的值保存在eax中,随后的

test eax, eax
je 0x10001ed4d

if (eax == 0) { goto loc_0x10001ed4d;}

函数返回0则跳转到0x10001ed4d处,那么0x1000ed4d是什么呢?

屏幕快照 2014-12-18 下午5.45.25

已经很明显了呢,那么我们的目标就是这个getApplicationStatus函数了。

可是Hook C函数,在iOS上我们有CydiaSubstrate的MSFindSymbol帮我们,可是Mac上呢?对于私有C函数,我们似乎是无能为力。

不管怎么说,先看看这个C函数的汇编码吧。

屏幕快照 2014-12-18 下午5.51.14

很简单的调用,就是返回了currentStatus的值。再看一下这个函数的Cross References呢。

屏幕快照 2014-12-18 下午5.51.48

很多地方都用到了啊,那么我们只要小小的修改一下函数返回值不就全搞定了吗?

不过不能用runtime搞定的话,我们就来简单粗暴的方法吧!直接修改机器码!

如果我们能把

mov eax, dword [ds:___currentStatus_1004bec90]

改为我们想要的

mov eax, 0x1

就大功告成了。

在这一句汇编的左边,我们可以看见它的机器码:8B051AC74B00

于是借助Hex编辑器,搜索8B051AC74B00

屏幕快照 2014-12-18 下午6.01.59

仅仅拿到这些还不够,我们还需要知道mov eax, 0x1的机器码,这又得靠Hopper了,虽然不能直接保存。

屏幕快照 2014-12-18 下午6.04.17


屏幕快照 2014-12-18 下午6.04.35

于是我们就得到了机器码B801000000,不过这比原来的差一个字节,没关系,用nop补上吧~(nop的机器码和刚才一样的方法得到)

于是我们把8B051AC74B00替换为B80100000090

屏幕快照 2014-12-18 下午6.12.34

保存之后再打开Hopper,点击GDB

屏幕快照 2014-12-18 下午6.10.17

再试试保存功能、

屏幕快照 2014-12-18 下午6.11.05

嗯,没问题了呢!

11 thoughts on “Hopper Disassembler v2.8.1 破解笔记”

  1. 你好 最近看了这个网站的一个教程 http://adr.horse/?p=753 可是程式的版本变了 用hopper分析出的代码有些不一样 最后不知道要怎么修改 还有最后一步的应用程序签名 不知道要怎么完成 博主能帮帮我么 谢谢啦

  2. 其实博主操作还是有些麻烦了。
    今天看到了博主的文章(一直关注你呦~),于是来自己动手操作一下,毕竟自己用的是老版2.7.12版的破解版。
    之前objc动态操作的话,是不是性能会有点点欠缺。。手动改汇编码,不是更酸爽吗。。
    前提是找到破解版的ida,hopper啥的
    以下方法我都没实践过
    不会告诉你用旧版Hopper破解以后直接覆盖新版就免注册了
    按博主思路分析,第一步class dump出一大堆垃圾头文件,搜索到了有关registration的方法。基于博主找出的几个方法,可以猜测除了返回值为BOOL的方法,其余都是提供许可信息的方法,并无太大价值。(一看id就想到NSString,我这是怎么了= =)
    那就从checkSavedRegistration入手吧。
    通过Hopper分析发现,这个方法中有一个跳转,在0x100005396这个位置。
    如果test rax,rax失败了 那么就不跳转,继续往下执行,而之后的代码段里引向了checkRegistrationLicense这个方法 两个红包一手抓。那就要走另一条路了,就是0x1000053ad,这个分支就是简单无脑的一条指令 xor al,al 把al复位了。
    所以就直接把je改成jmp好了。
    接着是-(id)expired:(id)arg1的修改
    直接用流程图理解,它是通过调用getApplicationStatus来验证许可是否有效的
    hopper你直接把第三条拽出来了,说好的第二条呢?!
    强迫症善后,继续je改成jmp。
    最后getApplicationStatus的修改照博主做就行了。。
    如果有错误的地方还请博主么么哒指出= =

    1. 啊啦,最近没怎么上博客~
      正如你所说的,第一步的确是class dump出了一大堆垃圾头文件(我顺便hook了其中几个,改成了自己的信息,其实就是为了调戏一下Hopper)。

      一开始想用objc动态操作,其实就是图个方便,不太想直接上汇编码。性能上,和全靠改汇编码比起来,可能会慢一小点,但是基本也察觉不到就是啦:)

      1. 博主看了Hopper v3没有? 貌似免疫了class-dump
        万恶的Hopper v3,下载下来研究一下

      2. 看过了 基本上所有函数的签名 甚至字符串 都加密了 懒得研究了

        1. v3的加密丧心病狂,所以才选了v2来玩。
          当然要是真的有人想去破解v3的话,肯定也能做出来,只是太耗费时间和精力了。从技术上来说,破解v3应该会很(jing)有(jin)意(ren)思(wang);从其他方面来讲,Hopper已经很便宜了,直接买买买吧!

    1. 嘛,毕竟涉及到破解软件,虽然没有给出修改后的文件,但是还是得明确一下购买正版的思想,我又不想说的太正经,只好卖个萌顺便还能缓和一下气氛 :P

      niconiconi~~

Leave a Reply

Your email address will not be published. Required fields are marked *

two + eight =