不一

最简单的Hopper Disassembler玩转Mac逆向

字数统计: 2.4k阅读时长: 8 min
2017/09/06 Share

工具

  • Folx
    一个mac上挺好用的下载工具,本文逆向破解的对象。直接把 Folx.app 拖到 Applications 文件夹中即可。

  • mySIMBL
    扩展包( plug in )管理软件,本文将要给Folx软件写扩展包达到破解的目的,因此使用mySIMBL进行扩展包管理,图形界面方便的删除、开启等功能。
    直接把 mySIMBL.app 拖到 Applications 文件夹中即可。

  • EasySIMBL-Bundle-Template
    一个扩展包XCode模板,类似于开发iOS在XCode新建工程时选的 Single View App
    EasySIMBL Bundle.xctemplate 文件夹拖到 ~/Library/Developer/Xcode/Templates/Project Templates 目录下即可,如图所示。
    EasySIMBL安放地址

  • class-dump
    iOS/Mac逆向必须介绍的软件,从 可执行文件 中导出头文件,然而本文用不上,不做介绍。
  • Hopper Disassembler
    超级强大的反编译软件,不仅可以把机器码解析成汇编,还能解析出相似与Objc的伪代码。总之就是太强大了,强大到我们几乎连 class-dump 都用不上了。本文提供了 史蒂芬周 的破解版本,把 Hopper Disassembler v4.app 拖进 HopperV4Patcher 即可破解,如图所示。
    破解Hopper

问题分析

Folx有个很方便的功能下载Youtube视频,只要把Youtube视频的URL输入就可以下载(而且速度还不错,暂时没验证需不需要科学上网)。然而这是个付费功能,只要点下OK按钮就会跳出讨钱页。
Folx
Folx叫你交保护费
听说有小伙伴因为种种原因弄不到Youtube的URL?下面提供一个。

https://www.youtube.com/watch?v=QFH747sK200

逆向分析

打开Hopper,选择 File-Read Executable to Disassemble 直接粗暴读取二进制可执行文件来破解,如图所示。
Hopper界面
选择Applications文件夹中的Folx,右键 显示包内容 ,并找到可执行文件,类似于win平台的 .exe 文件,在这里:
打开Folx可执行文件
等Hopper缓过神来,界面就差不多长这样。由于个人使用习惯,隐藏了底部和右边栏,可以在右上角的三个按钮选择是否开启。 左边栏是导航,可以看到使用Objc的方框语法列出了许多方法,还要啥class-dump?
中间区域是汉莫拉比法典,记载了一些上古语言,讲述了一些你不需要了解的事,直接无视就行。
Hopper界面
OK我们的目的是要破解YouTube下载功能,那么把 Youtube 当做关键词来搜索应该不会错,所以在左边栏的搜索框中输入 youtube ,可以得到许多和Youtube相关的类和方法:
搜索Youtube
我们来猜一下这都是些什么东西。(十秒逆向九秒猜)

  • FolxYouTubeHelper :看上去没有什么特别的东西,应该不是我们要找的。
  • AppDelegate :看上去也只是一个干杂货的,负责弹框之类,应该也不是我们要找的。
  • SDUrl :看上去像是个下载辅助的东西,应该还不是我们要找的。
  • FolxNewEditTask :看上去是负责新建下载任务相关的类,估计会包含验证之类的东西,我们可以尝试从这个入手。
    在搜索栏中查找 FolxNewEditTask ,可以得到一整列表,这东西有点肥,看上去方法很多,其实基本每个 @Property 都有 getset 两个方法。

    此处无图

FolxNewEditTask 的方法中看到一个 done: 方法,应该是新建任务完成的方法,也就是 OK按钮 的点击方法。选中该方法,一探究竟。
done方法
在顶部栏点击伪代码按钮可以把上古语言翻译成类似于Objc的代码,极大提高可阅读性。代码中还保留了许多汇编的特征,例如 rbxr14 之类的寄存器,可以简单理解为变量。如果你认可我葬爱家族,那么这样的代码对你来说应该没有任何阅读压力。
伪代码按钮
得到[FolxNewEditTask purchased]的伪代码:
伪代码
在方法的开头就是一个判断语句,由 && 区分出两个判断条件。
前一条件首先是一个Objc下消息机制的方法调用,由前一句 r14 = @selector(addTaskType); 可以猜测应该是判断当前的下载类型,记得Folx提供了三个下载类型,而Youtube是第三个类型,就是 ==0x2 成立。
下载类型
后一个条件的关键词在于 purchased ,这就很明显了。purchase的消息对象是rbx,前两句 rbx=self 可以知道FolxNewEditTask对象应该有个purchased方法,判断交没交保护费,如果交了就走else语句,没交的话就弹出交钱框,就是底下的 @selector(showFreeYouTubeAlert:)
不过我们的重点在于判断交保护费的方法,在左侧栏搜索,果然FolxNewEditTask是有这个方法,而且还有setPurchased方法,可以推知purchased 应该是一个成员属性。
purchased方法
这样我们就不用管它判断的机制是什么,只要这个方法返回 YES 就对了,办法就是 把FolxNewEditTask的purchased方法换成我们自己的purchased方法 ,这样不仅是YES,要返回大象都可以。

Hook

