这个系列,是很早听 MJ 课程时的整理,现在分享出来。 其中一些参考资料有些有引用,有些可能忘记添加了,如果有引用部分资料,可以联系我。
iOS 逆向(一)环境搭建
iOS 逆向(二)Cycript
iOS 逆向(三)逆向工具
iOS 逆向(四)脱壳
审核中 iOS 逆向(五)Theos工具
iOS 逆向(六)动态调试
iOS 逆向(七)重签名
一、工程准备
1.1 安装签名工具
$ brew install ldid
1.2 修改环境变量
- 编辑用户的配置文件```bash $ vim ~/.bash_profile
- 在`.bash_profile`文件后加入变量,配置变量可参考[macOS环境变量配置](https://wenghengcong.com/posts/349bdc7c/)```bash
# THEOS
export THEOS=~/theos
export PATH=$PATH:$THEOS/bin
- 让
.bash_profile
配置的环境变量立即生效,或者重启终端```bash $ source ~/.bash_profile
##1.3 下载Theos
建议在上述配置的`$THEOS`目录下载代码:
```bash
$ git clone --recursive https://github.com/theos/theos.git $THEOS
二、项目开发-喜马拉雅去广告
开发一个tweak项目的流程大致如下:
- 确认开发需求:比如去广告、加会员,破解加锁功能等等。
- 根据需求,确认需要修改的方案。
- 比如去广告需要确定视图关系,对视图关系进行分析。
- 加会员、破解功能则需要分析函数调用、逻辑关系,猜测实现,最后尝试hook逻辑。
-
项目开发
1. Clutch、dumpdecrypted破壳;
- 2. class dump导出头文件;
3. Reveal、Cycript分析界面;
- 4. 分析类关系、函数调用逻辑,尝试进行hook;
- 6. 重签名、发布;5. 调试、编译、打包、安装;
我们在这里,将会实施前5步,重签名会在后面讲述。
2.1 新建Tweak项目
我们今天破解的是喜马拉雅FM APP。
需求是:去广告。
cd到存放项目代码的目录,此处:
$ cd ~/Desktop/crackApp/ting/
- Project Name:
- 必选项
- 此处我们工程的名字是tingtweak;
- Package Name
- 包名,一般规则即可,也可以随便
- 此处,我们com.luci.tingtweak
- Author/Maintainer Name
- 作者,当然是Wenghengcong
- 直接敲回车默认Mac用户名
- [iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]
- 我们要tweak App的bundle id,针对喜马拉雅tweak:com.gemd.iting
- 可以使用Cycript或者MJAppTool来查看对应的App的Bundle Identifier;
- [iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]
- 直接回车
2.2 项目文件结构
2.2.1 MakeFile
MakeFile,指定工程用到的文件、框架、库等信息,将整个过程自动化。
我们看MakeFile文件:
include $(THEOS)/makefiles/common.mk
# tweak的名字,即用Theos创建工程时指定的“Project Name”,跟control文件中的“Name”字段对应,不要更改。
TWEAK_NAME = tingtweak
# tweak包含的源文件(不包括头文件),多个文件间以空格分隔
tingtweak_FILES = Tweak.xm
include $(THEOS_MAKE_PATH)/tweak.mk
#在tweak安装之后杀掉SpringBoard进程,好让CydiaSubstrate在进程启动时加载对应的dylib
after-install::
install.exec "killall -9 SpringBoard"
在前面加入环境变量,写清楚通过哪个IP和端口访问手机:
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_IP THEOS_DEVICE_PORT=10010
...include $(THEOS)/makefiles/common.mk
此处通过本机地址,及10010端口访问手机,参考逆向(一)环境搭建通过USB连接手机一节。
如果不希望为每个项目的MakeFile都export端口,可以添加到用户配置文件中,同上面添加$THEOS
变量类似,source生效:
# THEOS
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_IP THEOS_DEVICE_PORT=10010
export THEOS=~/theos
export PATH=$PATH:$THEOS/bin
- Tweak默认编码方式是MRC 如果需要ARC的话 在MakeFile中插入
//其他项目,请修改tingtweak为项目名
tingtweak_CFLAGS = -fobjc-arc
2.2.2 control
主要是项目有关的信息,比如项目的名称、版本、开发者等信息。
Package: com.luci.tingtweak
Name: tingtweak
Depends: mobilesubstrate
Version: 0.0.1
Architecture: iphoneos-arm
Description: An awesome MobileSubstrate tweak!
Maintainer: Wenghengcong
Author: Wenghengcong
Section: Tweaks
2.2.3 tingtweak.plist
主要是设置需要被逆向的app的bundle Id,如果需要逆向多个APP,就在Bundles数组中添加其bundle Id:
{ Filter = { Bundles = ( "com.gemd.iting" ); }; }
2.2.4 xm文件
xm就是hook代码文件。
2.3 脱壳、导出头文件
-
Clutch -d 破壳,始终无法破壳,则换采用dumpdecrypted工具
-
先使用MJAppTool列出应用列表,获取喜马拉雅的app路径,得到:> /private/var/mobile/Containers/Bundle/Application/77CC1D65-FAD8-4E87-AA39-88756270F899/ting.app/
-
dumpdecrypted破壳:
-
破壳,执行命令:> 5s:~ root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/mobile/Containers/Bundle/Application/77CC1D65-FAD8-4E87-AA39-88756270F899/ting.app/ting
-
在
/var/root
找到对应的破壳文件,拷贝到电脑
-
-
class dump导出头文件,执行命令:> class-dump -H ting -o Headers
2.4 分析界面
收听界面,展示了如下广告:
通过Reveal分析,基本可以判定广告视图类为:XMSoundPatchImageView
可以通过Cycript验证上面的猜想:
//ps -A查找到喜马拉雅进程id 893
//进入cy环境调试
5s:~ root#cycript -p 893
cy# @import mjcript
cy# MJFrontVc()
#"<XMPlayingViewController: 0x12eca0a00>"
//1. 从Reveal获取到猜测的广告视图的地址,打印其子视图
cy# #0x130524080.recursiveDescription().toString()
`<XMSoundPatchImageView: 0x130524080; frame = (0 105; 320 223); layer = <CALayer: 0x12ff8c8b0>>
| <UIView: 0x130524a60; frame = (0 0; 320 223); layer = <CALayer: 0x1302a6fe0>>
| | <UIImageView: 0x130524220; frame = (56 15; 208 208); clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x1301c7950>; layer = <CALayer: 0x130524050>>
| | | <XMAdMarkView: 0x130524880; baseClass = UIImageView; frame = (0 196; 21.6 12); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x13026faf0>>
| <UIButton: 0x1305245f0; frame = (249 0; 30 30); opaque = NO; layer = <CALayer: 0x13027e6e0>>
| | <UIImageView: 0x1300e0eb0; frame = (0 0; 30 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1303f17c0>>`
//2. 根据猜测,真正的广告视图是UIImageView,从父视图移除
cy# #0x130524220.removeFromSuperview()
通过上面移除,我们从手机看到,广告没有了。
猜想是对的。
2.5 编写代码
下面,我们就要开始针对XMSoundPatchImageView来做一点事情了。
先从之前导出的头文件里看看XMSoundPatchImageView类:
#import <UIKit/UIView.h>
#import "CAAnimationDelegate-Protocol.h"
#import "XMSoundPatchImageViewProtocol-Protocol.h"
@class NSString, UIButton, UIImageView, XMADAudioItem, XMAdMarkView;
@interface XMSoundPatchImageView : UIView <CAAnimationDelegate, XMSoundPatchImageViewProtocol>
{
_Bool _hideToTop;
_Bool _onShow;
unsigned long long _animationType;
CDUnknownBlockType _soundPatchImageViewWillClose;
UIButton *_adHidButton;
UIImageView *_adImageView;
UIView *_shadow;
XMAdMarkView *_adMark;
}
@property(retain, nonatomic) XMAdMarkView *adMark; // @synthesize adMark=_adMark;
@property(nonatomic) _Bool onShow; // @synthesize onShow=_onShow;
@property(retain, nonatomic) UIView *shadow; // @synthesize shadow=_shadow;
@property(retain, nonatomic) UIImageView *adImageView; // @synthesize adImageView=_adImageView;
@property(retain, nonatomic) UIButton *adHidButton; // @synthesize adHidButton=_adHidButton;
@property(copy, nonatomic) CDUnknownBlockType soundPatchImageViewWillClose; // @synthesize soundPatchImageViewWillClose=_soundPatchImageViewWillClose;
@property(nonatomic) _Bool hideToTop; // @synthesize hideToTop=_hideToTop;
@property(nonatomic) unsigned long long animationType; // @synthesize animationType=_animationType;
- (void).cxx_destruct;
- (void)onHidButtonClicked:(id)arg1;
- (void)onAdImageViewTapped:(id)arg1;
@property(readonly, nonatomic) XMADAudioItem *audioItem;
......
- (void)initUI;
- (void)cleanWithAnimation:(_Bool)arg1;
- (void)clean;
- (id)initWithFrame:(struct CGRect)arg1;
// Remaining properties
@property(readonly, copy) NSString *debugDescription;
@property(readonly, copy) NSString *description;
@property(readonly) unsigned long long hash;
@property(readonly) Class superclass;
@end
从上面的头文件,我们发现的信息不多,但是我们可以直接hook掉视图,将该视图始终置为nil。
在Tweak.xm文件中:
%hook XMSoundPatchImageView
- (id)initWithFrame:(struct CGRect)arg1
{
return nil;
}
%end
2.6 编译、打包、安装、卸载
在电脑Tweak项目目录下:
2.6.1 编译
make
2.6.2 打包
打包成deb:
make package
默认make package打包debug版本,如果要打包release版本:
make package debug=0
- 版本号,可以再
control
文件中指定; - debug包会比release版本大,主要包含了一些调试信息;
- make package 包含了make指令的动作。
2.6.3 安装
默认会重启SpringBoard
make install
流程如下:
安装完之后,会重启Springboard,再次打开喜马拉雅,惊喜的是,广告没了!
2.6.4 卸载
- 直接去删除对应的动态库及plist文件。
/Library/MobileSubstrate/DynamicLibraries
- Cydia直接卸载
2.7 错误
2.7.1 - make package
$ make package
Can't locate IO/Compress/Lzma.pm in @INC (you may need to install the
IO::Compress::Lzma module) (@INC contains: /Library/Perl/5.18/darwin-
thread-multi-2level /Library/Perl/5.18 /Network/Library/Perl/5.18/darwin-
thread-multi-2level /Network/Library/Perl/5.18 /Library/Perl/Updates/5.18.2
/System/Library/Perl/5.18/darwin-thread-multi-2level
/System/Library/Perl/5.18 /System/Library/Perl/Extras/5.18/darwin-thread-
multi-2level /System/Library/Perl/Extras/5.18 .) at
/Users/mj/theos/bin/dm.pl line 12.
BEGIN failed--compilation aborted at /Users/mj/theos/bin/dm.pl line 12.
make: *** [internal-package] Error 2
是因为打包压缩方式有问题,改成gzip压缩就行。
- 修改dm.pl文件,用#号注释下面两句```bash THEOS/vendor/dm.pl/dm.pl #use IO::Compress::Lzma; #use IO::Compress::Xz;
- 修改deb.mk文件第6行的压缩方式gzip```bash
$ vim $THEOS/makefiles/package/deb.mk
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= gzip
2.7.2 - make的错误
1)
$ make
Error: You do not have an SDK in
/Library/Developer/CommandLineTools/Platforms/iPhoneOS.platform/Developer/S
DKs
是因为多个Xcode(安装多个Xcode),需要指定Xcode。
$ sudo xcode-select -s /Applications/Xcode.app/Contents/Developer/
2)
$ make
> Making all for tweak xxx...
make[2]: Nothing to be done for `internal-library-compile'.
之前编译过有缓存,需要clean。
$ make clean
$ make
三、更近一步-微信加功能
5s:~ root# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/mobile/Containers/Bundle/Application/4E7CFE17-8B9E-4B55-84B1-14E70653EFC3/WeChat.app/WeChat
3.1 多个tweak文件
假如新建Cell文件夹存放对应的hook代码:
那么在MakeFile中指定该文件:
tweakwechat_FILES = Tweak.xm Cell/MMTableViewCell.xm
需要注意的是:
- 每个文件以空格隔开
- 假如以通配符配置如下:```makefile tweakwechat_FILES = Tweak.xm Cell/*.xm
会报错:```bash
clang: error: no such file or directory: '/Users/wenghengcong/Desktop/crackApp/wechat/tweakwechat/.theos/obj/debug/armv7/Cell/MMTableViewCell.xm.mm'
clang: error: no input files
make[3]: *** [/Users/wenghengcong/Desktop/crackApp/wechat/tweakwechat/.theos/obj/debug/armv7/Cell/*.xm.298cc4f9.o] Error 1
rm /Users/wenghengcong/Desktop/crackApp/wechat/tweakwechat/.theos/obj/debug/armv7/Tweak.xm.mm /Users/wenghengcong/Desktop/crackApp/wechat/tweakwechat/.theos/obj/debug/armv7/Cell/*.xm.mm
make[2]: *** [/Users/wenghengcong/Desktop/crackApp/wechat/tweakwechat/.theos/obj/debug/armv7/tweakwechat.dylib] Error 2
make[1]: *** [internal-library-all_] Error 2
make: *** [tweakwechat.all.tweak.variables] Error 2
3.2 资源文件
资源文件存放,需要在tweak项目中新进layout
文件夹用于存放。
3.2.1 layout
layout
相当于iOS 系统根目录,在layout路劲中创建的文件路径,在打包之后,都会映射到iOS系统中。
在iOS中的映射:
所以,假如需要存放资源,规划好存放路径。
3.2.2 读取
//路径,在文件头部定义个宏
#define BFFile(path) @"/Library/PreferenceLoader/Preferences/BFWeChat/" #path
cell.imageView.image = [UIImage imageWithContentsOfFile:BFFile(exit.png)];
3.3 宏
宏定义语法和之前一致:
#define BFUserDefaults [NSUserDefaults standardUserDefaults]
#define BFAutoKey @"bf_auto_get_key"
3.4 安装脚本
将以上打包等步骤编写为脚本:
# bftweak-make.sh
#!/bin/bash
#不包含make命令,因为make package包含了make指令
make clean && make package && make install
安装成功之后:
五、Theos
环境变量:iphonedevwiki.net/index.php/T…
5.1 theos-tweak实现过程
- 编写Tweak代码
- make:编写Tweak代码为动态库(*.dylib)
- make package:将dylib打包为deb文件
- make install:将deb文件传送到手机上,通过Cydia安装deb
- 插件将会安装在
/Library/MobileSubstrate/DynamicLibraries
文件夹中- *.dylib:编译后的Tweak代码
- *.plist:存放着需要hook的App Id
- 当打开APP时
- Cydia Substrate(Cydia已自动安装的插件)会让APP去加载对应的dylib
- 修改APP内存中的代码逻辑,去执行dylib中的函数代码
5.2 Logos语法
iphonedevwiki.net/index.php/L…
- %hook %end:hook 一个类的开始与结束
- %log:打印方法调用详情
- 通过Xcode -> Window -> Devices and Simulators 查看日志
- HBDebugLog:和NSLog类似
- %new:添加一个新方法
- %c(className):生成一个Class对象,比如%c(NSObjct) ,类似NSStringFromClass()、objc_getClass()
- %orig:函数原来的代码逻辑
- %ctor:在加载动态库时调用
- %dtor:在程序退出时调用
- logify.pl xm:将一个头文件快速转换成一家包含打印信息的xm文件```bash logify.pl xx.h > xx.xm
## 5.3 logify.pl
```ba
logify.pl xx.h > xx.xm
logify.pl生成的xm文件,很多时候编译不通过,需要进行一些处理
- 删掉__weak
- 删掉inout
- 删掉协议
- 或者声明一下协议信息@protocol XXDelegate
- 删除- (void).cxx_destruct { %log; %orig; }
- 删除 HBLogDebug(@" = 0x%x", (unsigned int)r);
- 将所有不认识的类,均替换成id
- 比如instancetype 直接替换id
- 替换类名为void,比如**XXPerson **_ 替换为 **void **_
- 或者声明一下类信息 @class XXPerson
六、其他一些小tip
- SpringBoard的目录:/System/Library/CoreService/SpringBoard.app
- 未脱壳的APP也支持tweak,因为tweak是在内存中以动态库的形式实现的,并没有修改
.app
包中的可执行文件。 - tweak效果是否一直有效,只要tweak用到的代码没有修改过,就一直有效。假如更新到新版本,用到的代码有修改,就会失效;
- 未越狱手机不支持tweak;
- 当前已经逐步对Swift项目进行支持;
- 对游戏项目进行tweak难度大,主要因为游戏大多由C/C++/C#编写的,一般也会进行代码混淆;