iOS 11上的破解入门教程

iOS 11上的破解入门教程

前言

我是个新手,接触iOS逆向破解没几个月,网上教程资料看了很多,知识点比较零散,使用的工具大都是针对iOS 10之前的,在iOS 11上基本无法使用,弯路走了不少,经过多次试验,最终摸索出了自己的破解思路和风格。

网上已经有很多基于CydiaSubstrate的越狱开发教程,使用theos、MonkeyDev进行开发非常方便、高效,而本文则是脱离CydiaSubstrate,以非Unity游戏《干掉月亮》(Shoot The Moon)为例,纯手工打造动态库,注入到游戏中实现破解,虽说效率不比使用CydiaSubstrate来的高,但是能学到很多基本的知识,非常适合新手入门。

准备工作

设备

一部越狱的iPhone手机(iOS 11.0~11.1.2)

一台Mac机

macOS上的工具

Xcode

Terminal

Console

ssh

scp

Homebrew

usbmuxd

macho_edit

Hopper Disassembler

Impactor

iOS上的工具

bfinject

applst

App

《干掉月亮》(Shoot The Moon)

下载安装

Xcode

从App Store下载,或者从苹果开发者页面下载都可以,下载最新版即可。

Terminal

macOS自带。许多命令需要在终端上执行。

Console

macOS自带。查看手机日志。

ssh

macOS自带。通过电脑登录手机。

scp

macOS自带。在手机和电脑间互传文件。

Homebrew

从Homebrew官网(brew.sh)下载安装。

用于安装各种命令行工具。

usbmuxd

打开Terminal,使用Homebrew安装。

$ brew install usbmuxd

# 或者

$ brew install libidevicemobile

将iPhone上的端口通过usb线映射到电脑上的端口。

macho_edit

从https://github.com/Tyilo/macho_edit下载源码。

编译后可以得到macho_edit可执行文件。

用于编辑App的可执行文件。

Hopper Disassembler

请自行搜索下载安装。

用于反编译App。

Impactor

从Cydia Impactor官网(www.cydiaimpactor.com)下载。

用于安装ipa到手机。

bfinject

从https://github.com/BishopFox/bfinject下载。

根据说明文档,将bfinject放到iPhone中。

用来砸壳、动态库注入等。

applst

从https://github.com/DeviLeo/AppList下载。

根据说明文档,将命令行版的applst放到iPhone中。

用于列出手机上安装的App及文档目录。

《干掉月亮》(Shoot The Moon)

从App Store下载。

这是一款有趣好玩的游戏。

破解

开局一台机,过程全靠猜。

下面正式进入破解阶段,我会非常啰嗦地写下所有的步骤。

如果您有一定地开发经验,尽情跳过所有已会的步骤。

砸壳

从App Store下载下来的App都是加密的,直接复制出来是无法使用Hopper Disassembler看到任何代码的,所以我们需要砸壳解密。

使用usbmuxd

如果你的Wifi环境不是很理想,可以使用usbmuxd映射端口走usb线。

此处我们映射iPhone上的ssh端口22到macOS上的2222端口,输入以下命令。

$ iproxy 2222 22

ssh登录iPhone

默认密码是 alpine。

# -p 后面跟端口,默认是22

$ ssh root@localhost -p 2222

root@localhost's password: # 输入密码,默认密码是alpine

查询名称及进程ID

启动《干掉月亮》,查询App名称和进程ID。

因为《干掉月亮》的英文名是《Shoot The Moon》,所以我们在搜索进程的时候使用grep来筛选出带有moon的输出行。

$ ps -e | grep moon

1975 ?? 0:59.42 /var/containers/Bundle/Application/24546F40-53DA-4C49-81C0-DED0C13DB814/shootthemoon.app/shootthemoon

砸壳

有了App名称和进程ID,我们就可以使用bfinject来砸壳了。

# 以下两条命令二选一,推荐使用App名称

# 使用App名称

$ bash bfinject -P shootthemoon -L decrypt

# 使用进程ID

$ bash bfinject -p 1975 -L decrypt

# 输出结果

[+] Liberios detected

[+] Injecting into '/var/containers/Bundle/Application/24546F40-53DA-4C49-81C0-DED0C13DB814/shootthemoon.app/shootthemoon'

[+] Getting Team ID from target application...

[+] Thinning dylib into non-fat arm64 image

[+] Signing injectable .dylib with Team ID A6DVR4V967 and platform entitlements...

[bfinject4realz] Calling task_for_pid() for PID 1975.

[bfinject4realz] Calling thread_create() on PID 1975

[bfinject4realz] Looking for ROP gadget... found at 0x1826574e0

[bfinject4realz] Fake stack frame at 0x10b624000

[bfinject4realz] Calling _pthread_set_self() at 0x182897804...

[bfinject4realz] Returned from '_pthread_set_self'

[bfinject4realz] Calling dlopen() at 0x182657460...

[bfinject4realz] Returned from 'dlopen'

[bfinject4realz] Success! Library was loaded at 0x1c41e2d00

[+] So long and thanks for all the fish.

命令执行完成并不表示砸壳已经完成,需要以App界面的提示为准。

下图为砸壳中,务必保持屏幕常亮。

下图为砸壳完成。

如果你会使用NetCat,选择YES,将砸壳后的App传到电脑上。否则选择No,稍后使用scp来传输文件。

砸壳后的文件在App的文档目录下,名字为decrypted.ipa。

注意:

1、bfinject命令必须在bfinject目录下执行,在其它目录下执行会出错。

2、如果砸壳过程中出现闪退,按Ctrl+C退出,重启App,再执行一遍砸壳命令即可。

找到《干掉月亮》的App文档目录

此处使用工具applst查询App的文档目录。

# applst默认会列出所有用户安装的App以及BundleID,

# 使用grep过滤只显示《干掉月亮》的BundleID

$ applst | grep shoot

$ applst com.pipsqueakgames.shootmoon

# 此处会显示《干掉月亮》的相关信息

localizedName:

Shoot Moon

shortVersionString:

1.6

vendorName:

Shaun Coleman

applicationIdentifier:

com.pipsqueakgames.shootmoon

itemID:

809390893

itemName:

Shoot The Moon

teamID:

A6DVR4V967

bundleURL:

file:///private/var/containers/Bundle/Application/24546F40-53DA-4C49-81C0-DED0C13DB814/shootthemoon.app

dataContainerURL:

file:///private/var/mobile/Containers/Data/Application/99B25BD3-77BA-47F0-9503-46F912C5A2E4

applicationType:

User

其中 bundleURL 就是App的目录,dataContainerURL 是App的文档目录,数据、缓存、临时文件都存储在这个目录。

注意:少数情况下,一个App可能拥有 多个dataContainerURL,applst只能列出其中一个。

传输砸壳后的文件

电脑上输入以下命令,将Documents目录下的decrypted-app.ipa传到电脑上。

# -P 后面跟端口,默认是22

$ scp -P 2222 root@localhost:/private/var/mobile/Containers/Data/Application/99B25BD3-77BA-47F0-9503-46F912C5A2E4/Documents/decrypted-app.ipa ./

root@localhost's password: # 输入密码,与ssh登录时的密码相同

破解

解压砸壳后的ipa

如下图,选中ipa文件,右键选择解压工具解压,使用系统默认的解压工具即可。

备份可执行文件

解压后得到一个文件夹叫Payload,里面有shootthemoon.app,其实是一个文件夹。

如下图,选中后右键选择显示包内容。

找到 shootthemoon 没有后缀名的文件,这是一个砸壳后的Mach-O格式的可执行文件。

复制一份到其它目录,准备拿它开刀。

使用Hopper Disassembler

启动Hopper Disassembler,菜单栏中选择File->Read Executable to Disassembler...,或者按下快捷键Command+Shift+O,弹出的对话框中选择 shootthemoon 文件,再点击OK。

紧接着会弹出如下图所示的对话框,保持默认选项,点击OK。

等待解析完成后,File->Save或Command+S保存一下,以免闪退后又要重新解析。

猜猜猜

虽然Hopper Disassembler已经为我们解析出来大部分的方法名,但是我们不知道该从何下手。

与其瞎忙活,不如先玩一盘再说。

哇哦,10分!在游戏中靠近顶部的地方有一条隐隐约约的横线,当目标正好压在这根线上时,击中会得到10分,连着击中3次10分可以获得双倍分数的加成,而在那根线下面击中时分数会递减,加成也会消失,那就有思路了,我们把那根线移到最下面,这样我们就可以不管目标在哪个位置时,击中都能获得10分。

让我们回到Hopper Disassembler,在左侧列表中输入“ten”,看看能不能搜索到有关设置10分线位置的方法。

哇哦,运气太好了,这么容易就找到了,MainEnemy 类里面有一个方法名叫做 tenPointLineY 的方法,看名字应该是10分线的Y坐标,如果能将Y坐标改为屏幕最底部就能达到目的了。

嗯?你想直接改汇编代码?这对于新手来说太难了,我们用高级语言来实现我们想法。

编写动态库

打开Xcode,创建一个Project,选择Cocoa Touch Framework,名字就叫ShootMoonHacker。

首先新建文件,选择Cocoa Touch Class,名字叫HackerLoader,继承NSObject类,动态库加载时初始化的代码写在这个类中。

再新建一个文件,选择Objective-C File,文件类型选择Category,类选择NSObject,名字叫Hacker,所有的破解代码都写在这个分类中。

工程目录结构如下图。

ShootMoonHacker.h

这个文件是创建工程时自动创建的,我们将需要公开的类全部写在这个文件里即可。

#import

//! Project version number for ShootMoonHacker.

FOUNDATION_EXPORT double ShootMoonHackerVersionNumber;

//! Project version string for ShootMoonHacker.

FOUNDATION_EXPORT const unsigned char ShootMoonHackerVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import

#import

#import

我们在文件的最后追加我们之前创建的类和分类。

import时记得使用尖括号,而不是双引号。

NSObject+Hacker.h

我们在分类头文件中声明一个方法,叫hack,提供给HackerLoader类调用,执行破解代码。

#import

@interface NSObject (Hacker)

- (void)hack;

@end

NSObject+Hacker.m

现在我们开始改写 tenPointLineY 方法。

我们可以使用Objective-C运行时的方法交换来达到我们的目的。

此处我事先封装了交换方法的代码,参数是原始方法名、原始类名、新方法、新类、是否为实例方法。

虽然我们目前只需要交换 tenPointLineY 这一个方法,但是考虑到以后可能需要交换多个方法,为了避免出现大量重复的代码,所以封装一下,同时也能让代码看起来整洁一点。

- (void)exchangeMethod:(NSString *)methodName ofClass:(NSString *)className toMethod:(SEL)method ofClass:(Class)class isInstanceMethod:(BOOL)isInstanceMethod {

Class c = NSClassFromString(className);

SEL sel = NSSelectorFromString(methodName);

Method om = isInstanceMethod ? class_getInstanceMethod(c, sel) : class_getClassMethod(c, sel);

Method nm = isInstanceMethod ? class_getInstanceMethod(class, method) : class_getClassMethod(class, method);

method_exchangeImplementations(om, nm);

}

注:使用方法交换需要导入头文件。

#import

接下来编写我们自己的 tenPointLineY 方法,名字就叫 my_tenPointLineY。

- (float)my_tenPointLineY {

NSLog(@">>>>> my_tenPointLineY");

float ret = [self my_tenPointLineY];

NSLog(@">>>>> my_tenPointLineY ret: %f", ret);

ret = 200;

NSLog(@">>>>> change tenPointLineY ret to: %f", ret);

return ret;

}

