PC微信逆向分析のWeTool內部探秘


作者:zmrbak(趙慶明老師)

前言:

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

WeTool,一款免費的微信社群管理工具,正是一群痴迷於技術的人對於微信這個偉大的產品的研究而得到的成果。在微商界,這個軟件真可謂是鼎鼎大名、如雷貫耳。如果你還不知曉這個軟件,那么你肯定不是微商界的人。如果你想對你的微信群進行管理,而又不想花錢,也許這個軟件就是你最佳的選擇。當然,免費軟件的套路都是一樣的,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”文件與微信中加載的“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解析的結果中,讓我們很驚奇的是,在“WeHelp.dll”中居然未發現什么加殼啊、加密啊、混淆啊等等這些對於程序版權保護的技術。也許是WeTool太自信了吧!畢竟WeTool是事實上的業界老大,其地位無人可以撼動。

對於和微信之間交互的這部分功能來說,其實對於一個剛入門的、比較勤奮的逆向新手,只需經過半年到一年時間的練手,這部分功能也是可以完成。對於WeTool來說,其真正的核心價值不在這里,而在於其“正向”的管理邏輯,以及自己后台的Web服務器。在它的管理界面,各種功能實現里邏輯錯綜復雜,如果你想逆向的話,還不如重寫算了,況且它都已經免費給你用了,還有必要逆向嗎!!當然,WeTool后台的服務器,你根本就碰不到。

從IDA解析的結果中,可以看到WeHelp中各個函數、方法,毫無遮攔地完全展示在眼前。而在右側的窗口中,按下F5,瞬間匯編代碼變成了C語言的偽代碼。


對於一個稍稍有一些Window API編程經驗的人來說,這些全部都是似曾相識的C代碼,只需簡單地猜一猜,就能看明白寫的是啥。如果還是不懂的話,那就打開Visual Studio,對照着看吧。這里是DllMain,也就是DLL的入口函數。我們還是來創建一個C++的動態鏈接庫(dll)的項目,來對照着看吧:


fdwReason=1,恰好,DLL_PROCESS_ATTACH=1。一旦DLL被加載,則馬上執行DllMain這個函數中的DLL_PROCESS_ATTACH分支。也就是說,當“WeHelp.dll”這個文件被微信加載到進程之后,馬上執行一下DllMain函數,DLL_PROCESS_ATTACH分支里面的這兩個函數就會馬上執行。



鼠標雙擊第一個函數(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中,“WeHelp.dll”中的函數(方法)全部顯示出來了,但是也有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上下載,也歡迎和我們一起學習和研究。

后記:

2019年3月17日前,本人對WeTool進行過一些探索,始終沒有取得進展。時隔兩個月之后,突然有所發現,於是在2019年5月29日將我的探索成果錄制成一個個視頻,分享給和我一起研究和探索微信的好朋友。結果,在他們中激起了強烈的反響,有不少的朋友的研究進度有了一個飛躍性的發展,還有幾個朋友短短幾日之間,就遠遠超越了我的研究進度。看到這樣的場景,讓我的內心充滿歡喜。當然,還有不少朋友的評價,更是讓我開心.

源碼分享:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM