使用x64dbg分析微信聊天函數並實現發信息


1.引言

我們知道微信現在不光在手機上很常用,在電腦也是非常常用的,尤其是使用微信聯系客戶和維護群的人,那這個時候每天都會定期發送一些信息,如果人工操作會很累,所以自動化工具是王道,本節就使用x64dbg讓你看看怎么完成發消息。本節完整源碼在github:https://github.com/15pb/wechat_tools

2. 網絡協議分析模型

首先我們講一些理論知識,在開發中,網絡通信的協議最常見的有tcp,udp,http等,而在通信時使用的模型(這里的模型說的是代碼執行方式)也不盡相同,我們在分析微信協議的時候第一要確定微信是什么通信協議,第二要確定使用的是哪種模型。第三再分析微信的私有通信協議完成調用。

2.1 PC微信通信協議的識別

PC端微信使用的協議我們可以通過對每種協議相關的API設置斷點來確定是哪個協議。一般PC端客戶端程序的通信協議常用的是tcp和udp。 

關於tcp,udp的API:

協議 函數
tcp send
udp sendto

Clipboard Image.png

2.2 通信模型的識別

知道了通信協議之后,再說說通信協議的模型。一般我們在開發網絡程序時,會采用兩種方式來與網絡進行通信,第一種是就是直接從UI獲取數據然后發送數據,第二種是有單獨的工作線程負責發送數據,兩種通信模型我把它們分別稱為同步模型,異步模型。 這兩種模型中異步模型是比較復雜的,為了方便大家理解,我們將兩種模型最簡單的雛形給大家梳理一下:

① 同步模型 

Clipboard Image.png

這種模型的優點在於UI操作完就可以立即發送,非常適合我們做逆向分析,通過棧回溯一般都可以找到字符串的蹤跡,從而找到發送消息的函數,剩下的就是分析其參數,完成調用即可。一些網絡負載不是太大的程序,比如普通軟件、2D網絡游戲,大多會采用這種方式,實時的獲取 

② 異步模型 

Clipboard Image.png

這種模型通常在UI線程中發送數據時會添加到一個隊列中,然后在工作線程中不停的從隊列中讀取數據,然后發送數據。在逆向分析時,我們要做的就是通過在send設置斷點,然后可以通過觀察send的參數緩沖區,再對緩沖區或是與緩沖區關聯的地址設置訪問或寫入斷點,斷到寫緩沖區,添加隊列的地方。之后在去找調用函數。由於這個過程比較復雜,有時需要多次設置斷點才可以找到我們想要的信息。 

3. 使用x64dbg分析微信模型與定位關鍵函數

基於上面的理論,我們實際去分析一下微信的通信模型。

3.1 使用x64dbg分析微信網絡發包線程

首先我們還是在send設置斷點,然后等斷下之后觀察堆棧窗口中有沒有敏感字符串,我們使用PC版微信中的文件傳輸助手來測試  

Clipboard Image.png

send斷下之后,我們查看堆棧窗口中的信息,觀察有無我們輸入的字符串

Clipboard Image.png

實際觀察會發現堆棧中沒有我們想要的字符串,一般這個時候可以大致確定發送數據的這個線程與UI線程不是一個線程,通信的模型屬於異步模型。

3.2 使用x64dbg定位UI線程的隊列添加

確定了異步模型,我們下一步做的就是在send的參數buf上設置硬件寫入斷點,看看哪里給這個buf寫入了信息,找到那個隊列信息。 

send函數斷下返回上層的代碼中,發現buf的傳遞經過了好幾層,而這幾層當中有一個地址中的內容是隨着消息的改變而變化的,所以我們可以對這個地址設置硬件寫入斷點,而不是buf。 

Clipboard Image.png   

我在圖中的04EEECA8地址設置硬件寫入斷點,然后重新發送消息,看斷下之后填充值的代碼,然后觀察堆棧信息,如果沒錯的話,這個堆棧應該是UI線程,其中應該能找到我們剛剛發送的字符串。

Clipboard Image.png

當我們設置了硬件寫入斷點,等斷點斷下時觀察堆棧,發現堆棧中並沒有剛剛輸入的字符串,觀察許久發現只有一些和發送消息有關的字符串

Clipboard Image.png

這個時候說明我們發送的信息可能被包裝起來了,因為程序會將我們的字符串放在結構體中或是某些數據結構中進行傳遞,只是查看堆棧可能看不到,需要查看堆棧中看起來像地址的值的內容,才可能找到。

3.3 使用x64dbg定位關鍵函數

我們剛剛在分析堆棧時發現的字符串:”/cgi-bin/micromsg-bin/newsendmsg” 看起來像是發生信息時信息的類型字符串。我們可以使用x64dbg查看模塊wechatwin.dll中的所有和newsendmsg字符串,在其上所有相關字符串設置斷點,然后再次發消息測試。    

Clipboard Image.png

 

 