[self my_tenPointLineY] 这一句,其实调用的是原始的 tenPointLineY 方法,因为在交换方法后,原始的 tenPointLineY 方法名对应的是 my_tenPointLineY 方法的代码段,而 my_tenPointLineY 方法名对应的是 tenPointLineY 方法的代码段。

具体可以搜索 Method Swizzling 来了解方法交换的细节。

我们不知道把10分线的Y坐标改为多少才是我们想要的效果,先改个200试试看。

添加NSLog打印日志是为了确定代码是否按我们预期的那样执行了。

写完 my_tenPointLineY,开始交换方法,也就是实现我们最开始声明的hack方法。

- (void)hack {

NSString *className = @"MainEnemy";

Class selfClass = [self class];

// TenPointLineY

[self exchangeMethod:@"tenPointLineY" ofClass:className

toMethod:@selector(my_tenPointLineY) ofClass:selfClass

isInstanceMethod:YES];

}

原始的 tenPointLineY 是属于 MainEnemy 类的,my_tenPointLineY 是属于 NSObject 类的,是实例方法。

HackerLoader.m

我们希望在动态库加载时自动执行破解代码的话,需要这么写。

static void __attribute__((constructor)) entry(void) {

NSLog(@">>>>> Code Injected <<<<<");

NSObject *obj = [[NSObject alloc] init];

[obj hack];

}

不要忘记导入头文件 NSObject+Hacker.h。

#import "NSObject+Hacker.h"

方法 entry 的名字不是固定的,可以是你想要的任何符合命名规则的名字。

关键的是 __attribute__((constructor)) ,当动态库被加载的时候,会自动执行拥有此属性的方法。

编译

在编译之前,有些工程配置需要修改。

修改运行所需的最低系统版本

如下图,iOS Deployment Target 改为 iOS 11.0。

修改签名

如下图,签名 改为 None。

修改编译目标

如下图,编译目标 改为 Generic iOS Device。

配置修改完成后,按下Command+B编译。

编译成功后,就能得到ShootMoonHacker.framework。

动态库注入

展开Products目录,右键ShootMoonHacker.framework,选择Show in Finder。

新开一个Terminal窗口,输入 cd空格,然后把 ShootMoonHacker.framework 目录拖到Terminal窗口上,如下图。

松开后,效果如下图。

按下回车键后,我们需要将 ShootMoonHacker 文件传到iPhone上,命令如下。

$ scp -P 2222 ShootMoonHacker root@localhost:~/

root@localhost's password: # 输入密码

我猜测 tenPointLineY 这个方法会在开始游戏时调用,所以先将游戏退到初始界面,然后回到通过电脑ssh登录到iPhone上的Terminal窗口,进入到bfinject目录,输入如下命令注入我们的动态库。

# 注入动态库

$ bash bfinject -P shootthemoon -l ~/ShootMoonHacker

# 输出结果

[+] Liberios detected

[+] Injecting into '/var/containers/Bundle/Application/24546F40-53DA-4C49-81C0-DED0C13DB814/shootthemoon.app/shootthemoon'

[+] Getting Team ID from target application...

[+] Thinning dylib into non-fat arm64 image

[+] Signing injectable .dylib with Team ID A6DVR4V967 and platform entitlements...

[bfinject4realz] Calling task_for_pid() for PID 3593.

[bfinject4realz] Calling thread_create() on PID 3593

[bfinject4realz] Looking for ROP gadget... found at 0x1826574e0

[bfinject4realz] Fake stack frame at 0x10b3c8000

[bfinject4realz] Calling _pthread_set_self() at 0x182897804...

[bfinject4realz] Returned from '_pthread_set_self'

[bfinject4realz] Calling dlopen() at 0x182657460...

[bfinject4realz] Returned from 'dlopen'

[bfinject4realz] Success! Library was loaded at 0x1c0151b40

