Hook MSN Messenger之socket通訊的鳥事

如果要問我這幾天怎麼都沒寫blog,那除了正在搞DirectShow的心得分享外,卡在另一個API hooking上的問題,肯定是主因了。

這問題是怎樣的呢?話說我用API hooking的方式,試著掛上winsock API中的函式-recv()。其主要目的是要聽取MSN Messenger所傳送的所有訊息。程式寫好後,在自己的電腦上跑的也好好的,不過丟到另一台電腦上去,嘿,可怎麼都不會動。

接著開始漫長的診斷程序,我發現其餘的函式像send()sendto()都可以成功的掛上去,但就是recv()recvfrom()掛不上去。於是開始胡思亂想,猜想會不會是這台機器中毒了啊?請出了BirdmanArchon,也掃不出個所以然。

不過,就在快要絕望的時候,曙光竟然出現了-我發現,Messenger 7.5可以掛的上去,但Live Messenger不行啊。這是個好消息,經過反覆實驗後,發現的確如此。好,那問題就回到為什麼Live Messenger不行?難不成它用的不是recv()這個blocking的函式,而是non-blocking版本的WSARecv()嗎?

試著掛上WSARecv(),的確有反應,但截錄到的訊息並不是MSN用來傳遞訊息之用的。這這真是令人絕望啊。

等等,在hook函式時,我指定的是ws2_32.dll,也就是Winsock 2中的函式,而不是wsock32.dll,也就是Winsock 1.1中的函式,這Live Messenger該不會用的是Winsock 1.1中的函式吧?這也不對,因為讓我們先來看一張圖:

基本上整個Winsock API的發展,如果從Winsock 1.1講的話,首先要提的是針對當時仍是16 bits作業系統(Windows 3.1)的Winsock 1.1應用程式。當時以winsock.dll提供16 bits的應用程式使用Winsock 1.1中的功能。到Windows 95問世後,得以出現32 bitsWinsock應用程式,為了與16 bitswinsock.dll區隔,另行提供了wsock32.dll。在wsock32.dll中,為32 bits的應用程式,提供了Winsock 1.1的實作。之後Winsock 2API推出(ws2_32.dll),自然進行了許多的加強,但基於Winsock的遺產龐大,勢必處理相容Winsock 1.1的問題。而處理的最佳方式,自然是利用Winsock 2中的API來提供原先Winsock 1.1API的功能。所以我們可以在上圖中看到倘若在提供Winsock 2的環境上,Winsock 1.1的函式是基於Winsock 2而達成的。

所以幾乎可以猜想,wsock32.dll中的函式,最終大概就是會轉遞至ws2_32.dll中的函式,因為提供重複的Winsock實作是很奇怪也不合邏輯的事。這是為什麼我即使有點懷疑Live Messenger用的是Winsock 1.1中的函式,但還是繼續認為即便如此,我只要hookws2_32.dll就可以。

嘿,debug這回事呀,就是要捐棄所有的成見,放掉所有的偏見。當事情無論如何都不在你想要的軌道上運行時,就只能把大腦清成空白,然後把自己變成白痴,不受某些既定的推論影響,才能夠有所收獲。

所以最後一條路,就掛掛看啊。

天啊,就是它。當我把自己的recv()掛到wsock32.dll時,發現Live Messenger傳的訊息都收到了。

這要怎麼解釋呀?東西既然會動了,那就來找答案吧。

看看這篇:

http://www.dcsoft.com/private/winsock_api.htm

On WinXP, if you hook wsock32.dll, most of the API's are forwarded to either ws2_32.dll or to mswsock.dll.  Only a couple API's are handled directly.

是的,Only a couple API's are handled directly

我要的recv()該不會就是吧?

中整理了wsock32.dll中的每個函式究竟是自行實作,或是forwardmswsock.dllws2_32.dll

很不幸或很幸運的(因為我終於找到解釋了)

哈!夠鳥吧。wsock32.dll中的send()sentto()都是forwardws2_32.dll中的send()sendto()。但recv()recvfrom()卻都有自己的實作。這就是之所以之前hook ws2_32.dll中的recv()Live Messenger一直不能起作用的原因啊,因為它用的竟然是Winsock 1.1中的recv()而不是Winsock 2中的recv()

這整件事,從頭到尾都很詭異。為什麼7.5版的MSN Messenger用的是Winsock 2,但到了MSN Live Messenger後,反而用回了Winsock 1.1中的recv()。然後,為什麼Winsock 1.1中的recv()recvfrom()不像其他的函式一樣都forwardWinsock 2中的函式呢?這兩個謎團希望日後可以找到答案。

今天要開心的去睡覺了。