前言
上次我写过一篇叫做Hopper 之 CrossOver 19 破解的帖子,可惜因为代{过}{滤}理商维权,帖子被吞了,移到了高级会员区。
那么今天,我再写一篇 CrossOver 19 的破文。上一篇文章里,我用了“直接修改二进制文件”的方法来破解应用,而这次,我则通过动态库注入的方法来破解 CrossOver 19——这是一个巧妙、新奇的方法,说白了就是 hook,你会喜欢上它的。我还要感谢@云在天大神在我的CleanMyMac X 破解贴里的指导,要不是她,可能我到现在还不知道什么是动态库注入。
前言的最后,我再说一下来意。我只是想教大家“破解方法”,而不是给大家“破解软件”。就拿例子说吧,我现在用的 Hopper Disassembler 可是正版的。因此,如果你喜欢 CrossOver 19,请购买正版。(如果代{过}{滤}理商看到了这篇文章,还是气得发毛的话,尽管删吧)
准备
- 从CrossOver 官网上下载最新版的 CrossOver 19 。
- Hopper Disassembler v4 一枚。
- 与上篇文章不同的是,我们需要 Xcode(我的版本是11)。
分析软件
分析 UI
首先打开CrossOver,简单的看了一下,分析出几个信息:
- 打开软件后弹出了一个要钱弹窗,弹窗里提示了试用剩余天数,并提示你购买软件或者进行使用;
- 要钱弹窗中有两个需要关注的按钮,一个是
现在试用,另一个是使用购买信息解锁; - 按下
现在试用按钮,可以直接跳转到App里,开始14天试用; - 开始试用App后,在
CrossOver里仍然可以进行App激活操作。 CrossOver 没有附加反调试工具。
于是,我们就有如下的破解思路:
- Patch 剩余天数;
- Patch 使用购买信息解锁的验证流程。
本文讲述第一种方法。
使用 Hopper 分析
拖进 Hopper,先分析一波,看看有什么函数。本来想搜索UI中的字符串,字符串搜索无果后,根据“剩余天数”的英文“left”,搜索关键词:
我们发现,第一个函数-[CXApplication daysLeft],于是打开伪代码发现,这个函数返回的是一个int,极有可能是剩余的天数。我们可以尝试 Patch 这里,使得该函数永远返回十六进制0x8ef8(等同于 36600 天)。
按照上一篇文章的破解方法,我们只需要:
mov rax, 0x8ef8ret然后试用天数就永远是 36600 天了。但是别忘了,我们今天是要讲如何使用动态库注入来 hook 函数的,接下来,咱们就开始 hook。
构建动态库
动态库注入原理
在macOS下的应用程序,绝大多数都会用Objective-C或Swift进行编译(Python这类的先不谈)。
如果程序使用了Objective-C编译,我们可以仗着Objective-C的动态消息传送机制与runtime,在程序运行时进行函数的调换。
然而我们 crakers 都面对的是已经编译好的程序,所以我们要把函数调换的过程写到一个动态库中,然后再用动态库注入工具(insert_dylib之类的)注入到原来的二进制文件中。
新建项目
首先,打开 Xcode(按一下这里你会神奇地发现 Xcode 打开了),新建项目,选择macOS > Library,新建动态库项目,如图:
动态库的名称可以随便起,此处叫做CrossOverPatch,Framework选择Cocoa,Type选择Dyamic(动态)。随便找个地方保存项目即可。
现在你会得到一个动态库项目。
编写动态库
首先打开工程文件里的CrossOverPatch.m文件,输入:
#import "CrossOverPatch.h"#import <objc/runtime.h>我们用两个#import语句,将CrossOverPatch.h文件与objc/runtime.h库引入。CrossOverPatch.h文件(头文件),是每个.m文件里必须引用的。而objc/runtime.h库就是大名鼎鼎的运行时类库。
之后我们在下面声明一个实现@implementation
@implementation CrossOverPatch@end接下来,我们在实现里定义一个 hook 方法:
- (int)daysLeftHook { NSLog(@"====== METHOD PATCHING ======"); return 36600;}我们在下面的步骤中要用这个方法来替换原函数daysLeft,实现 hook。这里需要注意一点,我们定义的这个函数的返回值(int)和参数列表(无)需要与原函数相同。NSLog则是打印语句,方便我们后期检测程序。最后的return语句,让函数返回了36600这个值。你当然也可以把36600写作0x8ef8。
我们在实现里添加一个+ (void) load方法,如下:
+ (void)load { NSLog(@"====== START DYLIB INJECT ======"); NSLog(@"====== GETTING METHOD ======"); Method origMethod = class_getInstanceMethod(NSClassFromString(@"CXApplication"), NSSelectorFromString(@"daysLeft")); Method newMethod = class_getInstanceMethod([CrossOverPatch class], @selector(orphansArray:)); method_exchangeImplementations(origMethod, newMethod); NSLog(@"====== METHOD SWIZZLED ======");}我们一行一行地讲解代码:
- 函数
load定义。load函数会在动态库被加载时触发; - 打印日志;
- 同上;
- 定义变量
origMethod,它的类型是Method,它的值是原程序的daysLeft方法。class_getInstanceMethod::函数可以获取一个类(第一个参数)的一个实例方法(第二个参数);NSSelectorFromString:可以通过一个字符串(第一个参数)来获取一个类;NSSelectorFromString可以通过一个字符串(第一个参数)获取一个Selector;
- 定义变量
newMethod,类型是Method,它的值是我们刚才自定义的daysLeftHook方法,我们要用这个方法来替换第4行的daysLeft方法。 - 将第四行和第五行定义的新、旧两个函数通过
method_exchangeImplementations::交换。这样的话,原程序的daysLeft就成了我们自定义的daysLeftHook,而我们自定义的daysLeftHook就成了原程序的daysLeft,也就意味着成功 hook 了。 - 打印日志。
CrossOverPatch.m写完了。别忘了打开CrossOverPatch.h文件,声明函数:
@interface CrossOverPatch : NSObject+(void)load;@end按下Cmd + B编译一下,最终得到动态库文件:libCrossOverPatch.dylib!
注入动态库
离破解只差一步——注入。方法有许多:运行bash脚本、修改info.plist……不过我更倾向于使用insert_dylib工具注入。点击这个链接即可将insert_dylib项目克隆到Xcode,编译得到insert_dylib可执行文件。
- 把
insert_dylib、CrossOverPatch.dylib和 CrossOver 19 应用程序的原来的二进制文件的绝对路径记录下来。 - 打开终端,输入命令:
$ cd [insert_dylib的路径]$ ./insert_dylib [dylib的路径] [原来的二进制文件的路径]回车后,如果出现
LC_CODE_SIGNATURE load command found. Remove it? [y/n],那么就按下y,回车。
如果出现Added LC_LOAD_DYLIB to /Applications/CrossOver.app/Contents/MacOS/CrossOver_patched,代表注入成功。
打开访达,进入/Applications/CrossOver.app/Contents/MacOS/位置,你还会发现有两个文件:CrossOver和CrossOver_patched。其中CrossOver_patched就是已经被我们注入的文件。将原来的CrossOver二进制删除或更改名称,将CrossOver_patched更名为CrossOver。
改头换面
通过下图找到电子权利信息:
找到后,用文本编辑打开,在文件开头加上一句类似下面的话:
这个版本的CrossOver已经由xxx破解。你可以放心使用。注意,请勿广泛传播……
验证破解
双击CrossOver二进制文件,即可打开应用程序。可以看见试用天数已经破解:
电子权利信息也被修改:
与此同时,你的电脑应该会弹出终端窗口。窗口中赫然显示着四行大字:
花果山福地水帘洞洞天齐天大圣到此一游
不好意思,搞错了,是这四行:
====== START DYLIB INJECT ============ GETTING METHOD ============ METHOD PATCHING ============ METHOD SWIZZLED ======反思
- 这篇文章只能算是动态库注入的冰山一角。还有很多东西值得我学习,比如怎样 hook
Swift方法,等等; - 原文是直接引用的
runtime里的函数,有很多缺陷。实际上用runtime封装的库很多:ZKSwizzle、JRSwizzle等等; - 如果文章叙述中有不专业、错误的地方,请批评指正,我会第一时间修改,避免误人子弟;
- 代{过}{滤}理商要想维权,尽管删吧。
声明:本站所有资源均由网友分享,如有侵权内容,请在文章下方留言,本站会立即处理。






代码写错了 哥哥