以上的動圖可以看到,我們通過搜索newsendmsg字符串,定位到一處代碼,設置斷點后,再次發送消息,可以在堆棧中找到我們發送的內容。只要找到內容,其實離成功就不遠了。在堆棧中我們去尋找和內容有關的調用CALL,需要由下而上一一查看調用CALL的參數,分析之后,可以發現有一個CALL的調用參數非常適合我們的需求。其有5個參數,如下圖: 

 

 

Clipboard Image.png

 

 

上圖中的調用call 0x0F7F10C0應該就是發消息的代碼,看起來非常幸運。當我們查看call內部的時候發現有大量的混淆代碼,貌似這個函數被VM過了。查看wechatwin.dll模塊的區段果然有有一個VMP的區段。不管怎么樣,函數是定位到了,下一步就是調用函數了。

 

 

3.4 使用x64dbg分析關鍵函數的參數

 

 

定位到關鍵函數之后,觀察函數的參數,發現有5個參數。 

 

 

對每一個參數進行清除測試,即調試過程中分別將每一個參數清除,然后運行程序,發現參數4和參數5,可以沒有值,而參數1、參數2、參數3必須有值,根據內容可知參數2是微信用戶名,參數3是要發送的內容。而參數1看起來並沒有什么含義,經過測試發現,其實這是一個傳出緩沖區,其中存儲的是加密的數據信息,即我們發送信息的加密版本,由此也可知,0x0F7F10C0函數被VM的理由是其中有加密信息的代碼,即微信的私有加密通信協議。

 

 

Clipboard Image.png

 

 

不管怎么樣,參數現在基本定了,剩下的就是只要能調用這個函數,其實就可以最初的設想了。

 

 

4.使用C++編寫測試代碼

 

 

代碼使用的是一個MFC的DLL來完成的,我們只需注入到微信中,執行我們的代碼就可以了。我們可以根據參數編寫如下代碼:

  wchar_t* pUser1 = L"filehelper";         wchar_t* pContent1 = L"hello 15pb"; ​         wchar_t* pUser = (wchar_t*)&pUser1;         wchar_t* pPass = (wchar_t*)&pContent1; ​         char buf[0x3d4] = { 0 }; // 傳出buf         _asm {             push 1              // 參數5             push 0              // 參數4             push pPass          // 參數3:發送的內容             push pUser          // 參數2:用戶名 ​             lea eax, buf             push eax            // 參數1:傳出buf             mov eax, 0x0F7F10C0             call eax         }

 

 

使用上面代碼會發現程序會出現異常,而出現異常的地方中,是在訪問字符串指向的結構里,上面的代碼微信用戶名只是一個字符串指針,其他並沒有,而觀察原本調用時傳遞的參數可以發現,這是一個字符串結構體,其除了字符串指針之外還有字符串的長度,緩沖區最大長度等等。所以我們需要將整個結構都定義出來,然后測試,耐心排查直到測試完成。這個過程需要不停的修改我們定義的字符串結構體才行,或者分析代碼中所有的引用點反推出字符串的結構。因此需要大量的時間才能最終完成。 
這里注意一下,在測試的過程中,總結下來有兩個需要注意的問題。第一,參數2和參數3都是二級指針且參數2和參數3是一個字符串結構體而非就一個指針,第二,參數1是傳出參數。這三個參數傳對,就不會有問題了。 
經過測試以及對比內存中字符串周圍的信息,最后定義的字符串數據結構如下:

struct WXString {     int num;     wchar_t* pString;     int nLen;     int nMaxLen;     int n1;     int n2;     int n3;     int n4; ​     WXString(wchar_t* pStr) {         int len = wcslen(pStr);         pString = new wchar_t[len + 1];         memset(pString, 0, len * 2 + 2);         memcpy(pString, pStr, len * 2);         nLen = len;         nMaxLen = len + 2;         n1 = 0;         n2 = 0;         n3 = 0;         n4 = 0;     } ​     ~WXString() {         if (pString)             delete pString;     } };

 

 

而最后執行的代碼:

  WXString szUser(L"filehelper");     WXString szContent(L"hello 15pb");     char* pAddr = (char*)&szContent + 0x14;     char* pUser = (char*)&szUser.pString;     char* pPass = (char*)&szContent.pString; ​     char buf[0x3d4] = { 0 };     _asm {         push 1         push 0         push pPass         push pUser ​         lea eax, buf         push eax         mov eax, 0xF7F10c0         call eax     }

 

 

5. 測試結果

 

 

我們可以使用x64dbg的插件Scylla完成注入完成,為了測試方便,我們注入之后會顯示一個對話框,點擊對話框中的按鈕測試即可,執行我們上面的關鍵代碼:    

 

 

ceshi7.gif

 

 

6. 總結

 

 

在分析微信的發送消息的函數過程中,我們使用x64dbg的功能有軟件斷點、硬件寫入斷點、查找字符串、插件注入等等功能,而且在分析時用到了堆棧分析,找數據時會對數據窗口各種切換。總體來說想要從源頭一點一點實現本節的功能還是比較復雜的,祝大家好運!


免責聲明!

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



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