利用LLDB對微信進行分析,然後利用分析的結果,再逐步講解如何Hook微信的登入過程,截獲微信密碼。
在上一篇文章(APP重簽名)中,已經介紹瞭如何對APP重簽名,並且利用XCode將微信跑起來,既然到了這一步,就萬萬不能錯過強大的LLDB。這篇文章就講為大家講解到如何利用LLDB對微信進行分析,然後利用分析的結果,再逐步講解如何Hook微信的登入過程,截獲微信密碼。
老規矩,片頭先給福利:點選下載Demo:HookWeChat,這次有兩份程式碼。由於越獄版微信體積太大,受到github限制,所以並沒有將它傳到github,可以在下方連結單獨下載
文中所需要用到的工具和檔案:
越獄版本微信7.0.2 提取碼: 2w87
MachOView 提取碼: n3hy
yololib 提取碼:e8qs
class-dump 提取碼:v5ku
接下來我們會從一下幾部,讓微信脫下看似安全的外衣,裸露在大家面前。
- Framework的作用
- 初探MachO (原理分析)
- 程式碼注入 (程式碼過程)
- ViewDebug、LLDB、class-dump分析微信登入頁面(原理分析)
- Hook登入,自動獲取密碼 (程式碼過程)
- 總結
1、Framework的作用(對Framework熟悉的同學可以跳過這一步)
什麼是Framework這裡就不多加敘述,我參考這個網站,非常詳細,看不懂你直接@我。點這裡:Framework最強講解
廢話不多說,接下來直接演示如何建立一個Framework,並且介紹跟我們們Hook微信有關的基礎原理。
新建一個工程FrameworkDemo,新建一個Framework,取名FYHook
在新建出來的FYHook資料夾中新建InjectCode(繼承NSObject)物件,並且新建程式碼:
+ (void)load {
NSLog(@"來了,老弟?");
}
複製程式碼
直接執行,會發現來了,老弟?
被輸出,證明用這種方法新建的Framework能夠直接執行在我們的專案中。
2、初探MachO (如果不想看原理,可以直接跳到第三部 程式碼注入)
根據上篇文章APP重簽名講到的,我們可以使用XCode將微信跑起來,那麼是不是將兩者結合起來,就可以將我們的程式碼注入進微信的APP呢?
Step 1 先思考一個問題。
根據APP重簽名中的結論,利用指令碼可以便捷重籤APP(因為我們用的WeChat舉例,所以下面簡稱WeChat),那麼我們在重籤指令碼的工程中,直接建立一個Framework,能不能讓我們Framework中的程式碼在WeChat中執行?
很顯然,這是不行的(有興趣的可以試一下)!為什麼? 這個問題下面會回答,先把這個問題記在心中。
Step 2 MachO作用
在我們用XCode新建HYHook的時候,其實XCode幫我們做了一部操作:建立HYHook時候,同時將HYHook連結到我們的專案中(這是後期的XCode新增功能,早年的XCode這一步是需要我們直接做的)
common
+b
Build一下,會發現在已經Build出來的檔案中的Frameworks下已經有FYHook了,已經已經表明FYHook被Copy我們的ipa檔案了。(如何看Build出來的檔案?檢視:APP重簽名中Step 8 App重簽名)
但是FYHook在ipa檔案中,並不代表著FYHook就可以被我們的可執行檔案所執行,因為FYHook並沒有沒導報入我們的可執行檔案,只有在這個可行執行檔案的某一個地方
做好標記,告知可執行檔案,在適當的時候需要載入外部的FYHook,才能夠正常執行。
而這個地方所說的可執行檔案就是MachO
檔案(具體什麼是MachO,這不是本片文章的重點內容,可以持續關注筆者之後的文章,下一章詳細介紹這至關重要的MachO),我們可以利用工具MachOView來檢視MachO中到底有什麼內容。
Step 3 MachOView
點選這裡下載:MachOView 提取碼: n3hy用MachOView開啟FrameworkDemo的MachO,可以看到如下圖
可以看到其中的有個Load Commons組,這裡面就包括所有需要被動態載入的庫。也就是說,如果在Load Commons中沒有對應的FYHook,就不會載入FYHook。
在上圖中可以看到FYHook已經被加入了Load Commons,並且圖右側也標記了FYHook所屬的目錄(和MachO檔案同級的Frameworks下FYHook.framework中 ,FYHook.framework其實是個資料夾,裡面的FYHook也是個MachO )
所以這裡就得到了「為什麼我們直接將FYHook加入我們的從重籤指令碼工程,不能直接執行FYHook」的答案。 因為在在我們Build出來的MachO檔案中的Load Commons中沒有加入FYHook的路徑。所以無法執行FYHook中的程式碼。
那麼我們直接將FYHook加入我們Build出的MachO檔案行嗎? 顯然也是不行的,因為我們Build出的MachO檔案始終會被原始包(WeChat)中的MachO給替換掉。我們需要將FYHook加入原始包(WeChat)中的MachO中。
Step 4 將FYHook標記入MachO中
這裡我們就需要用到終端命令列工具:yololib 提取碼:e8qs
將下載下來的yololib.zip解壓後得到的yololib放在目錄/usr/local/bin下,這樣我們在終端中就可以使用yololib命令了
以下命令就是將FYHook注入WeChat的命令
// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook
複製程式碼
3、程式碼注入
Step 1 建立重籤指令碼工程
新建工程,取名InjectFrameWork,過程可參照上一篇文章(APP重簽名) 最後得到如下工程:
Step 2 建立Framework檔案
新建一個Framework檔案,取名FYHook,在FYHook中新建檔案InjectCode,在InjectCode加入之前提到的同樣的load程式碼, 等到如下工程:
Step 3 修改原始檔的MachO檔案
找到WeChat的MachO檔案,開啟終端,進入此目錄下 執行命令
// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook
複製程式碼
Step 4 重新打包WeChat.ipa
zip -ry WeChat.ipa Payload
複製程式碼
Step 5 加入新的WeChat.ipa,執行工程
將新得到的WeChat.ipa重新加入APP檔案(這一步其實可以只加入檔案,而不用加入工程),刪除原來的Wechat7.0.2越獄.ipa。
common
+ R
執行程式碼,會發現微信跑起來了,我們的來了,老弟?
也被輸出了!
Step 6 新的思考
之前分析了我們建立了FYHook,但是沒有對MachO注入,得到的答案是來了,老弟?
不能被輸出,WeChat能跑起來。
那麼如果我們對MachO注入FYHook,卻沒有建立對應的FYHook.framework,會怎麼樣呢?
這就留給大家思考,再去驗證了,有答案的同學也能下方留言,並說出原因哦。
4、 ViewDebug、LLDB、class-dump分析微信登入頁面
Step 1 ViewDebug
XCode跑起微信之後,跳轉到登入頁面,利用ViewDebug檢視具體的詳細的UI
可以看到,登入按鈕是一個FixTitleColorButton物件,他的Target的名字存在地址0x280afaa40中,他的Action名字存在地址0x280afac00中。 用同樣的方法檢視賬號密碼的輸入框,會發現他們都屬於一個物件,叫做WCUITextFieldStep 2 LLDB
利用LLDB檢視登入按鈕具體的Target和Action名稱
得知: 登入按鈕處於WCAccountMainLoginViewController這個頁面之中 登入按鈕的點選方法叫做onNextStep 3 class-dump
class-dump,是可以把Objective-C執行時的宣告的資訊匯出來的工具。其實就是可以匯出.h檔案。用class-dump可以把未經加密的app的標頭檔案匯出來。
點選這下載命令列工具:class-dump 提取碼:v5ku 同樣的,將class-dump拷貝到Mac的目錄/usr/local/bin下,這樣我們在終端中就可以使用yololib命令了
執行命令將WeChat所有的標頭檔案匯出來。
// class-dump -H 「app的MachO檔案」 -o 「輸入的目錄」
class-dump -H WeChat -o /Users/dengbin/Code/GitHub/HookWeChat/InjectFrameWork/APP/WeChat-H
複製程式碼
Step 4 找到輸入框裡面的內容
利用文字工具,例如Sublime檢視WeChat的標頭檔案,找到前面發現的WCAccountMainLoginViewController
發現裡面確實有方法- (void)onNext;
,還有長得很像賬號輸入框,密碼輸入框的物件_textFieldUserNameItem
,_textFieldUserPwdItem
。
接下來就是找到密碼輸入框裡面的字串了,可以發現這兩個都是WCAccountTextFieldItem物件,所有我們繼續在匯出的檔案裡面找到WCAccountTextFieldItem
在其中只發現一個tips物件m_labelTip,沒有發現對應的textfiled,但是可以看到WCAccountTextFieldItem是繼承於WCBaseTextFieldItem的,所以繼續查詢WCBaseTextFieldItem
從這就可以看到一個m_textField物件,這是個WCUITextField物件,疑似我們的目標textField,繼續檢視WCUITextField
果然,這就是一個UITextField檔案,那麼我們就可以通過text欄位取出其string。
接下來在用LLDB試試看,驗證下我們的猜想:
隨便在賬號欄輸入:qwerty
然後在密碼欄輸入:123456
po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"]
po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"]
po [(WCUITextField *)0x112163a00 text]
複製程式碼
其中第一個地址0x1128bbc00是在前兩部利用ViewDubg找到的。
可以發現最後確實找到了我們輸入的密碼123456
,證明我們的分析是正確的。
5、Hook登入,自動獲取密碼
接下來又是程式碼Coding了。原理分析完,其實程式碼就很簡單了,直接上程式碼:
+ (void)load {
NSLog(@"來了,老弟?");
Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));
//1.儲存原始的IMP
old_onNext = method_getImplementation(onNext);
//2.SET
method_setImplementation(onNext, (IMP)my_next);
}
IMP (*old_onNext)(id self,SEL _cmd);
void my_next(id self,SEL _cmd){
// 獲取密碼
NSString *pwd = [[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
NSString *accountTF = [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
NSLog(@"密碼是!%@",pwd);
// 將密碼追加在賬號欄的後面
[[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(setText:) withObject:[NSString stringWithFormat:@"%@+%@",accountTF,pwd]];
//呼叫原來的方法
old_onNext(self,_cmd);
}
複製程式碼
稍微解釋一下,在前面我們發現登入的響聲事件是onNext,所有我們利用Objective-C的Runtime特性,對onNext進行方法替換,在響應原有的onNext之前,我們加上我們自己的方法,比如程式碼中的,在賬號欄中直接輸入密碼。
執行後結果如圖:
我這用的是setIMP和getIMP的方式,對原方法進行HOOK,其實方法有多種:如:class_replaceMethod()
,method_exchangeImplementations()
,這裡只是舉一個例子供大家參考。
這篇文章的所有程式碼都可以在這下載到:HookWeChat
6、總結:
- 先對APP重簽名,讓APP能在XCode執行起來
- 利用yololib注入Framework,讓APP可以執行我們直接的程式碼
- 利用ViewDebug、LLDB、class-dump分析登入事件和密碼框所在位置
- 利用Runtime的MethodSwizzle,Hook登入事件
這次只是簡單的微信的一個靜態頁面進行了初步接觸,雖然思路簡單,但這運用到的工具,卻是無數大神前輩們為我們鋪好的路,感謝!
MachO檔案在本文中只是初略的提及,其實在我們逆向過程中MachO是一個至關重要的存在,如:
- 對app的砸殼,其實就是對MachO解密
- 所有的方法名,靜態字串都是存在MachO中
- app的架構(arm64,arm7...)也是在MachO中區分的
- app載入其實也是對MachO的一步步操作
- ...
所以,在下篇文章,筆者將會對MachO檔案進行詳細的講解。請持續關注,覺得有幫助的點個收藏,留言評估了哦。