逆向線上遊戲:建立一個包記錄器和編輯器

qq_27446553發表於2016-02-29

免責宣告:逆向獵龍遊戲完全出於學習目的,我反對本文提供的資訊被用於任何惡意行為,並且目前發現的所有漏洞已提交至Aeria遊戲或已經被修復。

0×01 概述

這篇部落格中,準備向大家展示如何逆向線上遊戲獵龍,為其建立一個包記錄器和編輯器。後續的部落格中可能會展示如何傳送我們自己的資料包。

 從資料包著手,可以做你想做的任何事情,包括尋找漏洞,相關功能函式。獵龍是一款Aeria Games開發的大型多人線上遊戲。儘管現今這些遊戲都捆綁了一系列的反作弊軟體,例如 nProtect、GameGuard、AhnLab、HackShield XIGNCODE3但事實上本文中的方法適用於任何遊戲

 這些反作弊軟體的功能類似防毒軟體,掃描已知型別的作弊手段如果你執行了任何這種型別的作弊軟體,反作弊軟體就會將遊戲關閉。這種軟體同時還有一個核心模式的驅動,阻止使用分析類軟體,例如Ollydbg或Cheat Engine,通過在ring0上HOOK某種API函式可以阻止在ring3上使用OpenProcess, ReadProcessMemoryWriteProcessMemory。(這些API函式經常用作分析)。更重要的是,這些反作弊軟體使用反除錯技術,掃描記憶體以確保反作弊軟體的程式碼不被修改,遊戲時刻被保護著。

繞過反作弊軟體最簡單的辦法就是阻止其執行,但是一旦不執行,就有95%的機率在1-5分鐘之內與遊戲服務端斷開連線。這是由於大部分的反作弊軟體會有一個叫做heartbeat packet來確保軟體時刻執行。服務端傳送一個資料包至客戶端,然後反作弊軟體呼叫函式執行演算法程式,返回一個正確的值,接著這個值再傳送至服務端。如果返回的資料不正確或者壓根沒有返回,此時就會斷開連線。這種工作機制類似於安裝軟體的許可證。如果你鍵入錯誤的Key,軟體不會執行。這些反作弊軟體的程式碼通常都是執行在虛擬機器下的位元組碼,導致這些演算法非常難以被逆向。

 更多細節,可以閱讀這些部落格:

http://www.unknowncheats.me/forum/index.php

https://mega.nz/#!8xkhFQJb!pSzoOHIqZqz5jIpQi39usyoGD2kHeTukwc4UU4b9P9c

獵龍遊戲是一款大型多人線上遊戲,不具備任何型別的反作弊軟體,也沒有包括很複雜的程式碼,因此這款遊戲適合作為逆向線上遊戲的教程,那下面開始吧。

注意:2016年1月28日更新後Aeria Games為獵龍遊戲增加了XIGNCODE3,如果你不知道怎麼繞過,那麼接下來的分析將不能完成。目前,不需要通過一個heartbeat包,只需找到XIGNCODE3的初識化函式,然後修改其中的程式碼導致其不能初始化即可。(在函式返回值前,植入mov eax,1即可)。

0×02 準備工作

熟悉 x86 彙編逆向工程以及 Win32 APIs

