一、概述
iOS 逆向工程是指在软件层面上进行逆向分析的一个过程,基于 iOS 逆向工程技术,我们可以监控甚至改变 APP 的运行逻辑,从而达到获取核心信息,了解软件设计原理等目的。通过一段时间对 iOS 逆向工程的研究发现很有趣,会在博客记录学习开发过程中的心得和笔记。
二、用到的设备或工具
- 一台越狱设备:iPhone 手机越狱和 Android 手机 ROOT 一样非常简单,具体的越狱方法网上很多,这里不在讨论。
- Cydia:一般越狱过的手机都会自动被安装该软件,相当于App Store,可以搜索安装越狱app,也可以用来管理(卸载)我们开发的插件。
- Theos:越狱开发工具包。
- ldid:模拟给 iPhone 签名的流程,使我们能够在真实的设备上安装越狱的 apps/hacks。
- dkpg:一个 Debian 的一个命令行工具,它可以用来安装、删除、构建和管理 Debian 的软件包。
三、软件或工具的介绍与安装
1、Theos
越狱开发中除了 Thoes 外还有一个叫 iOSOpenDev 的工具,功能和 Thoes 是一样的,不同点是 iOSOpenDev 是整合到 Xcode 中使用的,通过本人亲身实践发现使用 Thoes 开发更简单方便,感兴趣的可以去了解下 iOSOpenDev,这里不再讲解,个人建议使用 Thoes,本文也将以 Thoes 为基础进行开发。
安装 Thoes 方法如下:
首先设置环境变量,我们将 Thoes 安装在 /opt/theos 中,打开 terminal 然后输入:
1 | export THEOS=/opt/theos |
通过在命令行执行 echo $THEOS
可以看到这个变量是否正确设置。每次你打开 terminal 都需要重新设置一下。
然后下载Theos:
1 | sudo git clone git://github.com/DHowett/theos.git $THEOS |
之后会提示输入密码,输入密码等待下载完成即可。
2、ldid
ldid 是一个用来给 iOS 可执行程序签名的工具,使我们开发的越狱 APP 或者插件能够安装到越狱手机上。
我们可以从http://joedj.net/ldid上下载 ldid 后拷贝到“/opt/theos/bin/”目录中,然后使用下面命令行赋予可执行权限:
1 | sudo chmod 777 /opt/theos/bin/ldid |
3、dkpg
Dpkg 能够把你的 APP 打包成 Debian Package,可以分发的 Cydia 的存储目录中。
1 | brew install dpkg |
4、配置 libsubstrate.dylib
在开始开发之前,还需要下载 libsubstrate.dylib,然后 copy 到“/opt/theos/lib”目录下即可,点击下载:libsubstrate.dylib
由于某些的原因,访问国外网站需要梯子,如果你没有梯子,可以从我网盘下载:
http://pan.baidu.com/s/1hsL0llM
最后我们在开发之前可以看下 Theos 中的模板,执行如下命令可以看到默认存在的模板:
1 | $THEOS/bin/nic.pl |
有的人会在使用模板创建项目的时候会有如下提示:
原因是没有执行如下命令:
1 | export THEOS=/opt/theos |
上面已经说了,每次都要执行一次,如果不想每次都执行也可以直接使用如下命令:
1 | /opt/theos/bin/nic.pl |
可以看到上面一共有 17 个模板。
实际上安装 后默认只有 12 个模板,想要添加更多模板,可以从[https://github.com/DHowett/theos-nic- templates/archive/master.zip55.tar](https://github.com/DHowett/theos-nic- templates/archive/master.zip55.tar)下载额外的 5 个模板,下载后解压得到的 5 个 .tar 文件复制到“/opt/theos/templates/iphone/”目录下即可。
四、创建工程
首先介绍一下本教程所写插件实现的功能:“修改”设备信息。实际上对于系统硬件信息是不能修改的,但是我们可以修改获取设备信息的方法的返回值,比如我们获取系统版本用如下方法:
1 | [[UIDevice currentDevice] systemVersion]; |
如果我们的系统是 10.0.2 版本,该方法会返回字符串“10.0.2”,我们要做的就是当别的 APP 调用上面方法时,我们拦截住并返回一个我们设定的任意值,比如我们让上面方法返回 “11.0.2”,这就是传说中的 HOOK。
首先我们新建一个文件夹 MyDemo,cd 到该文件夹中,然后按照上面所说的,我们使用如下命令查看与选择模板:
1 | $THEOS/bin/nic.pl |
我们选择模板 15(iphone/tweak),之后根据提示输入 Project Name(tweak 工程名)、Package Name(deb 包的名字,类似于bundle identifier)、Author(作者)、Bundle filter(tweak作用对象的 bundle identifier)即可,具体的根据实际情况填写。
最后在 MyDemo 目录中生成的文件如下:
介绍一下上面的几个文件:
(1) control 文件
主要记录的 deb 包管理系统所需要的基本信息,会被打包进 deb 包中,该文件中主要是我们创建工程时所填写的信息,如下:
1 | Package: com.imlifengfeng.tweakdemo |
(2) Makefile 文件
用于指定工程用到的文件、框架、库等信息,将整个过程自动化,文件默认内容如下:
1 | include $(THEOS)/makefiles/common.mk |
注意一下上面第一行,如果在使用命令行做操作(如打包、安装)时,如果没有执行下面命令会报错:
1 | export THEOS=/opt/theos |
这个是新手容易犯的错误,还是一样,想省事也可以把上面第一行直接改成:
1 | include /opt/theos/makefiles/common.mk |
我们需要在 Makefile 文件中做一些配置:
设置我们用到的框架:
1 | tweakDemo_FRAMEWORKS = UIKit CoreGraphics |
注意一下前缀 tweakDemo,这是你的项目名,根据自己项目名填写。
指定 iOS SDK 版本(这里指定采用最新版 SDK,插件适用最低版本9.0):
1 | TARGET = iphone:latest:9.0 |
上面的 latest 可以也设置成具体版本,如 10.0。
已连接目标真机的IP:
1 | THEOS_DEVICE_IP=192.168.2.61 |
注意:这里使用的 ssh 连接的,关于连接真机,有个注意的一点是最新的越狱方法已经不再需要手机安装 OpenSSH 插件了,安装后反而无法连接。但是 OpenSSH 功能是默认禁用的,需要手动开启。开启方法也很简单,在 Cydia 中搜索 Filza 并安装,进入以下路径:/private/var/containers/Bundle/Application/yalu102/yalu102.app/,用文本编辑器打开 dropbear.plist 文件,替换 127.0.0.1:22 为 22,重启设备,重新使用越狱工具恢复越狱即可。
最终配置完后的文件内容如下:
1 | include /opt/theos/makefiles/common.mk |
(3) Tweak.xm 文件
该文件就是我们写相关代码的文件,使用的是 Logos 语言。
(4) tweakdemo.plist文件
这个文件主要用来设置插件的作用范围,对哪些 APP 有效,比如可以设置哪些 APP 调用我们 HOOK 的方法时返回我们设定的值。
用 Xcode 打开其内容如下:
用Sublime等编辑器打开内容如下:
1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } |
写完相关的代码记得把作用的 APP 的 bundle identifier 加上。
五、插件代码编写
上面介绍了生成的几个文件,可以知道我们在 Tweak.xm 文件中写 Tweak 代码。我们要实现的功能就是 HOOK 获取设备信息的方法,为了验证效果,我们先写一个 APP(bundle identifier 为imlifengfeng.InfoGetter)用来获取设备信息,界面如下:
核心代码为:
1 | // |
也就是说我们要HOOK住的三个方法为:
1 | [[UIDevice currentDevice] name] |
开始写之前先简单下 Logos 语言,非常简单:
(1) %hook
指定需要 hook 的 class,必须以 %end
结尾
1 | %hook SpringBoard |
这段代码的意思是勾住(hook) _SpringBoard_
类里的__menuButtonDown:_
函数,先将一句话写入 _syslog_
, 再执行函数的原有操作。
(2) %log
该指令在 %hook
内部使用,将函数的类名、参数等信息写入 syslog
。
1 | %hoot SpringBoard |
(3) %orig
该指令在 _%hook_
内部使用,执行被勾住(hook)的方法的原始代码。例如:
1 | %hook SpringBoard |
如果去掉 _%orig_
那么原始方法不会执行:
1 | hook SpringBoard |
还可以利用 _%orig_
更改原始行数的参数:
1 | %hook SBLockScreenDateViewController |
这个方法会改变锁屏界面的日期显示。
(4) %group
该指令用于将_ %hook _
分组,便于代码管理及按条件初始化分组,必须以 _%end_
结尾;一个_ %group _
可以包含多个_ %hook _
, 所有不属于某个自定义_ group _
的_ %hook _
会被隐式归类到_ %group_ungroupes _
中。用法如下:
1 | %group iOS7Hook |
(5) %init
该指令用于初始化某个 _%group _
,必须在_ %hook _
或_ %ctor _
内调用;如果带参数,则初始化指定的 group
,如果不带参数,则初始化 __ungrouped_
,如下:
1 | #ifndef kCFCoreFoundationVersionNumber_iOS_8_0 |
只有调用了 %init
,对应的 %group
才能起作用。
(6) %new
在 _%hook_
内部使用,给一个现有 _class_
加新函数,功能与 _class_addMethod_
相同。它的用法如下:
1 | %hook SpringBoard |
(7) %c
该指令的作用等同于 _objc_getClass_
或 _NSClassFromString_
,即动态获 一个类的定义,在 _%hook_
或 _%ctor_
内使用。
由于我们只是要 HOOK 住三个方法,所以我们只能用到 %hook
。
具体怎么实现呢?非常简单,我们要 HOOK 的方法是 UIDevice
类中的 name
、systemVersion
、model
三个方法,所以我们在 Tweak.xm 文件中直接写代码:
1 | #import <SpringBoard/SpringBoard.h> |
然后在 tweakdemo.plist 文件中加上上面我们写的测试 APP 的 bundle identifier,如下:
1 | { Filter = { Bundles = ( "com.apple.springboard","imlifengfeng.InfoGetter"); }; } |
最后就可以安装插件到手机了,cd 进入项目目录,依次执行三个命令:make、make package、make install即可将插件安装到手机。
如果在安装(make install)时出现如下错误:
只需要配置一下设备 IP 环境即可,用如下命令行:
1 | export THEOS_DEVICE_IP=192.168.2.61 |
注意将上面 IP 改成你真机的 IP。
安装后在手机桌面是看不到插件的,可以通过 Cydia 查看或卸载:
之后就可以通过我们的测试 APP 进行测试了,测试结果如下:
安装插件前:
安装插件后:
以上就是这个简单插件开发的整个过程。
- 本文章采用 知识共享署名 4.0 国际许可协议 进行许可,完整转载、部分转载、图片转载时均请注明原文链接。