最近对 iOS 逆向很感兴趣,想学习下如何通过逆向app、分析源码、注入动态库的方式来给其它 app 添加一些酷炫的功能。于是我决定先从微信开始,希望通过做笔记的方式,巩固自己学过的知识,以及分享这些知识给其他对此感兴趣的人。
说干就干,逆向工程哪是那么容易的一件事。首先,我们要从一些优秀书籍和一些大神的博客中学习基础知识。有了一定的基础之后,于是我在我的学习地将学习过程写了下来。
首先,看一下实现效果:
打开终端
Terminal 一般 Mac 电脑自带,打开 Terminal 执行后续操作。
安装 theos
theos 是一个越狱开发工具包,它可以生成 iOS app 以及 tweak 等程序的框架,并提供 makefile 来编译、打包和安装。
- 从 Github 下载 theos ,进行如下操作:
export THEOS=/opt/theos
rm -rf $THEOS # 如果之前已经安装过 theos,请先删除,然后下载最新版
sudo git clone --recursive https://github.com/theos/theos.git $THEOS
执行命令后,显示如下:
Cloning into '/opt/theos'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 8802 (delta 4), reused 9 (delta 4), pack-reused 8784
Receiving objects: 100% (8802/8802), 2.20 MiB | 9.00 KiB/s, done.
Resolving deltas: 100% (5467/5467), done.
Submodule 'vendor/dm.pl' (https://github.com/theos/dm.pl.git) registered for path 'vendor/dm.pl'
Submodule 'vendor/include' (https://github.com/theos/headers.git) registered for path 'vendor/include'
Submodule 'vendor/lib' (https://github.com/theos/lib.git) registered for path 'vendor/lib'
Submodule 'vendor/logos' (https://github.com/theos/logos.git) registered for path 'vendor/logos'
Submodule 'vendor/nic' (https://github.com/theos/nic.git) registered for path 'vendor/nic'
Cloning into '/opt/theos/vendor/dm.pl'...
remote: Enumerating objects: 142, done.
remote: Total 142 (delta 0), reused 0 (delta 0), pack-reused 142
Receiving objects: 100% (142/142), 54.20 KiB | 9.00 KiB/s, done.
Resolving deltas: 100% (72/72), done.
...
...
...
Submodule path 'vendor/include/rocketbootstrap/LightMessaging': checked out '496257b11c3e906333797639355db9a43015eb50'
Submodule path 'vendor/lib': checked out 'b1d502cc632ec349f8e2b3df9d7630bad64fd25e'
Submodule path 'vendor/logos': checked out 'a54760ea60acf45fa48267b9fb344c0317d9351c'
Submodule path 'vendor/nic': checked out '794d210f81198c6aef4f0ab8d04bd74ffe149f51'
- 配置 ldid
ldid 是用于对 iOS 可执行文件进行签名的工具,可以在越狱 iOS 中替换 Xcode 自带的签名工具。
下载 ldid ,将其移动到 /opt/theos/bin 目录下,然后设置可执行权限。
# cd <下载ldid的目录>
cd ~/Downloads/
sudo mv ldid /opt/theos/bin
sudo chmod 777 /opt/theos/bin/ldid
- 配置环境变量
使用命令 vi ~/.bash_profile
或者 open -e ~/.bash_profile
,在 .bash_profile 文件的最后加入 (否则每次重启 Terminal 都要重新 export)
export PATH=/opt/theos/bin:$PATH
export THEOS=/opt/theos
保存并退出,使用命令 source ~/.bash_profile
,立即生效。
PS: 也可以使用 iOSOpenDev
iOSOpenDev 集成在 Xcode 中,提供了一些模板,可直接使用 Xcode 进行开发。只是这个工具停止更新,对高版本的 Xcode 不能很好地支持。本人安装遇到了许多问题,通过查阅许多的资料,最后在 Xcode 中显示了该工具。若安装失败,则参考 iOSOpenDev Wiki 或者其它资料。
Tweak
何谓 tweak ?
tweak 定义是:对复杂的系统—通常是电子设备—进行微调或修改来增强其功能。而在 iOS 当中,tweak 是指那些能够增强其它进程功能的 dylib 。可以将 tweak 理解为一个外挂,只不过这个外挂是以动态链接库的方式注入到目标应用当中。我们已经很了解外挂其实就是用来做一些原本的应用无法做到的事情。
创建 tweak
使用 nic.pl 创建 tweak ,若提示无此命令,请根据上述步骤配置环境变量,或者不嫌麻烦使用 /opt/theos/bin/nic.pl ,根据提示选择 iphone/tweak ,接着分别输入:
- 项目名
- 该 deb 包的名字(类似 bundle identifier,此 bundle identifier 与要 hook 的 app 的 bundle identifier 不是同一个)
- 作者/维护者
- tweak 作用对象的 bundle identifier(比如微信为com.tencent.xin)
- tweak 安装完成后需要重启的应用名(比如微信为WeChat)
如下图所示:
完成后会看到四个文件( make 后将生成 .theos , obj 文件夹 ):Makefile, wcodtplugin.plist, control, Tweak.xm。
- Makefile
工程用到的文件、框架、库等信息。该文件过于简单,还需要添加一些信息,如:
指定处理器架构 ARCHS = armv7 arm64
指定 SDK 版本 TARGET = iphone:latest:8.0
导入所需的 framework 等。
修改后的 Makefile 文件如下所示:
ARCHS = armv7 arm64
TARGET = iphone:latest:8.0
THEOS_MAKE_PATH = /opt/theos/makefiles
include $(THEOS_MAKE_PATH)/common.mk
TWEAK_NAME = wcodtplugin
$(TWEAK_NAME)_FILES = $(wildcard src/*.m) src/Tweak.xm
$(TWEAK_NAME)_FRAMEWORKS = UIKit AVFoundation CoreLocation
src/xxa.m_CFLAGS = -fobjc-arc
...
src/xxz.m_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk
after-install::
install.exec "killall -9 WeChat"
- wcodtplugin.plist
该文件中的 Bundles : 指定 bundle 为 tweak 的作用对象,也可添加多个 bundle ,指定多个为 tweak 作用对象。
- control
该 tweak 所需的基本信息 (其实大部分都是创建 tweak 所填写的信息)
Package: com.aple.wcodtplugin
Name: wcodtplugin
Depends: mobilesubstrate
Version: 0.0.1 # 版本号
Architecture: iphoneos-arm
Description: An awesome MobileSubstrate tweak! # 填写项目描述
Maintainer: dyf # 维护者
Author: dyf # 作者
Section: Tweaks
- Tweak.xm
重点文件,用来编写 hook 代码,因为支持 Logos 和 C/C++ 语法,可以让我们不用去写一些 runtime 方法 (必要时候还是要写) ,从而进行 hook 。
PS: .x 文件支持 Logos 语法,.xm 文件支持 Logos 和 C/C++ 语法。
Logos 常用语法
- %hook
指定需要 hook 的类,以%end结尾。
- %orig
在 %hook 内部使用,执行 hook 住的方法原代码。
- %new
在 %hook 内部使用,给 class 添加新方法,与 class_addMethod 相同。
与 Category 中添加方法的区别:Category 为编译时添加,class_addMethod 为动态添加。
warning :添加的方法需要在 @interface 中进行声明。
- %c
获取一个类,等同于 objc_getClass 、NSClassFromString 。
- MSHookIvar<id>(self, "m_tableViewMgr")
在 %hook 内部使用,获取一个类的私有成员变量。
%hook、%log、%orig 等都是 mobilesubstrate 的 MobileHooker 模块提供的宏,除此之外还有 %group %init %ctor 等,其实也就是把 method swizzling 相关的方法封装成了各种宏标记。
编写 Tweak.xm
在熟悉各种语法之后,可以进行编写代码了,其中 MMUIViewController 为微信的基础的 ViewController 。我们通过 hook viewDidApper: 来进行 Hello World! 弹窗。
编写一个 hook 接口声明头文件 HookInterfaceStatment.h
,代码如下:
@interface MMUIViewController : UIViewController
- (void)startLoadingBlocked;
- (void)startLoadingNonBlock;
- (void)startLoadingWithText:(NSString *)text;
- (void)stopLoading;
- (void)stopLoadingWithFailText:(NSString *)text;
- (void)stopLoadingWithOKText:(NSString *)text;
// Added method.
- (void)helloWorld;
@end
编写 Tweak.xm ,代码如下:
#import "HookInterfaceStatment.h"
%hook MMUIViewController
- (void)viewWillAppear:(_Bool)arg1 {
%orig;
[self helloWorld];
}
%new
- (void)helloWorld {
UIAlertController *alertController = ({
UIAlertController *_alertController = [UIAlertController alertControllerWithTitle:@"Hello World!" message:nil preferredStyle:UIAlertControllerStyleAlert];
[_alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {}]];
[_alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {}]];
_alertController;
});
[self presentViewController:alertController animated:YES completion:NULL];
}
%end
编译
使用 make
进行编译,若想重新编译,则先 make clean
。make 编译完成后,在当前文件夹下面将生成两个文件夹: .theos 与 obj ,其中编译完成的动态库就在 .thoes/obj/debug 的下面,与工程名相同。
问题描述和解决方法
- 问题1
Makefile:6: theos/makefiles/common.mk: Not a directory
Makefile:25: /tweak.mk: No such file or directory
make: *** No rule to make target `/tweak.mk'. Stop.
解决办法:首先确保安装并配置了 theos ,其次修改 Makefile 文件,在 $(THEOS)/makefiles
代码行上方定义 THEOS_MAKE_PATH = /opt/theos/makefiles
,将 $(THEOS)/makefiles
替换成 $(THEOS_MAKE_PATH)
。
- 问题2
bash: ldid: command not found
make[2]: *** [/Users/xxx/Desktop/wcodtplugin/.theos/obj/debug/wcodtplugin.dylib] Error 6
rm /Users/xxx/Desktop/wcodtplugin/.theos/obj/debug/wcodtplugin.dylib.47ba6b93.unsigned
make[1]: *** [internal-library-all_] Error 2
make: *** [wcodtplugin.all.tweak.variables] Error 2
解决办法:按照配置 ldid 步骤执行,重新编译。
- 问题3
xcrun: error: SDK "iphoneos" cannot be located
xcrun: error: SDK "iphoneos" cannot be located
==> Error: You do not have any SDKs in /Library/Developer/CommandLineTools/Platforms/iPhoneOS.platform/Developer/SDKs or /opt/theos/sdks.
make: *** [before-all] Error 1
解决办法:在终端执行命令 sudo xcode-select --switch /Applications/Xcode.app
即可。
- 问题4 (代码报错)
> Making all for tweak wcodtplugin…
==> Preprocessing Tweak.xm…
==> Compiling Tweak.xm (armv7)…
Tweak.xm:5:26: error: expected ';' after expression
... UIAlertController *_alertController = [UIAlertController alertControllerWithTitle...
^
;
1 error generated.
make[3]: *** [/Users/xxx/Desktop/wcodtplugin/.theos/obj/debug/armv7/Tweak.xm.8aee9f68.o] Error 1
rm /Users/xxx/Desktop/wcodtplugin/.theos/obj/debug/armv7/Tweak.xm.mm
make[2]: *** [/Users/xxx/Desktop/wcodtplugin/.theos/obj/debug/armv7/wcodtplugin.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [wcodtplugin.tweak.variables] Error 2
解决办法:根据错误提示,找到报错的代码进行修改,重新编译。
- 问题5 (打包出错)
> Making all for tweak wcodtplugin…
make[2]: Nothing to be done for `internal-library-compile'.
> Making stage for tweak wcodtplugin…
Can't locate IO/Compress/Lzma.pm in @INC (you may need to install the IO::Compress::Lzma module) (@INC contains: /usr/local/Cellar/perl/5.26.2/lib/perl5/site_perl/5.26.2/darwin-thread-multi-2level /usr/local/Cellar/perl/5.26.2/lib/perl5/site_perl/5.26.2 /usr/local/Cellar/perl/5.26.2/lib/perl5/5.26.2/darwin-thread-multi-2level /usr/local/Cellar/perl/5.26.2/lib/perl5/5.26.2 /usr/local/lib/perl5/site_perl/5.26.2/darwin-thread-multi-2level /usr/local/lib/perl5/site_perl/5.26.2) at /opt/theos/bin/dm.pl line 12.
BEGIN failed--compilation aborted at /opt/theos/bin/dm.pl line 12.
make: *** [internal-package] Error 2
解决办法:
1. /opt/theos/vendor/dm.pl/dm.pl
# 注释掉第12、13行
# use IO::Compress::Lzma;
# use IO::Compress::Xz;
2. /opt/theos/makefiles/package/deb.mk
# 第6行 lzma 改为 gzip
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= gzip
最后重新 make package ,成功了。