iOS逆向(4)-程式碼注入,非越獄竊取微信密碼

一縷清風揚萬里發表於2019-03-10

利用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

建立Framework(1).png

建立Framework(2).png

在新建出來的FYHook資料夾中新建InjectCode(繼承NSObject)物件,並且新建程式碼:

+ (void)load {
    NSLog(@"來了,老弟?");
}
複製程式碼

新建InjectCode.png

直接執行,會發現來了,老弟?被輸出,證明用這種方法新建的Framework能夠直接執行在我們的專案中。

NSLog字串.png

2、初探MachO (如果不想看原理,可以直接跳到第三部 程式碼注入)

根據上篇文章APP重簽名講到的,我們可以使用XCode將微信跑起來,那麼是不是將兩者結合起來,就可以將我們的程式碼注入進微信的APP呢?

Step 1 先思考一個問題。

根據APP重簽名中的結論,利用指令碼可以便捷重籤APP(因為我們用的WeChat舉例,所以下面簡稱WeChat),那麼我們在重籤指令碼的工程中,直接建立一個Framework,能不能讓我們Framework中的程式碼在WeChat中執行?

很顯然,這是不行的(有興趣的可以試一下)!為什麼? 這個問題下面會回答,先把這個問題記在心中。

Step 2 MachO作用

在我們用XCode新建HYHook的時候,其實XCode幫我們做了一部操作:建立HYHook時候,同時將HYHook連結到我們的專案中(這是後期的XCode新增功能,早年的XCode這一步是需要我們直接做的)

XCode自動連結.png
common+b Build一下,會發現在已經Build出來的檔案中的Frameworks下已經有FYHook了,已經已經表明FYHook被Copy我們的ipa檔案了。(如何看Build出來的檔案?檢視:APP重簽名中Step 8 App重簽名)
自動加入Frameworks已經MachO檔案.png
但是FYHook在ipa檔案中,並不代表著FYHook就可以被我們的可執行檔案所執行,因為FYHook並沒有沒導報入我們的可執行檔案,只有在這個可行執行檔案的某一個地方做好標記,告知可執行檔案,在適當的時候需要載入外部的FYHook,才能夠正常執行。

而這個地方所說的可執行檔案就是MachO檔案(具體什麼是MachO,這不是本片文章的重點內容,可以持續關注筆者之後的文章,下一章詳細介紹這至關重要的MachO),我們可以利用工具MachOView來檢視MachO中到底有什麼內容。

Step 3 MachOView

MachOView.png
點選這裡下載:MachOView 提取碼: n3hy

用MachOView開啟FrameworkDemo的MachO,可以看到如下圖

檢視MachO.png

可以看到其中的有個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命令了

yololib.png

以下命令就是將FYHook注入WeChat的命令

// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook
複製程式碼

3、程式碼注入

Step 1 建立重籤指令碼工程

新建工程,取名InjectFrameWork,過程可參照上一篇文章(APP重簽名) 最後得到如下工程:

重籤工程.png

Step 2 建立Framework檔案

新建一個Framework檔案,取名FYHook,在FYHook中新建檔案InjectCode,在InjectCode加入之前提到的同樣的load程式碼, 等到如下工程:

建立Framework(3).png

Step 3 修改原始檔的MachO檔案

找到WeChat的MachO檔案,開啟終端,進入此目錄下 執行命令

// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook
複製程式碼

yololib注入成功.png

Step 4 重新打包WeChat.ipa

zip -ry WeChat.ipa Payload
複製程式碼

重新打包WeChat.ipa.png

Step 5 加入新的WeChat.ipa,執行工程

將新得到的WeChat.ipa重新加入APP檔案(這一步其實可以只加入檔案,而不用加入工程),刪除原來的Wechat7.0.2越獄.ipa。

新WeChat.ipa.png
新WeChat.ipa-2.png

