iOS逆向(4)-代碼注入,竊取微信密碼

轉(zhuǎn)載:原文地址

利用LLDB對微信進(jìn)行分析,然后利用分析的結(jié)果,再逐步講解如何Hook微信的登錄過程,截獲微信密碼。

在上一篇文章(APP重簽名)中,已經(jīng)介紹了如何對APP重簽名,并且利用XCode將微信跑起來,既然到了這一步,就萬萬不能錯過強大的LLDB。這篇文章就講為大家講解到如何利用LLDB對微信進(jìn)行分析,然后利用分析的結(jié)果,再逐步講解如何Hook微信的登錄過程,截獲微信密碼。

老規(guī)矩,片頭先給福利:點擊下載Demo:HookWeChat,這次有兩份代碼。由于越獄版微信體積太大,受到github限制,所以并沒有將它傳到github,可以在下方鏈接單獨下載

文中所需要用到的工具和文件:
越獄版本微信7.0.2 提取碼: 2w87
MachOView 提取碼: n3hy
yololib 提取碼:e8qs
class-dump 提取碼:v5ku

接下來我們會從一下幾部,讓微信脫下看似安全的外衣,裸露在大家面前。

  • Framework的作用
  • 初探MachO (原理分析)
  • 代碼注入 (代碼過程)
  • ViewDebug、LLDB、class-dump分析微信登錄頁面(原理分析)
  • Hook登錄,自動獲取密碼 (代碼過程)
  • 總結(jié)

1、Framework的作用(對Framework熟悉的同學(xué)可以跳過這一步)

什么是Framework這里就不多加敘述,我參考這個網(wǎng)站,非常詳細(xì),看不懂你直接@我。點這里:Framework最強講解

廢話不多說,接下來直接演示如何創(chuàng)建一個Framework,并且介紹跟咱們Hook微信有關(guān)的基礎(chǔ)原理。

新建一個工程FrameworkDemo,新建一個Framework,取名FYHook

創(chuàng)建Framework(1)
創(chuàng)建Framework(2)

在新建出來的FYHook文件夾中新建InjectCode(繼承NSObject)對象,并且新建代碼:

+ (void)load {
    NSLog(@"來了,老弟");
}
新建InjectCode

直接運行,會發(fā)現(xiàn)來了,老弟被輸出,證明用這種方法新建的Framework能夠直接運行在我們的項目中。

NSLog字符串

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

根據(jù)上篇文章APP重簽名講到的,我們可以使用XCode將微信跑起來,那么是不是將兩者結(jié)合起來,就可以將我們的代碼注入進(jìn)微信的APP呢?

Step 1 先思考一個問題。

根據(jù)APP重簽名中的結(jié)論,利用腳本可以便捷重簽APP(因為我們用的WeChat舉例,所以下面簡稱WeChat),那么我們在重簽?zāi)_本的工程中,直接創(chuàng)建一個Framework,能不能讓我們Framework中的代碼在WeChat中運行?

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

Step 2 MachO作用

在我們用XCode新建HYHook的時候,其實XCode幫我們做了一部操作:創(chuàng)建HYHook時候,同時將HYHook鏈接到我們的項目中(這是后期的XCode新增功能,早年的XCode這一步是需要我們直接做的)

XCode自動鏈接

common+b Build一下,會發(fā)現(xiàn)在已經(jīng)Build出來的文件中的Frameworks下已經(jīng)有FYHook了,已經(jīng)已經(jīng)表明FYHook被Copy我們的ipa文件了。(如何看Build出來的文件?查看:APP重簽名中Step 8 App重簽名)

自動加入Frameworks已經(jīng)MachO文件

但是FYHook在ipa文件中,并不代表著FYHook就可以被我們的可執(zhí)行文件所執(zhí)行,因為FYHook并沒有沒導(dǎo)報入我們的可執(zhí)行文件,只有在這個可行執(zhí)行文件的某一個地方做好標(biāo)記,告知可執(zhí)行文件,在適當(dāng)?shù)臅r候需要加載外部的FYHook,才能夠正常運行。

