遊戲對戰平台,在沒有瞭解的情況下,總是給人一種很神秘的感覺,然而,當你對socket的理解到達一定程度之後,你就不會再覺得神秘。
用一句話來總結這種技術:虛擬區域網路(VLAN)。
實現這種平台,主要是用戶端,而用戶端有很多種方法,就我所瞭解,可以用面三種方法實現:
1. 替換Windows socket DLL,然後,你想做什麼就做什麼吧。
2. 進程注入,HOOK WinSock函數調用。
3. 虛擬網卡驅動。
其實,前兩種技術,也是許多木馬使用的方法。正所謂技術是一面雙刃劍,看你要用到什麼地方了。現在的對戰平台,就我瞭解,使用的是後兩種方法。大多數是第2中----畢竟,驅動在有些使用者權限下是無法安裝和使用的。
浩方,QQ對戰平台,VS等,基本上都是採用第二中方法。第三種方法,見過一個。效果還可以。
下面介紹一下我研究時寫的平台結構:
整個平台包含兩個組成部分:服務端和用戶端。
通訊方式:全部採用UDP通訊。
零、基礎知識:
如果你有志與開發這樣一個類似平台,我建議你先瞭解以下內容:
a. Windows協議棧的簡單瞭解。
b. WinSock通訊。
c. HOOK技術。
d. 線程,進程之間的資料交換和通訊。
e. 線程之間的同步。
f. 線程注入。
e. 其它的一些Windows開發的基礎知識,就不一一列舉了。
這些都是基本功,基本功如何,決定了你能走到哪一步。
一、服務端:
伺服器在邏輯上被分為了兩部分:
a. 使用者服務器: 虛擬IP分配,使用者管理,訊息通知等。
b. 轉寄伺服器: 進行必要的資料轉寄(無法進行P2P通訊的)
二、用戶端:
用戶端也包含兩個部分,
a. 用戶端EXE: 負責進行進程注入,與伺服器通訊。
b. 用戶端DLL: 負責進行socket函數替換和處理。
註:這裡,伺服器和用戶端都有KeepAlive的功能,如果在一定時間內未收到包,則認為使用者已經掉線。
三、主要工作流程:
這裡主要對使用者登陸和登出,啟動和離開遊戲這連個主要環節進行總結。
a. 使用者登陸過程
+-------------------------------+
| 輸入使用者名稱和密碼,登陸 |
+-------------------------------+
|
+-----------------------------+
| 發送登陸包到伺服器 |
+-----------------------------+
|
+-----------------------------+
| 處理反饋資訊 |
+------------------------------+
|
<登陸成功> ------------失敗-------------> [提示使用者]
|
+------------------------------+
| 請求其他線上使用者資訊 |
+-----------------------------+
使用者登陸資訊用戶端處理流程
+--------------------+
| 收到使用者登陸包 |
+--------------------+
|
<資料解析>----------------> [丟棄不合法資料包]
|
<驗證使用者登陸資訊> -----------失-敗-------+
| |
| |
+----------------------------+ +---------------------------------+
| 分配虛擬IP地址 | |反饋登陸失敗資訊到用戶端|
+----------------------------+ +-------------------------------+
|
+--------------------------------------+
| 添加使用者到線上使用者列表 |
+--------------------------------------+
|反饋使用者登陸成功,伺服器資訊|
| 到用戶端 | (* 這裡包含了轉寄伺服器資訊)
+--------------------------------------+
|
+------------------------------+
|廣播資訊到所有登陸使用者|
+-----------------------------+
使用者登陸資訊服務端處理流程(由使用者服務器處理)
b. 使用者登出過程
+--------------------+
| 收到使用者退出包 |
+--------------------+
|
<資料解析>----------------> [丟棄不合法資料包]
|
+----------------------+
< 尋找將使用者資訊 > ------------> 未找到,不處理
+---------------------+
|
+----------------------------------------+
| 將使用者從線上使用者列表中刪除 |
+---------------------------------------+
|
+------------------------------------+
| 回收虛擬IP給其他使用者 |
+-----------------------------------+
|
+-------------------------------------------+
| 廣播使用者登出資訊到所有線上使用者 |
+-------------------------------------------+
伺服器處理過程
<判斷使用者是否在遊戲中> -----------是------------> 提示使用者
|
否
|
+-----------------------------+
| 發送登出包到伺服器 |
+-----------------------------+
|
+-------------------------+
| 退出 |
+-------------------------+
用戶端處理過程
c. 遊戲啟動過程
+--------------------------+
| 建立記憶體共用 |
| (CreateFileMapping) |
| 寫入遊戲當前配置 |
| (包含線上使用者資訊和 |
| 轉寄伺服器資訊) |
+--------------------------+
|
+-----------------------------+
| 根據使用者選擇啟動遊戲 |
| (調用CreateProcess) |
+----------------------------+
|
<是否啟動成功> ------------否----------> [提示使用者失敗資訊]
|
+-----------------------------+
| 將遊戲DLL注入到遊戲 |
+----------------------------+
|
+--------------------------------+
| 讀取遊戲的配置資訊 |
+-------------------------------+
|
+-----------------------------+
| 串連轉寄伺服器 |
+-----------------------------+
|
+--------------------------------------+
| 遊戲DLL HOOK所有網路函數 |
| (採用Inline Hook方式) |
+-------------------------------------+
|
+----------------------------------+
| OK, now game start OK! |
+----------------------------------+
d. 遊戲退出過程
+----------------------------------------------+
| 遊戲DLL釋放所有已經HOOK的函數 |
+---------------------------------------------+
|
+-----------------------------------+
| 關閉記憶體共用檔案 |
+-----------------------------------+
|
+--------------------------------------+
| 發送退出包到轉寄伺服器 |
+--------------------------------------+
四、遊戲DLL工作過程:
整個平台運作過程中,最主要的部分恐怕就是這個部分了,所以,單獨將這部分的結構進行一下說明。
在這裡,我將處理過程分成了三個層,每個層分別完成不同的功能:網路HOOK層,自訂協議棧,網路資料轉送層。
首先,HOOK所有上層的網路函數調用,然後交給自訂協議棧進行處理,處理完成後,如果需要發送資料,則交由下層的網路發送層進行發送。
+----------------------------------------------------------+
| |
| 網路函數HOOK層: 主要負責網路函數的替換 |
| 並且交由下層處理 |
| 這裡,其實也就是對於WS2_32.dll中的 |
| socket函數進行替換。 |
| |
+---------------------------------------------------------+
| |
| 資料處理層:主要負責將上層的各種網路 |
| 函數功能調用進行處理。 |
| 舉個簡單的例子,當遊戲調用Socket函數 |
| 準備建立一個socket時,我們根據它的參數, |
| 內部虛擬出一個socket控制代碼給它。而實際的上 |
| Windows本身並不知道這個調用過程。 |
| |
+-------------------------------------------------------+
| |
| 真實網路傳輸層:在這一層,才是真正的將數|
| 據包進行封裝和發送的過程 |
| |
+-------------------------------------------------------+
其實,整個用戶端只建立了兩個socket,一個用於和伺服器通訊的socket,另外一個就是在遊戲DLL中建立的一個和轉寄伺服器以及遊戲之間通訊所使用的socket。
這裡重要的就是中間的那層,主要就是對於socket調用中的每個函數進行類比。這個就需要各位自己去瞭解了。我不可能也沒有能力把每個都描述出來。
其實,這裡的第二層處理也可以不採用我的這種方法,可以採用協議替換法,比如,當遊戲調用socket函數要建立一個IPX socket時,你可以修改其中的參數,變成UDP,然後調用Windows真實的socket函數。
五、主要的技術痛點:
a. 類比Windows Socket。
這個技術點,說起來就比較多了。我們知道Windows有六中socket模型,我們必須類比出來大部分的模型(根據遊戲所使用的模型不同而需要類比的模型就不同)。
根據我的跟蹤和測試,說說現在瞭解的幾個遊戲所使用的socket模型和協議類型:
《紅色警戒》: 使用了簡單的WSAAsyncSelect模型。(IPX協議)
《星際爭霸》: 使用了Select 模型。(IPX, UDP協議,根據使用者的參數)
《暗 黑》: 使用Select模型。(使用TCP協議)
《反恐精英》: 使用Select模型。(使用TCP, UDP協議)
《冰封王座》: 似乎使用了IOCP Socket模型。這個還不是很清楚。(使用TCP,UDP兩種協議)
b. 改進UDP資料通訊的可靠性。
整個平台中,所有通訊全部使用的是UDP,所以,這點很重要。如果我們的遊戲中採用了TCP通訊,我們在類比的時候就的保證所有資料都能被對方收到。
六、開發後記:
去年的時候,我寫過一個英文的對戰平台研究,現在看看,那簡直是垃圾!可能是那是比較浮躁,對於什麼東西都沒有瞭解清楚。一年後,再回過頭來看我寫的那些代碼,真是慘不忍睹。現在,我覺得自己心靜了很多,技術上也成熟了許多。想說的就是Windows開發,我可以算是入門了吧!呵呵!
整個平台,只是在我的機器上進行測試和開發,難度比較大。工程。現在,我也只對《紅色警戒》, 《星際爭霸》, 《暗黑》三個遊戲測試通過。感覺一個人開發實在太累了,而且,這些東西都是經過一次次的AV錯誤一步步調試出來的,想想那些歲月,真是不堪回首!暫時不想再繼續下去了。等什麼時候有精力和時間的時候再來處理吧。
很多時候,為了能夠調試通過一個函數,我不知要經曆多少次的遊戲重啟過程。基本上MSDN上的大多數socket函數已經被我翻了個遍,每個函數的參數,傳回值等都的瞭解。
為了瞭解Windows實現socket的原理,閱讀那份據說是Win2K的源碼(如果你想閱讀的話,到網上搜尋一下,解壓後大概有700M),關於socket的那部分代碼在/win2k/private/net/sockets/winsock2/wsock32目錄下(估計是WS2_32.dll的源碼),讀了很多內容,也瞭解了一些東西,也讓我知道以後怎麼去寫socket程式。現在我有時寫代碼寫累的時候,還會去看點Windows的源碼,挺有意思的。像gina的實現,CommCtrl的實現等。
代碼大概已經寫的至少有一兩萬行了,基本上都是我在EditPlus/NotePad中一個字母一個字母敲出來的。暫時不想共用出來了,就分享一下原理篇給大家。