common + R執行程式碼,會發現微信跑起來了,我們的來了,老弟?也被輸出了!

Step 6 新的思考

之前分析了我們建立了FYHook,但是沒有對MachO注入,得到的答案是來了,老弟?不能被輸出,WeChat能跑起來。
那麼如果我們對MachO注入FYHook,卻沒有建立對應的FYHook.framework,會怎麼樣呢?
這就留給大家思考,再去驗證了,有答案的同學也能下方留言,並說出原因哦。

4、 ViewDebug、LLDB、class-dump分析微信登入頁面

Step 1 ViewDebug

XCode跑起微信之後,跳轉到登入頁面,利用ViewDebug檢視具體的詳細的UI

ViewDebug.png
可以看到,登入按鈕是一個FixTitleColorButton物件,他的Target的名字存在地址0x280afaa40中,他的Action名字存在地址0x280afac00中。 用同樣的方法檢視賬號密碼的輸入框,會發現他們都屬於一個物件,叫做WCUITextField
賬號輸入框WCUITextField.png

Step 2 LLDB

利用LLDB檢視登入按鈕具體的Target和Action名稱

LLDB檢視Target和Action.png
得知: 登入按鈕處於WCAccountMainLoginViewController這個頁面之中 登入按鈕的點選方法叫做onNext

Step 3 class-dump

class-dump,是可以把Objective-C執行時的宣告的資訊匯出來的工具。其實就是可以匯出.h檔案。用class-dump可以把未經加密的app的標頭檔案匯出來。

點選這下載命令列工具:class-dump 提取碼:v5ku 同樣的,將class-dump拷貝到Mac的目錄/usr⁩/local⁩/bin⁩下,這樣我們在終端中就可以使用yololib命令了

class-dump目錄.png

執行命令將WeChat所有的標頭檔案匯出來。

// class-dump -H 「app的MachO檔案」 -o 「輸入的目錄」
class-dump -H WeChat -o /Users/dengbin/Code/GitHub/HookWeChat/InjectFrameWork/APP/WeChat-H
複製程式碼

class-dump.png
WeChat-H.png

Step 4 找到輸入框裡面的內容

利用文字工具,例如Sublime檢視WeChat的標頭檔案,找到前面發現的WCAccountMainLoginViewController

WCAccountMainLoginViewController.png

發現裡面確實有方法- (void)onNext;,還有長得很像賬號輸入框,密碼輸入框的物件_textFieldUserNameItem,_textFieldUserPwdItem

接下來就是找到密碼輸入框裡面的字串了,可以發現這兩個都是WCAccountTextFieldItem物件,所有我們繼續在匯出的檔案裡面找到WCAccountTextFieldItem

WCAccountTextFieldItem.png

在其中只發現一個tips物件m_labelTip,沒有發現對應的textfiled,但是可以看到WCAccountTextFieldItem是繼承於WCBaseTextFieldItem的,所以繼續查詢WCBaseTextFieldItem

WCBaseTextFieldItem.png

從這就可以看到一個m_textField物件,這是個WCUITextField物件,疑似我們的目標textField,繼續檢視WCUITextField

WCUITextField.png

果然,這就是一個UITextField檔案,那麼我們就可以通過text欄位取出其string。

接下來在用LLDB試試看,驗證下我們的猜想:
隨便在賬號欄輸入:qwerty
然後在密碼欄輸入:123456

po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"]
po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"]
po [(WCUITextField *)0x112163a00 text]
複製程式碼

其中第一個地址0x1128bbc00是在前兩部利用ViewDubg找到的。

找到輸入的密碼.png

可以發現最後確實找到了我們輸入的密碼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之前,我們加上我們自己的方法,比如程式碼中的,在賬號欄中直接輸入密碼。
執行後結果如圖:

執行結果.PNG

我這用的是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檔案進行詳細的講解。請持續關注,覺得有幫助的點個收藏,留言評估了哦。

相關文章