而這個地方所說的可執(zhí)行文件就是MachO文件(具體什么是MachO,這不是本片文章的重點內(nèi)容,可以持續(xù)關(guān)注筆者之后的文章,下一章詳細(xì)介紹這至關(guān)重要的MachO),我們可以利用工具M(jìn)achOView來查看MachO中到底有什么內(nèi)容。

Step 3 MachOView

MachOView

點擊這里下載:MachOView 提取碼: n3hy

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

查看MachO

可以看到其中的有個Load Commons組,這里面就包括所有需要被動態(tài)加載的庫。也就是說,如果在Load Commons中沒有對應(yīng)的FYHook,就不會加載FYHook。

在上圖中可以看到FYHook已經(jīng)被加入了Load Commons,并且圖右側(cè)也標(biāo)記了FYHook所屬的目錄(和MachO文件同級的Frameworks下FYHook.framework中 ,FYHook.framework其實是個文件夾,里面的FYHook也是個MachO

所以這里就得到了「為什么我們直接將FYHook加入我們的從重簽?zāi)_本工程,不能直接運行FYHook」的答案。
因為在在我們Build出來的MachO文件中的Load Commons中沒有加入FYHook的路徑。所以無法運行FYHook中的代碼。

那么我們直接將FYHook加入我們Build出的MachO文件行嗎?
顯然也是不行的,因為我們Build出的MachO文件始終會被原始包(WeChat)中的MachO給替換掉。我們需要將FYHook加入原始包(WeChat)中的MachO中。

Step 4 將FYHook標(biāo)記入MachO中

這里我們就需要用到終端命令行工具:yololib 提取碼:e8qs

將下載下來的yololib.zip解壓后得到的yololib放在??目錄/usr?/local?/bin?下,這樣我們在終端中就可以使用yololib命令了

yololib

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

// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook

3、代碼注入

Step 1 建立重簽?zāi)_本工程

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

重簽工程

Step 2 創(chuàng)建Framework文件

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

創(chuàng)建Framework(3)

Step 3 修改源文件的MachO文件

找到WeChat的MachO文件,打開終端,進(jìn)入此目錄下
執(zhí)行命令

// yololib 「MachO路徑」 「FYHook相對MachO的路徑」
yololib WeChat Frameworks/FYHook.framework/FYHook

yololib注入成功

Step 4 重新打包WeChat.ipa

zip -ry WeChat.ipa Payload

重新打包WeChat

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

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

新WeChat.ipa
新WeChat.ipa-2

common + R運行代碼,會發(fā)現(xiàn)微信跑起來了,我們的來了,老弟也被輸出了!

Step 6 新的思考

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

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

Step 1 ViewDebug

XCode跑起微信之后,跳轉(zhuǎn)到登錄頁面,利用ViewDebug查看具體的詳細(xì)的UI

ViewDebug

可以看到,登錄按鈕是一個FixTitleColorButton對象,他的Target的名字存在地址0x280afaa40中,他的Action名字存在地址0x280afac00中。
用同樣的方法查看賬號密碼的輸入框,會發(fā)現(xiàn)他們都屬于一個對象,叫做WCUITextField

賬號輸入框WCUITextField

Step 2 LLDB

利用LLDB查看登錄按鈕具體的Target和Action名稱

LLDB查看Target和Action

得知:
登錄按鈕處于WCAccountMainLoginViewController這個頁面之中
登錄按鈕的點擊方法叫做onNext

Step 3 class-dump

class-dump,是可以把Objective-C運行時的聲明的信息導(dǎo)出來的工具。其實就是可以導(dǎo)出.h文件。用class-dump可以把未經(jīng)加密的app的頭文件導(dǎo)出來。

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

class-dump目錄