Aeria Games 賬戶 (http://aeriagames.com)

獵龍遊戲線上 (http://dragomonhunter.aeriagames.com/)

Ollydbg v1.10 (http://www.ollydbg.de/)

IDA Pro (https://www.hex-rays.com/products/ida/support/download_freeware.shtml)

通過SirmabusIDA函式字串 關聯到 外掛上

        (http://sourceforge.net/projects/idafunct ionstringassociate/)

Keygener Assistant v2.0 (http://www.softpedia.com/get/Programming/Other-Program ming-Files/Keygener-Assistant.shtml)

0×03 分析

警告:如果分析這些型別的惡意軟體,為了防止感染你的電腦應在VMware上執行。由於本次的軟體來源是可信的,因此可以放心執行。

再一次確保你的獵龍遊戲是最新版的。

圖片9.png 

開啟Keygener Assistant,點選scanning,在獵龍遊戲的安裝資料夾下找到Game.bin。請確保將“檔案型別”選為“所有檔案”,否則在在下圖的Keygener Assistant中不會找到該檔案(儘量它是.bin的副檔名,但是根據PE檔案頭,其實它是.exe檔案)。

圖片10.png 

Keygener Assistant顯示Game.bin檔案沒有加殼,同時指出了hash和加密特徵的偏移以及編譯器。下面通過IDA進一步分析。

圖片11.png 

根據IDA的分析,程式碼沒有被混淆。

圖片12.png 

輸入表也沒有混淆。

圖片13.png 

字串也沒有加密。

在多數情況下,如果分析的是惡意軟體,上述的步驟還需要做進一步的確認。

這個遊戲使用的是Gamebryo Game Engine (http://www.gamebryo.com/)來阻止遊戲被逆向的,根據我多年的經驗,斷定使用的是下圖IDA中相關的字串:

圖片14.png 

當我分析線上遊戲的時候,經常會用到IDA的字串關聯外掛。這個外掛可以在函式入口處建立引用字串的註釋。在IDA中,按ALT+F6,如下圖:

圖片15.png 

點選繼續,外掛開始分析。軟體的大小決定分析的時間。而這個軟體只有14MB,因此不會太久。之後你會看見函式引用字串的註釋:

 圖片16.png

所有就緒,我們開始建立包編輯器。問題是,從哪裡著手呢?傳送和接受資料包函式的路徑有太多太多。

一種方法就是找到一些成員的指標,例如遊戲人物的座標,這些可能存在資料包中併傳送至服務端。接著找到那個程式碼訪問該指標,移動你的人物角色,之後不斷跟蹤直到你找到傳送人物位置資料包的程式碼。

最好的辦法就是從結束的地方開始。我這麼說是什麼意思呢?在Windows上執行,資料包最後傳送的地方或者資料包剛開始接收的地方都會出現一個由WS2_32.dll匯出的Winsock函式。因此在這裡我會展示如何追蹤傳送加密資料包之前的函式,可能在以後的部落格中會展示如何記錄加密後的資料包。

Winsock Send APIs:

send (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740149(v=vs.85).aspx)

sendto (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740148(v=vs.85).aspx)

WSASend (https://msdn.microsoft.com/en-us/library/windows/desktop/ms742203(v=vs.85).aspx)

Winsock Receive APIs:

recv (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspx)

recvfrom (https://msdn.microsoft.com/en-us/library/windows/desktop/ms740120(v=vs.85).aspx)

WSARecv (https://msdn.microsoft.com/en-us/library/windows/desktop/ms741688(v=vs.85).aspx)

現在檢查這些函式的匯入表,(最簡單的方法就是在IDAlibrary中滾動查詢WS2_32)。

圖片17.png 

可以看到,遊戲使用WSASend傳送資料包,使用WSARecv接收資料包。

通過交叉引用功能檢視傳送資料包的函式。

圖片18.png 

可以看到兩個函式呼叫WSASend。檢視第一個函式。

圖片19.png 

如果WSASend返回值為-1即十六進位制的0xFFFFFFFF,將會執行WSAGetLastError,隨後從該函式返回一個0值,意味著返回錯誤,這樣由於資料包的錯誤導致遊戲關閉。如果WSASend返回0意味著資料包正確,發生跳轉繼續執行後續函式。

在WSASend函式的下面有一個WSAAsyncselect函式。我猜測可能這個遊戲在執行的時候不僅僅只開放一個連線,可能是兩個,因為有兩個函式呼叫WSASend。可以看到WSASend的buffer計數器引數一直是1,這個遊戲同樣可以使用WSAAsyncSelect讓遊戲知道資料包正確傳送了,這樣保持分組的順序讓下一個資料包繼續傳送。

在WSAAsyncSelect之前的“mov [esi+288Ch], eax”也很有意思。可能是一種互斥元素,或者網路資料結構或者是一個類,其他資料包傳送之前必須要被設定。

看看第二個呼叫WSASend的函式。

圖片20.png 

call    ds:WSASend

cmp     eax, 0FFFFFFFFh

jnz     short loc_F1E730

和第一個函式有些類似,如果向上回溯,可以看到另一個呼叫WSAAsyncSelect的地方

圖片21.png 

mov     [eax+288Ch], esi

我們又發現了這個指標+0x288C可能是網路資料結構或者類。通過Ollydbg的記憶體監視在這個地址處下斷點,能夠找到這個指標成員的值,接著回溯該網路成員指標。

這裡我使用的是Ollydbg的動態除錯功能。因此將遊戲附加至Ollydbg。

在WSASend處下斷點(使用OD的熱鍵F2即可)

圖片22.png 

通常我會通過遊戲的聊天視窗回溯。輸入Hello,點選enter,OD就會斷在WSASend,看到如下圖所示:(注意斷點時間不宜過長,否則就會斷開連線)

圖片23.png 

檢查一下資料包是否被加密了。跟蹤WSABUF陣列(pBuffers)在這裡是0x0018FC10。

這是一個WSABUF的結構,C++形式:

圖片24.png 

len是buffer的長度,buf是指向buffer的指標。這裡我們只有一個buffer,(nBuffers=1)這個陣列是這樣的:

0x0018FC10 (pBuffers) + 0×00 = the length of the buffer (0x0018FC10)

0x0018FC10 (pBuffers) + 0×04 = pointer to the buffer (0x0018FC14)

由於軟體是32-bit的無符號資料格式,總共4個位元組,因此要在這個基礎上加4得到Buffer地址,指向buffer同樣是一個4位元組的地址。

圖片25.png 

我們可以看到buffer大小為0×19十進位制為25。Buffer儲存地址為0x180c4940。在記憶體中跟蹤這個Buffer。我在聊天欄裡鍵入hello,因此在buffer中可以看到儲存的文字,如果這個值沒加密,我們的記錄傳送資料包的工作就可以結束了。

圖片34.png 

但是上述資料包中的資料看起來像是被加密的,因為在記憶體中沒有看到hello的ASCII。這個是現今線上遊戲的常見問題,目前還有很多遊戲是沒有加密資料包的。

圖片27.png 

在次鍵入hello之後,出現這種情況:

圖片28.png 

這個很有趣,顯示加密方案可能是一個初始化的vector (IV) 或者 starting variable (SV),這就能解釋為什麼輸入一樣而輸出確不能始終一樣,而且兩個buffer的前兩個位元組是相同的(0×17 0×00)。

嘗試鍵入hello1看看有什麼:

圖片29.png 

1700變為1800,這就說明前兩個位元組應該是資料包的大小。

現在我們知道資料包是被加密的,現在我們要嘗試找到加密前的buffer以及buffer大小,因此我們可以在這裡hook到傳送至伺服器的資料包。通常這個位置就在加密buffer函式之前。為了驗證,可以在WSASend上再下一個斷點,傳送聊天資料包,在棧中找到函式的返回地址。這個返回地址在棧頂,如下圖:

OD中顯示了這個函式來源自IDA分析的第二個函式,跟蹤這個函式直到看到這個函式的呼叫者。

圖片30.png 

如果資料包傳送成功,則函式跳轉至結束,如果繼續回溯是在WindowProc處結束。似乎我們能夠回溯到buffer是如何加密的點。

上述顯示這個遊戲是通過Window的訊息來通告一個資料包是否準備傳送或者已經被髮送。這種通過WSAAsyncSelect的訊息引數0x9C40傳送Windows訊息的途徑有很多種,在下圖可以看到,使用不同的訊息引數0x9C41可以呼叫PostMessageW。由於當資料包不傳送時,PostMessageW才會被執行,我就通過訊息0x9C41通知這個遊戲資料包沒有傳送。

在WSAAsyncSelect處下斷點。

 圖片31.png

在OD中找到WSAAsyncSelect,看下這個函式:

圖片32.png 

這個函式看起來有點意思,因為呼叫WSAAsyncSelect函式和指標,假設是網路資料結構或者類,這裡的ESI和WSASend的ESI一樣。

根據我的經驗和這段程式碼,這個呼叫約定是thiscall,因為網路指標在函式開始處通過ECX向ESI傳值,並且在函式結束處我們可以看到RETN 4。Keygen Assistant告訴我們遊戲是被MSVC++編譯的,這就意味著這個是this指標,同樣根據網路指標,傳入ECX,因此函式的功能是清潔棧空間。

如果閱讀彙編程式碼,第二個引數是一個指向結構體的指標。

在函式開始處下斷點,分析壓進棧區的引數。

圖片37.png 

在上圖可以看到指向結構體的指標,下面會解釋這個結構體,但是現在我們看看結構體的第二個成員:

圖片34.png 

可以看到加密前的資料包,buffer大小同樣是0×0017。在傳送hello資料包之前找到了該buffer。

這個結構體的第一個引數可能是buffer的hash或者一個ID用來後續整理的,第二個引數指向buffer起始地址,第三個引數指向buffer結束地址,第四個引數看起來應該是指向分配給buffer的記憶體結束的地址。如果將第三個成員和第二個成員相減(0x0E680279 - 0x0E680260)結果是0×19,這個就是最終伺服器讀取的包括頭兩個位元組完整buffer的大小。

為了確認這個buffer是加密前的,將hello修改為hello1,看下結果:

圖片35.png 

圖片36.png

現在看來,我們可以在資料包傳送至伺服器前修改buffer值,而在你接收聊天資訊前不會顯示任何訊息。

為了構造一個資料包記錄器,可以在讓程式跳轉至你的程式碼中列印資料包內容。這樣工作搞定!

0×04 可以做的事

現在已經可以成功修改資料包了,可以分析服務端和客戶端之間傳送的資料包。現在我們也可以傳送我們自己定義的資料包,甚至通過逆向工程可以建立自己的遊戲客戶端。通過向伺服器傳送不正常的資料包而無需通過軟體的開發者,通常就可以引發漏洞。你也可以根據資料包來回溯函式功能,例如聊天欄,人物移動資訊,購買條目資訊更直接的是直接呼叫遊戲功能而不通過按鍵的形式。

這裡我展示一個簡單的方法利用這個線上遊戲。大多數線上遊戲有一個swear的過濾系統,可以防止玩家互噴髒話。

例如,如果我在遊戲裡說shit,是這樣的:

圖片37.png 

圖片38.png

遊戲的過濾系統比較輸入的文字,如果是髒話則用垃圾字元代替,下面看看如果我將buffer修改為shit會怎樣:

圖片39.png 

圖片40.png 

現在客戶端繞過了過濾系統,顯示了shit。這個只是眾多可利用的一部分而已。當和其他玩家一起登入的時候有時會意外崩潰,當然這個漏洞幾小時之後就被修復了。

0×05 總結

個人認為遊戲公司以及其他任何一家公司,應該把更多的精力投入到自己的網路安全而且應當由伺服器來控制過濾器。總是會有人試圖利用,攻擊和黑掉這些安全性低的產品。遊戲公司經常收到不計其實的盜號,欺騙投訴從而導致玩家退出,這必然意味著虧損。

 然而不幸的是,大多數遊戲公司往往不願意在安全上開銷。他們經常通過反作弊軟體來抵抗攻擊。這種做法通常只能阻止比較低階的攻擊,這裡建議這些公司應更專注於自己的伺服器的安全性。

*參考來源:0xbaadf00dsec,FB小編老王隔壁的白帽子翻譯,轉載請註明來自FreeBuf黑客與極客(FreeBuf.COM)

相關文章