使用Theos逆向項目
一、Theos是什么?
Theos是一套跨平臺的開發工具,用于在不使用Xcode的情況下開發、部署iOS插件,大多數插件開發人員都使用Theos。
-
Theos工具套件包含一些重要組件:
配置好Theos后,就可以使用Theos中的
tweak模板
,快速創建逆向工程,并使用Logos語法
修改別人App的一些行為 ,例如:微信自動搶紅包、騰訊視頻去廣告等等,最后使用make構建系統
編譯、打包、分發。Theos環境變量和目錄:http://iphonedevwiki.net/index.php/Theos
二、Theos逆向的原理
-
使用tweak模板把咱們寫的逆向代碼安裝到手機的原理:首先會把咱們編寫的逆向代碼,編譯成
dylib動態庫
,然后與plist文件
一起,打包成deb文件,然后通過手機的Cydia,安裝到手機上 ,如下圖所示:
tweak模板 -
改變App行為的原理:手機打開要逆向的目標App后,會在內存中載入這個App的可執行文件,此時,Cydia會檢測
plist文件
中的BundleID是否和目標App的一致,如果一致,就會把咱們寫的dylib動態庫
載入內存,在調用目標App的代碼時,會把消息轉發到咱們寫的動態庫中,實現hook,如下圖所說:
改變App行為的原理.png
三、如何配置Theos?
1. 安裝簽名工具ldid
- 先確保安裝了brew,安裝命令如下:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- 利用brew安裝ldid,安裝命令如下:
$ brew install ldid
2. 修改環境變量
- 編輯用戶的配置文件:
$ vim ~/.bash_profile
- 在
.bash_profile
文件后面加入以下兩行:
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
- 讓
.bash_profile
配置的環境變量立即生效,命令如下:
$ source ~/.bash_profile
3. 下載Theos
- 建議在~/.theos目錄下載代碼,也就是剛才配置的環境變量$THEOS,命令如下:
$ git clone --recursive https://github.com/theos/theos.git $THEOS
4. 新建tweak項目
- cd到一個存放項目代碼的文件夾,例如桌面:
$ cd ~/Desktop
$ nic.pl
-
選擇模板[10.]iphone/tweak,如下圖所示:
image.png -
填寫項目信息
-
Project Name:
項目名稱,可以隨便寫,例如:tweak_wechat -
Package Name:
項目ID,可以隨便寫,例如:com.sp.wechat -
Author/Maintainer Name:
作者,直接敲回車,默認就是Mac上的當前用戶名 -
MobileSubstrate Bundle filter:
需要逆向的App的BundleID,可以通過Cycript查看,例如:微信的BundleID就是com.tencent.wechat -
List of applications to terminate upon installcation
,直接敲回車,默認即可 - 之后就會生成一個文件夾,里面包含:
control、Makefile、Tweak.x、xxx.plist
等文件,這些文件的具體作用,后續會說到
-
5. 編輯Makefile文件
-
在Makefile中加入環境變量,寫清楚通過哪個IP和端口訪問手機,如下所示,由于會把接口轉發到本地的10010端口,所以這里可以這樣寫:
- THOS_DEVICE_IP 手機IP
- THOS_DEVICE_PORT 要訪問的端口號
export THEOS_DEVICE_IP=127.0.0.1 export THEOS_DEVICE_PORT=10010
如果不想每個項目的Makefile都編寫IP和端口環境變量,也可以添加到用戶配置文件中,如下所示,編輯完成后,記得使用
source ~/.bash_profile
命令,讓配置生效
$ vim ~/.bash_profile
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_PORT=10010
$ source ~/.bash_profile
6. 編寫逆向代碼
- 打開Tweak.x文件,編寫自己的逆向代碼,如下所示,
%hook、%end
屬于Logos語法
%hook FindFriendEntryViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return %orig + 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSInteger totalSection = [self numberOfSectionsInTableView: tableView];
if (section == totalSection - 1){
return 2;
}else{
return %orig;
}
}
%end
7. 編譯-打包-安裝
- 編譯成dylib動態庫
$ make
- 把動態庫打包成deb文件
$ make package
- 安裝到手機
$ make install
8. 配置好Theos后,Theos的使用方法
配置好Theos后,Theos的使用只需三步:
在命令行中輸入nic.pl,選擇tweak模板,填寫項目信息
在Tweak.x中編寫逆向代碼
在命令行中輸入make編譯->make package打包->make install安裝到手機
建議把Makefile中的IP和端口環境變量,都加到
~/bash_profile
中,這樣以后新建項目,都不用配置環境變量了
四、配置Theos過程中可能遇到的問題
-
make package的錯誤,如下所示:
make package的錯誤.png
解決辦法:是因為打包壓縮方式有問題,改成gzip壓縮就可以
- 修改dm.pl文件,用#號注釋掉下面兩句:
$ vim $THEOS/vendor/dm.pl/dm.pl
#use IO::Compress::Lzma;
#use IO::Compress::Xz;
- 修改deb.mk文件第6行的壓縮方式為gzip,如下所示:
$ vim $THEOS/makefiles/package/deb.mk
_THEOS_PLATFORM_DPKG_DEB_COMPRESSION ?= gzip
-
make出現錯誤,如下所示:
image.png
-
解決辦法:是因為安裝了多個Xcode,導致的路徑錯誤,需要指定一下Xcode
$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
-
make出現以下錯誤:
image.png
-
解決辦法:因為之前已經編譯過,有緩存導致的,clean一下即可
$ make clean
五、Logos語法
-
- 寫逆向代碼時常用的Logos語法
%hook、%end
:hook一個類的開始和結束,中間包括的所有方法,默認是hook狀態-
%log
:在方法中,加入此關鍵詞,就會自動打印方法名、方法參數,會在系統日志中顯示出來,在Xcode->Window->Devices And Simulators->Open Console->選擇自己的手機
,即可查看,如下圖所示:
image.png
image.png HBDebugLog
:跟NSLog類似,一般用來輸出返回值的,會自動生成,不用管%new
:添加一個新的方法,寫在某個方法的上面,代表這個方法是新增的,而不是hook的%c(className)
:生成一個Class對象,例如:%c(NSObject),就相當于NSClassFromString()、object_getClass()%org
:方法原來的代碼邏輯,在方法里加上此關鍵詞,就代表實現了此方法的原來的代碼邏輯%ctor
:構造方法,加載咱們的動態庫時自動調用%dtor
:析構方法,在程序退出時自動調用logify.pl
:可以將一個頭文件快速轉換成已經包含打印信息的xm文件,命令如下:
logify.pl xx.h > xx.xm
-
- 使用logify.pl生成的xm文件,很多時候編譯是通不過的,需要進行以下處理:
- 刪掉
__weak
- 刪掉
inout
- 刪掉協議或者聲明協議,例如:
@protocol BaseMsgContentDelgate;
- 聲明類名,例如:
@class MMRichTextCoverView;
- 刪掉以.開頭的方法,例如:
- (void).cxx_destruct { %log; %orig; }
- 將
HBLogDebug(@" = 0x%x", (unsigned int)r);
刪除或者是替換為HBLogDebug(@" = 0x%@", r);
- 當參數里面帶上協議時,需要把協議刪掉,例如:
- (void)setM_backgroundThreadDelegate:( id <BaseMsgContentInBackgroundThreadDelgate> )m_backgroundThreadDelegate { %log; %orig; }
,把<BaseMsgContentInBackgroundThreadDelgate>刪掉即可。
六、tweak工程的一些技巧
- 多文件的時候,建議新建一個
src
文件夾,用來存放xm代碼
,這樣做的話,就需要在Makefile文件
中,修改WeChatTest_FILES = $(wildcard src/*.xm)
,把參數改成通配符;如果有多個類型的文件,就繼續追加即可,例如:
WeChatTest_FILES = $(wildcard src/*.xm) $(wildcard src/*.x)
- 多文件的時候,建議新建一個
- 如果工程里面需要額外的圖片的話,可以把圖片放在項目的layout文件夾中,
layout
相當于手機的Device根路徑
;當把圖片放在/layout/Library/Caches/項目名
下面時,插件安裝到手機后,圖片會自動存放在手機的/Device/Library/Caches/項目名
路徑中
- 如果工程里面需要額外的圖片的話,可以把圖片放在項目的layout文件夾中,
七、給微信增加自動搶紅包功能
- 首先分析需求,在微信的發現界面,增加兩行UI,自動搶紅包和退出微信,并實現功能(這里先繪制UI,功能實現在動態調試里面講)
- 使用Reveal觀察微信的發現界面,拿到發現界面的類名
FindFriendEntryViewController
- 使用Reveal觀察微信的發現界面,拿到發現界面的類名
- 對微信脫殼,并且用class-dump導出微信的頭文件,找到
FindFriendEntryViewController.h
文件,認真分析,發現里面實現了tableView的幾個代理方法:
FindFriendEntryViewController文件
- 對微信脫殼,并且用class-dump導出微信的頭文件,找到
-
nic.pl
選擇tweak模板,填寫項目信息創建tweak項目,在Tweak.x
中編寫自己的逆向代碼,逆向代碼主要還是OC代碼,部分關鍵詞用到了Logos語法,例如:%hook %end
代表替換微信中這些方法的實現;%new
代表這個方法是新增的;%org
代表這個方法的原有實現。如下所示:
-
#define SP_Defaults [NSUserDefaults standardUserDefaults]
#define SP_AutoKey @"sp_auto_key"
#define SP_File(path) @"/Library/PreferenceLoader/Preferences/SP_WeChat/" #path
@interface FindFriendEntryViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
@end
%hook FindFriendEntryViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return %orig + 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSInteger totalSection = [self numberOfSectionsInTableView: tableView];
if (section == totalSection - 1){
return 2;
}else{
return %orig;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSInteger totalSection = [self numberOfSectionsInTableView: tableView];
if ([indexPath section] != totalSection - 1){
return %orig;
}
NSString *cellID = ([indexPath row] == 0) ? @"sp_autoCellID" : @"sp_exitWXID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
cell.backgroundColor = [UIColor whiteColor];
cell.imageView.image = [UIImage imageWithContentsOfFile:SP_File(skull.png)];
}
if ([indexPath row] == 0){
//搶紅包
cell.textLabel.text = @"自動搶紅包";
UISwitch *switchView = [[UISwitch alloc] init];
switchView.on = [SP_Defaults boolForKey:SP_AutoKey];
cell.accessoryView = switchView;
[switchView addTarget:self action:@selector(sp_autoRed:) forControlEvents:UIControlEventValueChanged];
}else if ([indexPath row] == 1){
//退出微信
cell.textLabel.text = @"退出微信";
}
return cell;
}
- (double)tableView:(id)tableView heightForRowAtIndexPath:(id)indexPath{
if ([indexPath section] != [self numberOfSectionsInTableView:tableView] - 1) {
return %orig;
}
return 56;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([indexPath section] != [self numberOfSectionsInTableView:tableView] - 1) {
%orig;
return;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([indexPath row] == 0){
//自動搶紅包
}else if ([indexPath row] == 1){
// 終止進程
exit(0);
// abort();
}
}
%new
- (void)sp_autoRed:(UISwitch *)switchView{
[SP_Defaults setBool:switchView.on forKey:SP_AutoKey];
[SP_Defaults synchronize];
}
- 編譯、打包、安裝到手機,在手機的微信中,查看修改的成果
$ cd到tweak項目的目錄下
$ make clean && make page debug=0 && make install
- 如果想卸載插件,可以在Cydia的【已安裝】里找到咱們寫的插件,點擊卸載即可。(或者在手機的
Device/Libiary/MobileSubstrate/DynamicLibiaries
中找到咱們自己寫的 plist、dylib文件,刪除即可)
- 如果想卸載插件,可以在Cydia的【已安裝】里找到咱們寫的插件,點擊卸載即可。(或者在手機的
八、逆向工程總結
- 使用Theos的tweak模板,創建逆向工程之前,我們需要先對要逆向的App,進行界面分析和代碼分析,找到類名、方法名、成員變量等信息后,在用Logos語法和OC語法編寫我們的逆向代碼
- 界面分析,建議
Reveal
和Cycripy
一起配合使用,用Reveal
查看界面,找到內存地址,然后用Cycripy
做進一步的分析,例如:找到某個視圖的下一個響應者,#0x16166e2b0.nextResponder
- 界面分析,建議
- 代碼分析,脫殼后使用class-dump工具導出頭文件,用界面分析得到的類名,找到這個類的方法名、成員變量等信息,然后用我們開發時一些經驗進行分析