運行命令將WeChat所有的頭文件導(dǎo)出來。

// class-dump -H 「app的MachO文件」 -o 「輸入的目錄」
class-dump -H WeChat -o /Users/dengbin/Code/GitHub/HookWeChat/InjectFrameWork/APP/WeChat-H
class-dump
WeChat-H

Step 4 找到輸入框里面的內(nèi)容

利用文本工具,例如Sublime查看WeChat的頭文件,找到前面發(fā)現(xiàn)的WCAccountMainLoginViewController

WCAccountMainLoginViewController

發(fā)現(xiàn)里面確實有方法- (void)onNext;,還有長得很像賬號輸入框,密碼輸入框的對象_textFieldUserNameItem,_textFieldUserPwdItem。

接下來就是找到密碼輸入框里面的字符串了,可以發(fā)現(xiàn)這兩個都是WCAccountTextFieldItem對象,所有我們繼續(xù)在導(dǎo)出的文件里面找到WCAccountTextFieldItem

WCAccountTextFieldItem

在其中只發(fā)現(xiàn)一個tips對象m_labelTip,沒有發(fā)現(xiàn)對應(yīng)的textfiled,但是可以看到WCAccountTextFieldItem是繼承于WCBaseTextFieldItem的,所以繼續(xù)查找WCBaseTextFieldItem

WCBaseTextFieldItem

從這就可以看到一個m_textField對象,這是個WCUITextField對象,疑似我們的目標(biāo)textField,繼續(xù)查看WCUITextField

WCUITextField

果然,這就是一個UITextField文件,那么我們就可以通過text字段取出其string。

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

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

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

找到輸入的密碼

可以發(fā)現(xiàn)最后確實找到了我們輸入的密碼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]];
    //調(diào)用原來的方法
    old_onNext(self,_cmd);
}

稍微解釋一下,在前面我們發(fā)現(xiàn)登錄的響聲事件是onNext,所有我們利用Objective-C的Runtime特性,對onNext進(jìn)行方法替換,在響應(yīng)原有的onNext之前,我們加上我們自己的方法,比如代碼中的,在賬號欄中直接輸入密碼。
運行后結(jié)果如圖:

運行結(jié)果

我這用的是setIMP和getIMP的方式,對原方法進(jìn)行HOOK,其實方法有多種:如:class_replaceMethod(),method_exchangeImplementations(),這里只是舉一個例子供大家參考。

這篇文章的所有代碼都可以在這下載到:HookWeChat

6、總結(jié):

  • 先對APP重簽名,讓APP能在XCode運行起來
  • 利用yololib注入Framework,讓APP可以運行我們直接的代碼
  • 利用ViewDebug、LLDB、class-dump分析登錄事件和密碼框所在位置
  • 利用Runtime的MethodSwizzle,Hook登錄事件

這次只是簡單的微信的一個靜態(tài)頁面進(jìn)行了初步接觸,雖然思路簡單,但這運用到的工具,卻是無數(shù)大神前輩們?yōu)槲覀冧伜玫穆?,感謝!

MachO文件在本文中只是初略的提及,其實在我們逆向過程中MachO是一個至關(guān)重要的存在,如:

  • 對app的砸殼,其實就是對MachO解密
  • 所有的方法名,靜態(tài)字符串都是存在MachO中
  • app的架構(gòu)(arm64,arm7...)也是在MachO中區(qū)分的
  • app加載其實也是對MachO的一步步操作
  • ...

所以,在下篇文章,筆者將會對MachO文件進(jìn)行詳細(xì)的講解。請持續(xù)關(guān)注,覺得有幫助的點個收藏,留言鼓勵哦。

警告!
非越獄狀態(tài),玩逆向微信不要真的登錄,有被警告甚至封號風(fēng)險

轉(zhuǎn)載:原文地址


推薦文集

* 抖音效果實現(xiàn)

* BAT—最新iOS面試題總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容