【原創】PC微信逆向分析のWeTool內部探祕

作者:zmrbak(趙慶明老師)

前言:

先不說微信在社交領域的霸主地位,我們僅從騰訊公司所透露的在研發微信過程中踩過的無數的坑,以及公開的與微信相關的填坑的源代碼中,我們可以感受到,單從技術上講,微信是一款非常偉大的產品。然而,偉大的產品,往往會被癡迷於技術的人送進實驗室大卸八塊,以參悟其偉大之所在!

WeTool,一款免費的微信社羣管理軟件,正是這羣癡迷於技術的人對於這個偉大的PC微信的研究成果。在微商界,這個軟件真可謂是鼎鼎大名、如雷貫耳。如果你還不知曉這個軟件,那麼你肯定不是微商界的人。如果你想對你的微信羣進行管理,而又不想花錢,也許這個軟件就是你最佳的選擇。當然,免費軟件的套路都是一樣的,WeTool“有意地”不滿足你的一些需求,會保留其中一部分功能。如果你有特殊的需求的話,當然是要付費的,那就購買“企業版”吧。

但是,對於一個對技術有強烈興趣的人來說,研究WeTool與研究PC微信一樣有趣,在這裏,我把它們兩個一起送進實驗室,一窺其中的奧祕!

微信中的WeTool

由於騰訊干預,目前WeTool免費版本已經不再公開提供下載。但,之前的舊版本仍然可以自動升級到最新版本。如果你想獲得WeTool這個軟件,我想,你應該知道該怎麼做了吧。如果你還是不知道,很抱歉,這篇文章對你來說太深奧了。那麼我對你的建議是:關掉這個網頁吧。

WeTool在啓動時,會檢查當前計算機上是否安裝了版本匹配的PC微信。倘若找不到,或者版本不匹配,WeTool會引導你到它的官網去下載一個版本匹配的PC微信(可能比較舊,但能用)。下載完畢後,需要你手動去安裝一下。

在WeTool啓動的時候,還會檢查微信的登錄狀態,如果微信還未完成登錄,WeTool會等待微信登錄之後,再開啓自己的管理界面。

這裏的問題是:WeTool是如何得知微信是否已經登錄了呢?

在這裏,我們使用PCHunter來檢查一下微信(WeChat.exe)的進程模塊。我們可以看到,在微信的進程中加載了一個特殊的DLL文件(WeHelp.dll),而它的父目錄是一個特殊的字符串:“2.6.8.65”,恰好與我們當前運行的微信版本一致。再上一層的目錄,“WeToolCore”,很明顯,這個文件是WeTool的一部分。恰恰是這個DLL文件幫助WeTool完成了與微信之間的各種互動。也就是說,WeTool通過WeHelp.dll這個文件,可以感知到微信的各種活動,當然也包括微信是否已經登錄等等…
在這裏插入圖片描述

窺探WeTool

在不經意之間關閉了WeTool之後,我們發現微信也被關閉。

這又是爲什麼呢?

如果你曾經用OD調試過軟件,你會發現當你的OD被關閉的時候,被OD所調試的那個軟件也被關閉掉了。因此,我們猜想,WeTool對於微信來說,應該使用的是類似於OD之於其他軟件相同的原理,那就是“調試”。

在WeTool管理你的微信的時候,你也會發現,這時候微信無法被OD所附加。其實,還是“調試”。當一個軟件在一個調試器的“調試”之下,爲了防止出錯,這個調試器會阻止自己對這個已經被調試中的軟件的進行調試。這進一步印證了WeTool對於微信的“調試”的事實。然而就是這麼一個“小小的”設置,就擊碎不少“小白”想調試WeTool美夢。

既然我們找到了WeTool對於微信的關鍵,那就是文件“WeHelp.dll”。那麼,我們就把這個文件請入我們的實驗室,讓我們把它拆開,細細探尋其中的一點一滴。

拆解WeTool

