iOS逆向工程(七):使用Theos逆向項目

使用Theos逆向項目

一、Theos是什么?
  1. Theos是一套跨平臺的開發工具,用于在不使用Xcode的情況下開發、部署iOS插件,大多數插件開發人員都使用Theos。

  2. Theos工具套件包含一些重要組件

    • NIC組件,是一套項目模板系統,提供了各式各樣的模板,用這些模板可以快速開始項目

    • Make構建系統,由GNU Make驅動的強大構建系統,能夠直接創建.deb軟件包,并在Cydia中分發

    • Logos指令庫,提供了逆向的語法,允許使用一組預處理指令實現Hook

  3. 配置好Theos后,就可以使用Theos中的tweak模板,快速創建逆向工程,并使用Logos語法修改別人App的一些行為 ,例如:微信自動搶紅包、騰訊視頻去廣告等等,最后使用make構建系統編譯、打包、分發。

  4. Theos目錄結構:https://github.com/theos/theos/wiki/Structure

  5. Theos環境變量和目錄:http://iphonedevwiki.net/index.php/Theos

二、Theos逆向的原理
  1. 使用tweak模板把咱們寫的逆向代碼安裝到手機的原理:首先會把咱們編寫的逆向代碼,編譯成dylib動態庫,然后與plist文件一起,打包成deb文件,然后通過手機的Cydia,安裝到手機上 ,如下圖所示:

    tweak模板

  2. 改變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過程中可能遇到的問題
  1. 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
    1. make出現錯誤,如下所示:


      image.png

解決辦法:是因為安裝了多個Xcode,導致的路徑錯誤,需要指定一下Xcode

 $ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer/
    1. make出現以下錯誤:


      image.png

解決辦法:因為之前已經編譯過,有緩存導致的,clean一下即可

$ make clean
五、Logos語法
    1. 寫逆向代碼時常用的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
    
    1. 使用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工程的一些技巧
    1. 多文件的時候,建議新建一個src文件夾,用來存放xm代碼,這樣做的話,就需要在Makefile文件中,修改WeChatTest_FILES = $(wildcard src/*.xm),把參數改成通配符;如果有多個類型的文件,就繼續追加即可,例如:
      WeChatTest_FILES = $(wildcard src/*.xm) $(wildcard src/*.x)
    1. 如果工程里面需要額外的圖片的話,可以把圖片放在項目的layout文件夾中,layout相當于手機的Device根路徑;當把圖片放在/layout/Library/Caches/項目名下面時,插件安裝到手機后,圖片會自動存放在手機的/Device/Library/Caches/項目名路徑中
七、給微信增加自動搶紅包功能
    1. 首先分析需求,在微信的發現界面,增加兩行UI,自動搶紅包和退出微信,并實現功能(這里先繪制UI,功能實現在動態調試里面講)
    1. 使用Reveal觀察微信的發現界面,拿到發現界面的類名FindFriendEntryViewController
    1. 對微信脫殼,并且用class-dump導出微信的頭文件,找到FindFriendEntryViewController.h文件,認真分析,發現里面實現了tableView的幾個代理方法:
      FindFriendEntryViewController文件
    1. 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];
}
    1. 編譯、打包、安裝到手機,在手機的微信中,查看修改的成果
$ cd到tweak項目的目錄下
$ make clean && make page debug=0 && make install
    1. 如果想卸載插件,可以在Cydia的【已安裝】里找到咱們寫的插件,點擊卸載即可。(或者在手機的Device/Libiary/MobileSubstrate/DynamicLibiaries中找到咱們自己寫的 plist、dylib文件,刪除即可)
八、逆向工程總結
    1. 使用Theos的tweak模板,創建逆向工程之前,我們需要先對要逆向的App,進行界面分析和代碼分析,找到類名、方法名、成員變量等信息后,在用Logos語法和OC語法編寫我們的逆向代碼
    1. 界面分析,建議RevealCycripy一起配合使用,用Reveal查看界面,找到內存地址,然后用Cycripy做進一步的分析,例如:找到某個視圖的下一個響應者,#0x16166e2b0.nextResponder
    1. 代碼分析,脫殼后使用class-dump工具導出頭文件,用界面分析得到的類名,找到這個類的方法名、成員變量等信息,然后用我們開發時一些經驗進行分析
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容