本文僅供學習與交流,請勿用于商業(yè)用途拖云。
學習逆向的用處
- 了解iOS的底層實現(xiàn)
- 破解別人的軟件摘仅,實現(xiàn)各種變態(tài)的功能(微信搶紅包、釘釘打卡等等...)
- 保護自己的代碼叮叹,隱藏隱私數(shù)據(jù)艾栋,隱藏函數(shù)
- 分析別人的代碼架構(gòu) - 這個需要你有一定的架構(gòu)知識
聽起來好像很屌的樣子
需要掌握的基礎(chǔ)知識
- iOS正向開發(fā)知識
- App的簽名機制&&重簽名APP
- 代碼注入(MachO文件、dylib)
- 常用工具的使用(class-dump蛉顽、restore-symbol蝗砾、LLDB、MonkeyDev)
- ARM匯編
逆向開發(fā)的流程
- 解密携冤、導(dǎo)出應(yīng)用程序悼粮、class-dump導(dǎo)出頭文件、IDA反編譯二進制文件曾棕,為后續(xù)工作作準備扣猫。
- 從界面表現(xiàn)入手,獲取當前界面布局及控制器翘地。
- hook發(fā)現(xiàn)的一些相關(guān)類申尤,記錄輸出調(diào)用順序及參數(shù)。
- 找到關(guān)鍵函數(shù)衙耕,查看調(diào)用堆棧昧穿,hook測試效果。
- 靜態(tài)分析加動態(tài)調(diào)試分析關(guān)鍵函數(shù)的實現(xiàn)邏輯橙喘。
- 模擬或篡改函數(shù)調(diào)用邏輯粤咪。
- 制作插件,或者移植到非越獄機器渴杆。
整體流程就是這樣寥枝,但過程可能不會太順利,有時需要反復(fù)探索才能定位目標函數(shù)磁奖。這個過程很枯燥囊拜,也很有趣。
常用工具
frida-ios-dump
簡介:一鍵砸殼工具比搭,需要越獄手機冠跷。
用法:
$ iproxy 2222 22
$ frida-ios-dump -l //查看所有的進程 可以用 grep 過濾
$ frida-ios-dump Display name or Bundle identifier 砸到電腦的下載目錄
class-dump
簡介:class-dump 是一個工具,它利用了 Objective-C 語言的運行時特性,將存儲在 Mach-O 文件中的頭文件信息提取出來蜜托,并生成對應(yīng)的 .h 文件抄囚。
用法:
$class-dump -H MachO文件路徑 -o 導(dǎo)出頭文件需要存放路徑
$class-dump -H ./WeChat -o ~/Desktop/wechatHeader
restore-symbol
簡介:對二進制文件進行符號還原。
用法:
$restore-symbol origin_mach_o_file -o mach_o_with_symbol
IDA Pro
簡介:跨平臺反編譯工具橄务,可已將二進制文件反編譯成匯編語言代碼及偽代碼幔托,支持動態(tài)調(diào)試。
Charles
簡介:抓包工具蜂挪,可以抓HTTP請求重挑,支持SSL。
Postman
簡介:一款功能強大的接口測試工具棠涮,能大幅提升工作效率谬哀。
MonkeyDev
簡介:iOS逆向開發(fā)神器,只需拖入一個砸殼應(yīng)用严肪,自動集成class-dump史煎、restore-symbol、Reveal驳糯、Cycript和注入的動態(tài)庫并重簽名安裝到非越獄機器篇梭。
使用:安裝完成之后用Xcode新建工程,選擇MonkeyApp结窘,把需要逆向的ipa包拖入到工程里很洋,即可直接運行。
實戰(zhàn)-抖音去水印
新建MonkeyApp工程隧枫,將砸好殼的抖音ipa拖進工程喉磁,打開工程設(shè)置,搜索MONKEY關(guān)鍵字官脓,打開restore-symbol.
首先我們抓包獲取到視頻的URL:https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200f010000bmmosn3d82diq4cg9mg0&line=0&ratio=540p&watermark=1&media_type=4&vr_type=0&improve_bitrate=0&logo_name=aweme_suffix协怒,我們看到鏈接里有個watermark的參數(shù)值為1,我猜想這個值可能控制是否有水印卑笨,所以我們用Postman把watermark參數(shù)改為0測試一下孕暇,結(jié)果發(fā)現(xiàn)獲取的視頻果然沒有水印,所以我們需要注入代碼去修改這個鏈接赤兴。
然后我們使用class-dump獲取所有頭文件妖滔,使用IDA反編譯抖音的二進制文件,以備后面使用桶良。
我們知道保存視頻到相冊必須要調(diào)用系統(tǒng)的API座舍,因此我們先打一個符號斷點。
然后運行App陨帆,執(zhí)行保存操作曲秉,進入我們剛才打的斷點
我們看一下調(diào)用棧采蚀,發(fā)現(xiàn)有幾層調(diào)用棧是___lldb_unnamed_symbol,這些是沒有被符號化承二,可能是block榆鼠,至于怎么符號化block這里先不介紹了,此路不通亥鸠,我們換一個方向考慮妆够。
我們使用視圖層級查看工具,發(fā)現(xiàn)分享的控制器AWEAwemeShareViewController
然后我們打開AWEAwemeShareViewController.h里读虏,在里面搜索press责静、tap關(guān)鍵字袁滥,發(fā)現(xiàn)shareViewTapped:方法盖桥,我猜想點擊保存的時候就是調(diào)用的這個方法,我們來試著hook一下這個方法题翻。
打開Logos目錄下面的.xm文件揩徊,在文件的最后面加上下面的代碼,并打上斷點嵌赠,運行一下塑荒,證實我們的想法是對的。
%hook AWEAwemeShareViewController
- (void)shareViewTapped:(id)arg1 {
%orig();
}
%end
打開IDA姜挺,找到AWEAwemeShareViewController的shareViewTapped:方法齿税,反編譯成偽代碼。
經(jīng)過查看炊豪,我們找到AWEShareService協(xié)議凌箕,看名字應(yīng)該是處理邏輯的類,我們在class-dump導(dǎo)出的頭文件里去搜索AWEShareService關(guān)鍵字词渤,發(fā)現(xiàn)AWEShareService和AWEShareServiceUtils兩個類牵舱,分別查看它們的方法,找到AWEShareServiceUtils中的兩個方法可能和下載有關(guān)缺虐。
+ (void)downloadAndShareWithURLString:(id)arg1 videoModel:(id)arg2 distinationURL:(id)arg3 shareType:(long long)arg4 pointResume:(_Bool)arg5 hasWatermark:(_Bool)arg6 shouldAddEndWatermark:(_Bool)arg7 saveAsLivePhotoEnabled:(_Bool)arg8 shouldSaveDirectly:(_Bool)arg9 preprocess:(CDUnknownBlockType)arg10 completion:(CDUnknownBlockType)arg11;
+ (id)_URLListForAwemeModel:(id)arg1 videoModel:(id)arg2 forBTDShareType:(long long)arg3 hasWatermark:(_Bool *)arg4 shouldSaveDirectly:(_Bool *)arg5 shouldAddEndWatermark:(_Bool *)arg6;
hook這兩個方法芜壁,然后打斷點進行調(diào)試。
%hook AWEShareServiceUtils
+ (void)downloadAndShareWithURLString:(id)arg1 videoModel:(id)arg2 distinationURL:(id)arg3 shareType:(long long)arg4 pointResume:(_Bool)arg5 hasWatermark:(_Bool)arg6 shouldAddEndWatermark:(_Bool)arg7 saveAsLivePhotoEnabled:(_Bool)arg8 shouldSaveDirectly:(_Bool)arg9 preprocess:(id)arg10 completion:(id)arg11 {
%orig();
}
+ (id)_URLListForAwemeModel:(id)arg1 videoModel:(id)arg2 forBTDShareType:(long long)arg3 hasWatermark:(_Bool *)arg4 shouldSaveDirectly:(_Bool *)arg5 shouldAddEndWatermark:(_Bool *)arg6 {
id result = %orig();
BOOL hasWatermark = *arg4;
BOOL shouldSaveDirectly = *arg5;
BOOL shouldAddEndWatermark = *arg6;
return result;
}
%end
我們發(fā)現(xiàn)_URLListForAwemeModel方法的返回值就是視頻的下載鏈接高氮,然后我們再看一下這個方法的參數(shù)慧妄,發(fā)現(xiàn)第2個參數(shù)videoModel里包含兩個實例變量_hasWatermark和_hasEndWatermark,值都為ture剪芍。
打開AVEvideoModel的頭文件塞淹,找到對應(yīng)的屬性
hook一下AVEvideoModel類兩個屬性的getter方法,讓它們都返回NO紊浩,然后重新運行窖铡,斷點調(diào)試疗锐,發(fā)現(xiàn)_URLListForAwemeModel返回的鏈接里watermark參數(shù)已經(jīng)是0了。
%hook AWEVideoModel
- (BOOL)hasWatermark {
return NO;
}
- (BOOL)hasEndWatermark {
return NO;
}
%end
到這里我覺得可能已經(jīng)成功了费彼,于是保存了一個視頻滑臊,到相冊里查看,發(fā)現(xiàn)保存的視頻居然還有水印箍铲。于是我懷疑是不是鏈接后面又被修改過雇卷,于是再次抓包看了一下,發(fā)現(xiàn)鏈接確實沒有問題了颠猴。于是猜想是客戶端添加的水印关划。
于是打開我們最開始打的那個符號斷點,運行調(diào)試翘瓮,發(fā)現(xiàn)調(diào)用棧變了,多了一層-[AWEDynamicWaterMarkExporter waterMarkExporterFinished:]:贮折,從名字看就是給視頻添加水印成功的回調(diào)。
于是我猜想肯定是有一個變量控制客戶端添加水印的邏輯资盅,于是把之前hookAWEVideoModel的兩個方法注掉運行调榄,然后再加上運行,通過對比發(fā)現(xiàn)呵扛,兩次運行_URLListForAwemeModel方法調(diào)用后的shouldSaveDirectly參數(shù)的值不一樣每庆,通過名字我們可以猜出這個參數(shù)可能就是我們想要找的參數(shù)。
于是今穿,我們把這個參數(shù)修改為YES缤灵,重新運行
+ (id)_URLListForAwemeModel:(id)arg1 videoModel:(id)arg2 forBTDShareType:(long long)arg3 hasWatermark:(_Bool *)arg4 shouldSaveDirectly:(_Bool *)arg5 shouldAddEndWatermark:(_Bool *)arg6 {
id result = %orig();
BOOL hasWatermark = *arg4;
BOOL shouldSaveDirectly = *arg5;
BOOL shouldAddEndWatermark = *arg6;
*arg5 = YES;
return result;
}
接下來是見證奇跡的時刻,我們再保存一個視頻到相冊蓝晒,然后去相冊查看腮出,發(fā)現(xiàn)視頻已經(jīng)沒有水印了。到這里我們的抖音去水印就完成了拔创。