在動手拆解之前,我們還是先了解一下WeTool到底向我們的計算機上安裝了些什麼東東。順着桌面上的“WeTool 免費版”,我們找到了WeTool安裝的目錄,安裝目錄之下22個文件夾和84個文件。當然,讓我們比較感興趣的就是“WeChatVersion”這個文件夾,因爲它的名字與微信(WeChat)太讓人能聯想到一起了。
在這裏插入圖片描述
雙擊“WeChatVersion”,我們看到如下結果。恰好是用微信曾經的一個個版本號來做文件夾的名字。我們猜想,這個文件夾一定與這個版本的微信之間存在中某種聯繫。目前,我們可以得到最新的微信版本是2.6.8.68(此版本爲更新版;從騰訊官網可下載到的版本僅爲2.6.8.65),這裏恰好有一個以該版本號命名的文件夾“2.6.8.65”。
在這裏插入圖片描述
我們雙擊打開“2.6.8.65”這個文件夾。文章前面所提到的“WeHelp.dll”文件赫然在目。點開其他類似微信版本號的文件夾,同樣,每個文件夾中都有這兩個文件。唯一的區別就是文件的大小不一樣。由於我們使用的微信版本是2.6.8.65,那麼我們就針對2.6.8.65文件夾下的這個“WeHelp.dll”進行研究。通過二進制對比,我們發現該文件夾下的文件與微信中加載的“WeHelp.dll”爲同一個文件。
在這裏插入圖片描述
由此,我們得出結論:WeTool爲不同版本的微信分別提供了不同的WeHelp.dll文件,在WeTool啓動的時候,把WeChatVersion中對應與當前版本微信號的文件夾複製到當前Windows登錄用戶的應用程序數據文件夾中,然後再將裏面的“WeHelp.dll”加載到微信進程的內存中。

WeHelp解析

WeTool爲“WeHelp.dll”設置了一道阻止“動態調試”的障礙,這讓所有的動態調試器,在沒有特殊處理前,對它根本無法下手。如果能繞道而行,那何必強攻呢?於是我們請出靜態分析的利器——IDA PRO 32。注意,這裏務必使用32位版本的,因爲只有在32位版本中,纔可以把彙編代碼轉換成C語言的僞代碼。相比於彙編代碼來說,C代碼就直觀的多了。

打開IDA,選中GO,然後把WeHelp.dll拖入其中,接下來就是十幾秒的分析,解析完畢後,界面如下:
在這裏插入圖片描述
從IDA解析的結果中,讓我們很驚奇的是,居然未發現什麼加殼啊、加密啊、混淆啊等等這些對於程序版權保護的技術。也許是WeTool太自信了吧!畢竟WeTool是事實上的業界老大,其地位無人可以撼動。對於和微信之間交互的這部分功能來說,其實對於一個剛入門的、比較勤奮的逆向新手,只需經過半年到一年時間的練手,這部分功能也是可以完成。對於WeTool來說,其真正的核心價值不在這裏,而在於其“正向”的管理邏輯,以及自己後臺的Web服務器。在它的管理界面,各種功能實現裏邏輯錯綜複雜,如果你想逆向的話,還不如重寫算了,畢竟它都免費給你用了。當然,它自己後臺的服務器,你根本就碰不到。

從IDA解析的結果中,可以看到WeHelp中各個函數、方法,毫無遮攔地完全展示在眼前。而在右側的窗口中,按下F5,瞬間彙編代碼變成了C語言的僞代碼。 在這裏插入圖片描述
對於一個稍稍有一些Window API編程經驗的人來說,這些全部都是似曾相識的C代碼,只需簡單地猜一猜,就能看明白寫的是啥。如果還是不懂的話,那就打開Visual Studio,對照着看吧。這裏是DllMain,也就是DLL的入口函數。那麼,我們先創建一個C++的動態鏈接庫的項目,來對照着看吧:
在這裏插入圖片描述
fdwReason=1,恰好,DLL_PROCESS_ATTACH=1。一旦DLL被加載,則馬上執行DllMain這個函數中的DLL_PROCESS_ATTACH分支。就是說,DLL被加載後,下面這兩個函數會馬上執行。
在這裏插入圖片描述
鼠標雙擊第一個函數(sub_10003040),到裏面去看看這個函數裏面有啥,如下圖,它的返回值來自於一個Windows Api(桃紅色字體)——“RegisterWindowMessageW”,查看MSDN後,發現,原來是註冊Windows消息。
在這裏插入圖片描述
這不是我們最想要的,按ESC鍵,返回。鼠標雙擊下一個函數(sub_100031B0),頁面變成這個啦。很明顯,在註冊一個窗口類。對於一個窗口來說,最重要的就是它的回調函數,因爲要在回調函數中,完成對窗口的所有事件處理。這裏,lpfnWndProc= sub_10003630,就很明顯了,回調函數。
在這裏插入圖片描述
雙擊sub_10003630這個函數,窗口切換爲如下內容。除了第一條語句的if之外,剩下的if…else if…else if是那麼的惹人注目。每一個判斷之後,都調用了一個函數。而判斷的依據是傳入的參數“lParam”要與一個dword的值比較。我們猜測,這些函數大概是WeHelp和微信之間交互相關的函數吧。當然,這只是猜測,我們還要進一步驗證纔行。
在這裏插入圖片描述
sub_10003630這個函數,是窗口的回調函數,我們要重點關注。那麼,我們先給它改個名字吧。在函數名上點右鍵,選中“Rename global item”,我們取個名字叫“Fn_WndProc”吧。於是頁面就變成了這樣:
在這裏插入圖片描述
雖然在IDA中,函數全部顯示出來了,但是也有40多個呢,我們找個簡單一點的來試試。CWeHelp::Logout(void),這個函數沒有參數,那麼我們就選這個吧。在左側函數窗口中雙擊CWeHelp::Logout(void),右側窗口換成了這個函數的C語言僞代碼(如果你顯示的還是彙編,請點擊彙編代碼後按F5)。
在這裏插入圖片描述
在前面,我們看到在回調函數中,lParam要與一個dword值進行比較。在這個函數中,我們發現,這裏爲lParam賦了一個dword類型的值。爲了方便記憶,我們把這個dowrd值改個名字吧,因爲是Logout函數中用到的數字,那麼就叫做“D_Logout”吧。
在這裏插入圖片描述
接下來,我們要看看”還有誰”在用這個數值。在我們修改後的“D_Logout”上點右鍵,選擇“Jump to xref…”。原來這個數值只有兩個地方使用,一個就是當前的“Logout”函數,而另一個卻是在”Fn_WndProc”中,那不就是前面的那個窗口的回調函數嘛!選中“Fn_WndProc”這一行,點擊OK!
在這裏插入圖片描述
又一次看到了熟悉的if…else if…,還有和“D_Logout”進行比較的分支,而這個分支裏面只調用了一個函數sub_10005940,而且不帶參數。
在這裏插入圖片描述
雙擊函數“sub_10005940”後,發現這個函數很簡單。核心語句只有兩條,首先調用了sub_100030F0函數,然後得到一個返回值。接下來,爲這個返回值加上一個數值“0x3F2BF0”,再轉換成一個函數指針,再給一個0作爲參數,再調用這個函數指針。最後返回結果。
在這裏插入圖片描述
我們這裏要關注,來自於“sub_100030F0”函數的返回值result到底是什麼?