[+] So long and thanks for all the fish.

注意:

1、bfinject命令必须在bfinject目录下执行,在其它目录下执行会出错。

2、如果注入过程中出现闪退,按Ctrl+C退出,重启App,再执行一遍注入命令即可。

注入成功后,我们开始游戏看一下效果。

就像游戏中的肥蜜蜂一样,我皱起了眉头。

怎么没有任何效果,是不是动态库没有执行?

查看日志

让我们在电脑上打开Console,选择iPhone,重启游戏再执行一遍注入。

由于日志太多,我们在搜索栏输入“>>>”,按下回车,可以在列表中看到我们注入成功的代码。右键选择我们动态库输出的那行日志,选择Show Process 'shootthemoon',这样列表就会隐藏其它和我们App无关的日志了。

日志告诉我们,注入成功了,但是10分线的位置为什么没有改变呢?开始游戏的时候似乎也没有调用我们的代码。难道10分线的位置是启动游戏时候调用的?抱着试试看的想法,我们在游戏启动的瞬间执行注入命令,不过这么做会导致游戏卡住然后闪退,只能换一种方式了。

换个姿势插入动态库

还记得我们的 shootthemoon.app 目录吗?把我们的动态库文件 ShootMoonHacker 复制到这个目录下。

接下来我们要使用 macho_edit 工具来修改 shootthemoon 可执行文件的动态库列表。

还记得我们备份出来的那个 shootthemoon 文件吗?我们对它下手。

执行如下命令。

$ macho_edit shootthemoon

# 输出内容

Thin mach-o binary:

arm64 arch (offset 0x0)

1 Fat mach-o configuration

2 Load command edit

3 Exit

Select an option: 2

选择 2 Load command edit,编辑列表。

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 1

选择 1 List load commands,看看原始的列表有哪些内容。

arm64 arch (offset 0x0):

0: LC_SEGMENT_64: __PAGEZERO

1: LC_SEGMENT_64: __TEXT

2: LC_SEGMENT_64: __DATA

3: LC_SEGMENT_64: __LINKEDIT

4: LC_DYLD_INFO_ONLY

5: LC_SYMTAB

6: LC_DYSYMTAB

7: LC_LOAD_DYLINKER: /usr/lib/dyld

8: LC_UUID: 6f33289b-6f33-3328-9b6d-3c3a847d7f7f

9: LC_VERSION_MIN_IPHONEOS: 0.0.0

10: LC_SOURCE_VERSION

11: LC_MAIN: 0x242d8

12: LC_ENCRYPTION_INFO_64

13: LC_LOAD_DYLIB: /usr/lib/libz.1.dylib

14: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreText.framework/CoreText

15: LC_LOAD_DYLIB: /System/Library/Frameworks/EventKit.framework/EventKit

16: LC_LOAD_DYLIB: /System/Library/Frameworks/EventKitUI.framework/EventKitUI

17: LC_LOAD_DYLIB: /System/Library/Frameworks/WebKit.framework/WebKit

18: LC_LOAD_DYLIB: /System/Library/Frameworks/Social.framework/Social

19: LC_LOAD_DYLIB: /System/Library/Frameworks/Security.framework/Security

20: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreTelephony.framework/CoreTelephony

21: LC_LOAD_DYLIB: /System/Library/Frameworks/MessageUI.framework/MessageUI

22: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreData.framework/CoreData

23: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreMedia.framework/CoreMedia

24: LC_LOAD_DYLIB: /System/Library/Frameworks/StoreKit.framework/StoreKit

25: LC_LOAD_DYLIB: /System/Library/Frameworks/AdSupport.framework/AdSupport

26: LC_LOAD_DYLIB: /System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration

27: LC_LOAD_DYLIB: /System/Library/Frameworks/GameKit.framework/GameKit

28: LC_LOAD_DYLIB: /System/Library/Frameworks/OpenAL.framework/OpenAL

