使用Theos逆向項(xiàng)目
一浸须、Theos是什么?
Theos是一套跨平臺(tái)的開(kāi)發(fā)工具琉闪,用于在不使用Xcode的情況下開(kāi)發(fā)迹炼、部署iOS插件,大多數(shù)插件開(kāi)發(fā)人員都使用Theos颠毙。
-
Theos工具套件包含一些重要組件:
NIC組件斯入,是一套項(xiàng)目模板系統(tǒng),提供了各式各樣的模板蛀蜜,用這些模板可以快速開(kāi)始項(xiàng)目
Make構(gòu)建系統(tǒng)刻两,由GNU Make驅(qū)動(dòng)的強(qiáng)大構(gòu)建系統(tǒng),能夠直接創(chuàng)建.deb軟件包滴某,并在Cydia中分發(fā)
Logos指令庫(kù)磅摹,提供了逆向的語(yǔ)法,允許使用一組預(yù)處理指令實(shí)現(xiàn)Hook
配置好Theos后霎奢,就可以使用Theos中的
tweak模板
户誓,快速創(chuàng)建逆向工程,并使用Logos語(yǔ)法
修改別人App的一些行為 幕侠,例如:微信自動(dòng)搶紅包帝美、騰訊視頻去廣告等等,最后使用make構(gòu)建系統(tǒng)
編譯晤硕、打包悼潭、分發(fā)庇忌。Theos目錄結(jié)構(gòu):https://github.com/theos/theos/wiki/Structure
Theos環(huán)境變量和目錄:http://iphonedevwiki.net/index.php/Theos
二、Theos逆向的原理
-
使用tweak模板把咱們寫(xiě)的逆向代碼安裝到手機(jī)的原理:首先會(huì)把咱們編寫(xiě)的逆向代碼女责,編譯成
dylib動(dòng)態(tài)庫(kù)
漆枚,然后與plist文件
一起,打包成deb文件抵知,然后通過(guò)手機(jī)的Cydia墙基,安裝到手機(jī)上 ,如下圖所示:
-
改變App行為的原理:手機(jī)打開(kāi)要逆向的目標(biāo)App后刷喜,會(huì)在內(nèi)存中載入這個(gè)App的可執(zhí)行文件残制,此時(shí),Cydia會(huì)檢測(cè)
plist文件
中的BundleID是否和目標(biāo)App的一致掖疮,如果一致初茶,就會(huì)把咱們寫(xiě)的dylib動(dòng)態(tài)庫(kù)
載入內(nèi)存,在調(diào)用目標(biāo)App的代碼時(shí)浊闪,會(huì)把消息轉(zhuǎn)發(fā)到咱們寫(xiě)的動(dòng)態(tài)庫(kù)中恼布,實(shí)現(xiàn)hook,如下圖所說(shuō):
三搁宾、如何配置Theos折汞?
1. 安裝簽名工具ldid
- 先確保安裝了brew,安裝命令如下:
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- 利用brew安裝ldid盖腿,安裝命令如下:
$ brew install ldid
2. 修改環(huán)境變量
- 編輯用戶的配置文件:
$ vim ~/.bash_profile
- 在
.bash_profile
文件后面加入以下兩行:
export THEOS=~/theos
export PATH=$THEOS/bin:$PATH
- 讓
.bash_profile
配置的環(huán)境變量立即生效爽待,命令如下:
$ source ~/.bash_profile
3. 下載Theos
- 建議在~/.theos目錄下載代碼,也就是剛才配置的環(huán)境變量$THEOS翩腐,命令如下:
$ git clone --recursive https://github.com/theos/theos.git $THEOS
4. 新建tweak項(xiàng)目
- cd到一個(gè)存放項(xiàng)目代碼的文件夾鸟款,例如桌面:
$ cd ~/Desktop
$ nic.pl
-
選擇模板[10.]iphone/tweak,如下圖所示:
-
填寫(xiě)項(xiàng)目信息
-
Project Name:
項(xiàng)目名稱茂卦,可以隨便寫(xiě)何什,例如:tweak_wechat -
Package Name:
項(xiàng)目ID,可以隨便寫(xiě)等龙,例如:com.sp.wechat -
Author/Maintainer Name:
作者处渣,直接敲回車,默認(rèn)就是Mac上的當(dāng)前用戶名 -
MobileSubstrate Bundle filter:
需要逆向的App的BundleID而咆,可以通過(guò)Cycript查看霍比,例如:微信的BundleID就是com.tencent.wechat -
List of applications to terminate upon installcation
幕袱,直接敲回車暴备,默認(rèn)即可 - 之后就會(huì)生成一個(gè)文件夾,里面包含:
control们豌、Makefile涯捻、Tweak.x浅妆、xxx.plist
等文件,這些文件的具體作用障癌,后續(xù)會(huì)說(shuō)到
-
5. 編輯Makefile文件
-
在Makefile中加入環(huán)境變量凌外,寫(xiě)清楚通過(guò)哪個(gè)IP和端口訪問(wèn)手機(jī),如下所示涛浙,由于會(huì)把接口轉(zhuǎn)發(fā)到本地的10010端口康辑,所以這里可以這樣寫(xiě):
- THOS_DEVICE_IP 手機(jī)IP
- THOS_DEVICE_PORT 要訪問(wèn)的端口號(hào)
export THEOS_DEVICE_IP=127.0.0.1 export THEOS_DEVICE_PORT=10010
如果不想每個(gè)項(xiàng)目的Makefile都編寫(xiě)IP和端口環(huán)境變量,也可以添加到用戶配置文件中轿亮,如下所示疮薇,編輯完成后,記得使用
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. 編寫(xiě)逆向代碼
- 打開(kāi)Tweak.x文件按咒,編寫(xiě)自己的逆向代碼,如下所示但骨,
%hook励七、%end
屬于Logos語(yǔ)法
%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動(dòng)態(tài)庫(kù)
$ make
- 把動(dòng)態(tài)庫(kù)打包成deb文件
$ make package
- 安裝到手機(jī)
$ make install
8. 配置好Theos后,Theos的使用方法
配置好Theos后奔缠,Theos的使用只需三步:
在命令行中輸入nic.pl掠抬,選擇tweak模板,填寫(xiě)項(xiàng)目信息
在Tweak.x中編寫(xiě)逆向代碼
在命令行中輸入make編譯->make package打包->make install安裝到手機(jī)
建議把Makefile中的IP和端口環(huán)境變量添坊,都加到
~/bash_profile
中剿另,這樣以后新建項(xiàng)目,都不用配置環(huán)境變量了
四贬蛙、配置Theos過(guò)程中可能遇到的問(wèn)題
-
make package的錯(cuò)誤雨女,如下所示:
解決辦法:是因?yàn)榇虬鼔嚎s方式有問(wèn)題,改成gzip壓縮就可以
- 修改dm.pl文件阳准,用#號(hào)注釋掉下面兩句:
$ 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出現(xiàn)錯(cuò)誤,如下所示:
-
解決辦法:是因?yàn)榘惭b了多個(gè)Xcode野蝇,導(dǎo)致的路徑錯(cuò)誤讼稚,需要指定一下Xcode
$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
-
make出現(xiàn)以下錯(cuò)誤:
-
解決辦法:因?yàn)橹耙呀?jīng)編譯過(guò),有緩存導(dǎo)致的绕沈,clean一下即可
$ make clean
五锐想、Logos語(yǔ)法
-
- 寫(xiě)逆向代碼時(shí)常用的Logos語(yǔ)法
%hook、%end
:hook一個(gè)類的開(kāi)始和結(jié)束乍狐,中間包括的所有方法赠摇,默認(rèn)是hook狀態(tài)-
%log
:在方法中,加入此關(guān)鍵詞,就會(huì)自動(dòng)打印方法名藕帜、方法參數(shù)烫罩,會(huì)在系統(tǒng)日志中顯示出來(lái),在Xcode->Window->Devices And Simulators->Open Console->選擇自己的手機(jī)
洽故,即可查看贝攒,如下圖所示:
HBDebugLog
:跟NSLog類似,一般用來(lái)輸出返回值的时甚,會(huì)自動(dòng)生成隘弊,不用管%new
:添加一個(gè)新的方法,寫(xiě)在某個(gè)方法的上面荒适,代表這個(gè)方法是新增的长捧,而不是hook的%c(className)
:生成一個(gè)Class對(duì)象,例如:%c(NSObject)吻贿,就相當(dāng)于NSClassFromString()串结、object_getClass()%org
:方法原來(lái)的代碼邏輯,在方法里加上此關(guān)鍵詞舅列,就代表實(shí)現(xiàn)了此方法的原來(lái)的代碼邏輯%ctor
:構(gòu)造方法肌割,加載咱們的動(dòng)態(tài)庫(kù)時(shí)自動(dòng)調(diào)用%dtor
:析構(gòu)方法,在程序退出時(shí)自動(dòng)調(diào)用logify.pl
:可以將一個(gè)頭文件快速轉(zhuǎn)換成已經(jīng)包含打印信息的xm文件帐要,命令如下:
logify.pl xx.h > xx.xm
-
- 使用logify.pl生成的xm文件把敞,很多時(shí)候編譯是通不過(guò)的,需要進(jìn)行以下處理:
- 刪掉
__weak
- 刪掉
inout
- 刪掉協(xié)議或者聲明協(xié)議榨惠,例如:
@protocol BaseMsgContentDelgate;
- 聲明類名奋早,例如:
@class MMRichTextCoverView;
- 刪掉以.開(kāi)頭的方法,例如:
- (void).cxx_destruct { %log; %orig; }
- 將
HBLogDebug(@" = 0x%x", (unsigned int)r);
刪除或者是替換為HBLogDebug(@" = 0x%@", r);
- 當(dāng)參數(shù)里面帶上協(xié)議時(shí)赠橙,需要把協(xié)議刪掉耽装,例如:
- (void)setM_backgroundThreadDelegate:( id <BaseMsgContentInBackgroundThreadDelgate> )m_backgroundThreadDelegate { %log; %orig; }
,把<BaseMsgContentInBackgroundThreadDelgate>刪掉即可期揪。
六掉奄、tweak工程的一些技巧
- 多文件的時(shí)候,建議新建一個(gè)
src
文件夾凤薛,用來(lái)存放xm代碼
姓建,這樣做的話,就需要在Makefile文件
中缤苫,修改WeChatTest_FILES = $(wildcard src/*.xm)
速兔,把參數(shù)改成通配符;如果有多個(gè)類型的文件活玲,就繼續(xù)追加即可涣狗,例如:
WeChatTest_FILES = $(wildcard src/*.xm) $(wildcard src/*.x)
- 多文件的時(shí)候,建議新建一個(gè)
- 如果工程里面需要額外的圖片的話帜矾,可以把圖片放在項(xiàng)目的layout文件夾中,
layout
相當(dāng)于手機(jī)的Device根路徑
屑柔;當(dāng)把圖片放在/layout/Library/Caches/項(xiàng)目名
下面時(shí),插件安裝到手機(jī)后珍剑,圖片會(huì)自動(dòng)存放在手機(jī)的/Device/Library/Caches/項(xiàng)目名
路徑中
- 如果工程里面需要額外的圖片的話帜矾,可以把圖片放在項(xiàng)目的layout文件夾中,
七掸宛、給微信增加自動(dòng)搶紅包功能
- 首先分析需求,在微信的發(fā)現(xiàn)界面招拙,增加兩行UI唧瘾,自動(dòng)搶紅包和退出微信,并實(shí)現(xiàn)功能(這里先繪制UI别凤,功能實(shí)現(xiàn)在動(dòng)態(tài)調(diào)試?yán)锩嬷v)
- 使用Reveal觀察微信的發(fā)現(xiàn)界面饰序,拿到發(fā)現(xiàn)界面的類名
FindFriendEntryViewController
- 使用Reveal觀察微信的發(fā)現(xiàn)界面饰序,拿到發(fā)現(xiàn)界面的類名
- 對(duì)微信脫殼,并且用class-dump導(dǎo)出微信的頭文件规哪,找到
FindFriendEntryViewController.h
文件求豫,認(rèn)真分析,發(fā)現(xiàn)里面實(shí)現(xiàn)了tableView的幾個(gè)代理方法:
- 對(duì)微信脫殼,并且用class-dump導(dǎo)出微信的頭文件规哪,找到
-
nic.pl
選擇tweak模板诉稍,填寫(xiě)項(xiàng)目信息創(chuàng)建tweak項(xiàng)目蝠嘉,在Tweak.x
中編寫(xiě)自己的逆向代碼,逆向代碼主要還是OC代碼杯巨,部分關(guān)鍵詞用到了Logos語(yǔ)法蚤告,例如:%hook %end
代表替換微信中這些方法的實(shí)現(xiàn);%new
代表這個(gè)方法是新增的服爷;%org
代表這個(gè)方法的原有實(shí)現(xiàn)杜恰。如下所示:
-
#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 = @"自動(dòng)搶紅包";
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){
//自動(dòng)搶紅包
}else if ([indexPath row] == 1){
// 終止進(jìn)程
exit(0);
// abort();
}
}
%new
- (void)sp_autoRed:(UISwitch *)switchView{
[SP_Defaults setBool:switchView.on forKey:SP_AutoKey];
[SP_Defaults synchronize];
}
- 編譯、打包仍源、安裝到手機(jī)心褐,在手機(jī)的微信中,查看修改的成果
$ cd到tweak項(xiàng)目的目錄下
$ make clean && make page debug=0 && make install
- 如果想卸載插件笼踩,可以在Cydia的【已安裝】里找到咱們寫(xiě)的插件檬寂,點(diǎn)擊卸載即可。(或者在手機(jī)的
Device/Libiary/MobileSubstrate/DynamicLibiaries
中找到咱們自己寫(xiě)的 plist戳表、dylib文件桶至,刪除即可)
- 如果想卸載插件笼踩,可以在Cydia的【已安裝】里找到咱們寫(xiě)的插件檬寂,點(diǎn)擊卸載即可。(或者在手機(jī)的
八、逆向工程總結(jié)
- 使用Theos的tweak模板匾旭,創(chuàng)建逆向工程之前镣屹,我們需要先對(duì)要逆向的App,進(jìn)行界面分析和代碼分析价涝,找到類名女蜈、方法名、成員變量等信息后,在用Logos語(yǔ)法和OC語(yǔ)法編寫(xiě)我們的逆向代碼
- 界面分析伪窖,建議
Reveal
和Cycripy
一起配合使用逸寓,用Reveal
查看界面,找到內(nèi)存地址覆山,然后用Cycripy
做進(jìn)一步的分析竹伸,例如:找到某個(gè)視圖的下一個(gè)響應(yīng)者,#0x16166e2b0.nextResponder
- 界面分析伪窖,建議
- 代碼分析簇宽,脫殼后使用class-dump工具導(dǎo)出頭文件勋篓,用界面分析得到的類名,找到這個(gè)類的方法名魏割、成員變量等信息譬嚣,然后用我們開(kāi)發(fā)時(shí)一些經(jīng)驗(yàn)進(jìn)行分析