同樣,雙擊這個函數(sub_100030F0),進去看看唄!原來,調用了一個Windows API函數(GetModuleHandleW),查看MSDN後,發現原來這個函數的功能就是取微信的基址(WeChatWin.dll)。
在這裏插入圖片描述
那就簡單多了,是不是說,如果我們在微信中執行“((int (__stdcall *)(_DWORD))(weChatWinBaseAddress + 0x3F2BF0))(0);”這麼一句代碼,就可以實現Logout功能呢?當然,我們需要驗證。打開原來創建的C++的動態鏈接庫項目,把 case分支DLL_PROCESS_ATTACH換成如下內容:

case DLL_PROCESS_ATTACH:
	{
		DWORD weChatWinBaseAddress = (int)GetModuleHandleW(L"WeChatWin.dll");
		((int(__stdcall*)(DWORD))(weChatWinBaseAddress + 0x3F2BF0))(0);
	}

注意:把IDA中拷貝過來的代碼裏的“_DWORD”中的下劃線去掉,就可以編譯通過了。
在這裏插入圖片描述
啓動微信,登錄微信(這時候,手機微信中會顯示“Windows微信已登錄”)。

使用OD附加微信(確保WeTool已經退出,否則OD附加不成功)。

在OD彙編代碼窗口點右鍵,選擇”StrongOD\InjectDll\Remote Thread”,選中剛纔Visual Studio中編譯成功的那個dll文件。 在這裏插入圖片描述
一秒鐘!OK,神奇的事情發生了:微信提示,你已退出微信!

同時,手機微信上原來顯示的 “Windows微信已登錄”,也消失了。從這裏我們可以確定,微信“真的”是退出了,而不是崩掉了。
在這裏插入圖片描述

總結:

其實逆向研究,並不只是靠苦力,更重要的是強烈的好奇心和發散的思維。也許一個瞬間,換一下思維模式,瞬間一切都開朗了。一個人的力量是有限的,融入一個圈子,去借鑑別人的成功經驗,同時貢獻自己成功經驗,你會發現,逆向研究其實是非常好玩的一件事。當然,我研究的後編寫源碼都是公開的,你可以到GitHub(https://github.com/zmrbak/PcWeChatHooK)上和我一起研究和學習。

後記:

2019年3月17日,本人對WeTool進行過探索,始終沒有取得進展。時隔2月後,突然有所發現,於是在2019年5月29日將我的探索成果錄製成一個個視頻,分享給和我一起研究和探索微信的好朋友,在他們中激起了強烈的反響。其中有不少的朋友的進展迅速,還有幾個朋友短短几日就遠遠超越了我的研究進度。看到這樣的場景,讓我的內心充滿歡喜。當然,還有不少朋友的評價,更是讓我開心,現摘錄如下:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

源碼分享:

https://github.com/zmrbak/PcWeChatHooK

交流QQ羣:

456197310 PC微信HOOK逆向分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章