29: LC_LOAD_DYLIB: /System/Library/Frameworks/UIKit.framework/UIKit

30: LC_LOAD_DYLIB: /System/Library/Frameworks/QuartzCore.framework/QuartzCore

31: LC_LOAD_DYLIB: /System/Library/Frameworks/AVFoundation.framework/AVFoundation

32: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics

33: LC_LOAD_DYLIB: /System/Library/Frameworks/OpenGLES.framework/OpenGLES

34: LC_LOAD_DYLIB: /System/Library/Frameworks/Foundation.framework/Foundation

35: LC_LOAD_DYLIB: /System/Library/Frameworks/AudioToolbox.framework/AudioToolbox

36: LC_LOAD_DYLIB: /usr/lib/libobjc.A.dylib

37: LC_LOAD_DYLIB: /usr/lib/libc++.1.dylib

38: LC_LOAD_DYLIB: /usr/lib/libSystem.B.dylib

39: LC_LOAD_DYLIB: /System/Library/Frameworks/CFNetwork.framework/CFNetwork

40: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation

41: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreMotion.framework/CoreMotion

42: LC_LOAD_DYLIB: /System/Library/Frameworks/CoreVideo.framework/CoreVideo

43: LC_LOAD_DYLIB: /System/Library/Frameworks/GLKit.framework/GLKit

44: LC_LOAD_DYLIB: /System/Library/Frameworks/MediaPlayer.framework/MediaPlayer

45: LC_LOAD_DYLIB: /System/Library/Frameworks/MobileCoreServices.framework/MobileCoreServices

46: LC_FUNCTION_STARTS

47: LC_DATA_IN_CODE

48: LC_CODE_SIGNATURE

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 3

能看到加载了很多系统的动态库。

选择 3 Insert load command,将我们的动态库注入到文件中。

Select the cmd you want to insert:

1 LC_LOAD_DYLIB

2 LC_LOAD_WEAK_DYLIB

3 LC_RPATH

4 Cancel

Select an option: 1

选择 1 LC_LOAD_DYLIB,注入动态库。

Dylib path: @executable_path/ShootMoonHacker

输入 @executable_path/ShootMoonHacker,按下回车。

@executable_path 指的是 shootthemoon 这个可执行文件所在的目录,也就是 shootthemoon.app 这个目录。

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 1

选择 1 List load commands,看看编辑是否成功。

49: LC_LOAD_DYLIB: @executable_path/ShootMoonHackers/MediaP

如果列表中最后一项不是输入的那样,如上结果后面跟着其它字符,说明编辑出现了bug,需要退出 macho_edit,删除错误内容,再重新插入。

# 此处已省略无关内容

49: LC_LOAD_DYLIB: @executable_path/ShootMoonHackers/MediaP

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 6

选择6,取消编辑。

1 Fat mach-o configuration

2 Load command edit

3 Exit

Select an option: 3

选择3,退出。重新再次编辑。

$ macho_edit shootthemoon

# 输出内容

Thin mach-o binary:

arm64 arch (offset 0x0)

1 Fat mach-o configuration

2 Load command edit

3 Exit

Select an option: 2

选择2,编辑。

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 2

选择2,删除。

Select a load command to remove:

# 此处已省略无关内容

50 LC_LOAD_DYLIB: @executable_path/ShootMoonHackers/MediaP

51 Cancel

Select an option: 50

选择50,删除bug导致的错误的动态库路径。

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 3

选择3,删除后重新插入动态库。

Select the cmd you want to insert:

1 LC_LOAD_DYLIB

2 LC_LOAD_WEAK_DYLIB

3 LC_RPATH

4 Cancel

Select an option: 1

选择1,动态库。

Dylib path: @executable_path/ShootMoonHacker

输入动态库路径 @executable_path/ShootMoonHacker。

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 1

选择1,确认插入的动态库路径是否正确。

arm64 arch (offset 0x0):