打开XCode,新建一个 EasySIMBL模板工程
新建工程
工程名无所谓,最重要的是 Target App Bundle Id ,也就是我们要破解的App的 Bundle ID ,在Folx.app的包内容中可以找到 info.plist 文件,然后找到Folx的Bundle ID。
我一般用如下结构存放文件,其中 Sources 组下存放原App中类的头文件,而 HookClasses 组下存放我们自制的对应类。
思维僵化的项目结构
首先在Sources下创建 FolxNewEditTask.h 文件,然后把里面的代码都删了,填入如下内容。

1
2
3
4
5
@interface FolxNewEditTask

- (BOOL)purchased;

@end

虽然我们创建了 FolxNewEditTask.h ,假装我们知道FolxNewEditTask的一切,其实我们只需要知道FolxNewEditTask有purchased这么一个方法,但这就够了,因为我们只需要一个 flag 。当然正经点的做法是使用 class-dump 导出 .h 头文件来使用, 学习class-dump
接着在 HookClasses 中创建FolxNewEditTask+Hook的.h和.m文件。在 FolxNewEditTask+Hook.h 文件中填入代码如下:

1
2
3
4
5
6
7
8
#import <Foundation/Foundation.h>
#import "FolxNewEditTask.h"

@interface NSObject(FolxNewEditTaskHook)

+ (void)hookFolxNewEditTask;

@end

FolxNewEditTask+Hook.m 文件中填入如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "FolxNewEditTask+Hook.h"

@implementation NSObject(FolxNewEditTaskHook)

+ (void)hookFolxNewEditTask {
NSError *error;
[self jr_swizzleMethod:@selector(purchased)
withMethod:@selector(banana_purchased)
error:&error];
if (error) {
NSLog(@"+++++hookFolxNewEditTask error: %@", error);
}
}

- (BOOL)banana_purchased {
return YES;
}

@end

  • banana_purchased 方法是我们自制的保护费管理员,不管什么情况下都会返回YES。
  • hookFolxNewEditTask 中我们调用 jr_swizzleMethod: 方法把FolxNewEditTask原本的purchased方法和我们自制的purchased方法交换。
    接着就是要在Folx程序启动的时候调用偷天换日大法。找到 Banana.m 或者 你的项目名.m ,里面已经提供好了 load 方法,搞Objc开发的都应该知道 load 方法是在类载入内存的时候调用,也是偷换方法的最佳时机。
    首先得导入我们的头文件:
    1
    #import "FolxNewEditTask+Hook.h"

其次在 load 方法后加上一行来调用偷换方法。

1
[NSClassFromString(@"FolxNewEditTask") hookFolxNewEditTask];

command + B 来编译一下,显示 build succeeded 这样扩展就已经安装好了。我们可以打开 mySIMBL 来管理扩展。

mySIMBL管理扩展界面
因为在扩展的方法中我们打印了一些信息,因此可以打开 Console.app 来查看,这个是系统自带程序,在 Launchpad 里找找。在Consolo里搜索 ++++ 来过滤其他不必要信息。
然后就是见证奇迹了,运行Folx吧。
在Console中接收到这么一条消息就表示扩展已经成功执行:

Console接收NSLog信息
接下来去测试一下Youtube功能是不是能使用。
点击OK之后讨厌的讨钱窗口没有跳出来,而是直接开始下载了,那么就算破解成功了:

Folx开始下载Youtube视频
根据我的猜测也有可能因为某些科学原因没法下载,因为公司都是科学上网的,所以我才不会开4G去验证呢。

更暴力的方法

正如标题所说, Hopper玩转Mac逆向 ,而没说Mac和XCode玩转Mac逆向。
Hopper掌握了机器码,就拥有了生杀大权,所谓汇编、伪代码都是解析给程序员看的,虽然说使用Hook方法替换原方法可以自定返回值,甚至可以返回大象!但是我们不需要大象,如果只是一个 BOOL 的事,汇编的修改是不是就够了呢? 当然,首先我们在mySIMBL里把方才所写的Folx扩展禁用掉,然后把Folx关了,回到Hopper中。
依旧在左侧栏中搜索找到 [FolxNewEditTask purchased] 方法,并选择汇编代码。
选择汇编代码
其实 [FolxNewEditTask purchased] 的Objc代码只有一两行,对应的汇编代码其实也不长,就7行:

1
2
3
4
5
6
7
1. push       rbp        
2. mov rbp, rsp
3. mov rax, qword [objc_ivar_offset_FolxNewEditTask__purchased]
4. mov al, byte [rdi+rax]
5. movsx eax, al
6. pop rbp
7. ret

rax 寄存器是返回值寄存器,相当于被放在 rax 里的值最后都会被 return rax;
rax 在第3行出现过一次,mov指令可以理解为赋值语句,意义是将 qword [objc_ivar_offset_FolxNewEditTask__purchased] 的值赋予 rax
我们不用管 qword [objc_ivar_offset_FolxNewEditTask__purchased] 是什么,我们要的结果是 return YES ,也就是 return 0x01 ,只需要确保在ret指令的时候rax的值是0x01即可。
因此选中 mov rax, qword [objc_ivar_offset_FolxNewEditTask__purchased] 一行,选择 Modify - Assemble Instruction ,输入如下指令:

1
mov rax, 0x01

回车
修改汇编代码
选择 File - Produce New Executable 来生成新的可执行文件Folx,替换掉原来的文件即可。

结尾

没有结尾。

CATALOG
  1. 1. 工具
  2. 2. 问题分析
  3. 3. 逆向分析
  4. 4. Hook
  5. 5. 更暴力的方法
    1. 5.1. 结尾