# 此处已省略无关内容

49: LC_LOAD_DYLIB: @executable_path/ShootMoonHacker

1 List load commands

2 Remove load command

3 Insert load command

4 Move load command

5 Remove code signature

6 Cancel

Select an option: 6

选择6,动态库路径插入正确,可以退出编辑。

1 Fat mach-o configuration

2 Load command edit

3 Exit

Select an option: 3

选择3,退出。

打包安装

把编辑好的 shootthemoon 文件覆盖掉 shootthemoon.app 目录下的原始文件。

然后在Finder中,右键 Payload 文件夹,选择 压缩"Payload",得到 Payload.zip 压缩包,将其重命名为 shootthemoon_hacked.ipa。

打开 Impactor 工具,将 shootthemoon_hacked.ipa 文件拖到 Impactor 的 install Cydia Extender 的位置上。

松开后,会要求输入你的 Apple ID 和 密码,然后会将ipa安装到手机上。

注意:

1、Apple账号需要关闭二次验证功能,否则Impactor会安装失败。

2、安装前务必先卸载原来的App,因为从App Store下载的App签名与Impactor安装的App签名不同,所以无法覆盖安装。

推荐:申请一个新的Apple账号,专门用于Impactor安装ipa。

胜败乃兵家常事

安装完成后,赶紧启动游戏看一下效果。

好尴尬啊~虽然10分线出现在了底部,但是分数还是没变。看来 tenPointLineY 只是修改位置,并不会影响到分数。

大侠请重新来过

既然改10分线没有用,那就简单粗暴点,直接改分数吧。

让我们回到Hopper Disassembler,在左侧列表中输入“point”,看看能不能搜索到和分数相关的方法,貌似没有,换个词试试,搜索“score”看看。

第一条 -[GamePlay updateScore:] 貌似看上去可能或许大概应该好像就是修改分数的方法,尝试一下?尝试一下!

回到Xcode,在 NSObject+Hacker.m 文件中添加以下代码。

- (void)my_updateScore:(int)score {

NSLog(@">>>>> my_updateScore: %d", score);

score = 10000;

NSLog(@">>>>> my_updateScore change score to: %d", score);

[self my_updateScore:score];

NSLog(@">>>>> my_updateScore done");

}

我们把分数固定在10000分,先看看效果如何。

然后修改hack方法,如下。

- (void)hack {

NSString *className = @"GamePlay";

Class selfClass = [self class];

// UpdateScore

[self exchangeMethod:@"updateScore:" ofClass:className

toMethod:@selector(my_updateScore:) ofClass:selfClass

isInstanceMethod:YES];

}

注意:updateScore是带参数的,对应的字符串后面要有冒号。

例子:- (NSInteger)plus:(NSInteger)a and:(NSInteger)b; 方法对应的字符串就是"plus:and:"。

编译通过后,将动态库传到iPhone上,用bfinject注入,玩一下看看。

哈哈哈哈哈,这个貌似有点过分了。虽然和预期想的不太一样,以为updateScore修改的是左下角的总分数,阴差阳错地修改了击中时获得的分数,既然如此我们把分数固定在10分就可以了。

修改代码后,重新编译,再次注入,看看效果。

完美。我们有了如此完美的动态库,可以有两种选择。

1、针对越狱机器,我们保留从App Store下载的版本,需要时通过bfinject注入即可。

2、针对非越狱机器,我们用macho_edit插入动态库,重新打包安装。

总结

基本知识点

1、usbmuxd的使用

2、ssh与scp的使用

3、使用bfinject砸壳

4、Hopper Disassembler的使用

5、Method Swizzling,方法交换

6、动态库的编写

7、使用bfinject实时注入动态库

8、使用macho_edit插入动态库

9、重新打包ipa

10、Impactor的使用

其它

1、如果有苹果开发者账号,可以使用 iOS App Signer 对ipa重签名,然后使用Xcode安装即可。

相关阅读