1. 程式人生 > 其它 >網路遊戲逆向分析-3-通過發包函式找功能call

網路遊戲逆向分析-3-通過發包函式找功能call

網路遊戲逆向分析-3-通過發包函式找功能call

網路遊戲和單機遊戲的分析有相似點,但是區別還是很大的。

網路遊戲和單機遊戲的區別:

網路遊戲是需要和伺服器進行互動的,網遊中的所有功能幾乎都會先發送封包資料到伺服器,然後有伺服器做出判斷後反饋給客戶端,客戶端才會產生對應的相關功能。

找功能call的辦法:

由於網遊和單機遊戲的區別,所以在網路遊戲中要尋找功能call可以通過在發包函式處下斷點來回溯找功能call。

相當於伺服器是一個皇帝,客戶端每想幹什麼事情前都得先給伺服器進行互動,直到伺服器同意才行。

大概是以下這個邏輯:

那麼通過發包函式往上找,就可以找到可能是真實的吃藥函式,當然也可能是吃藥函式到發包函式的中間過程,但是沒有關係能呼叫就好。

發包函式:

Windows的socket發包函式總共有三個:

//ws2_32.send
int WSAAPI send(
SOCKET s,
const char *buf,
int len,
int flags
);
int WSAAPI WSASend(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
int WSAAPI sendto(
SOCKET s,
const char *buf,
int len,
int flags,
const sockaddr *to,
int tolen
);

尋找喊話的功能call

首先查詢發包函式,然後給發包函式打斷點後再喊話,來檢視是呼叫的哪一個發包函式。

這裡通過查詢後,發現只有send是可以斷下來的,WSASend和sendto都沒有用。

但是這裡的send和我們想的不一樣:

它打上斷點後一直就卡這裡,還沒有喊話就斷在這裡了。

這裡就需要引入一個新的內容:心跳包。

心跳包:

心跳包顧名思義,字面意思是按照心跳來發包,實際意思就是每時每刻都給伺服器發個包,藉此伺服器可以用來檢測,比如你是否還線上,是否掉線了,或者你有沒有幹別的壞事之類的,時刻讓客戶端和伺服器保持聯絡。

心跳包的特點:心跳包只需要有特定的驗證字元就好了,不需要發一堆東西來浪費資源,所以心跳包的長度len一般都比較小,而且長度是固定的。

還好這裡心跳包頻率不快,還是會隔一會才心跳的,還是可以按照之前的邏輯來找函式call。

假設:A呼叫B,B呼叫C,C呼叫發包函式,那麼發包函式執行到函式返回再往上一條的call指令就是call的發包函式,然後再在呼叫發包函式這裡使用執行到函式返回再往上一個指令就是call呼叫C函式,這樣一直往上找六到七個函式來先分析一下看看

這裡採用xdbg的辦法來給每個函式上註釋,通過找到發包函式,然後執行到函式返回回到上一層,然後這樣來實現往上找函式。

通過xdbg的檢視->註釋可以檢視到自己新增的註釋的位置,以此來方便檢視。

通過從send 到1然後到8從下往上給函式打斷點,打完斷點後人物再喊話來找到函式的call函式。(可以在註釋這個視窗打斷點)

打完斷點後還得測試,測試是否是隻有喊話的時候才會停下來,否則就不能用,這裡我是在對應註釋3這個函式找到的唯一可以在喊話後斷下來的函式。

找到喊話功能call函式後進行分析

前面我們找到了喊話的函式,現在對其進行分析,一個函式必不可少的有,返回型別,函式引數的結構。返回型別不太好說明,但是函式引數可以先考慮,首先分析函式引數:

進入這個函式檢視,最後有一個ret10,而且前面也給開闢的堆疊平衡了,說明函式的引數棧空間有十六位數的 10個,就是十位數的16,在看該函式前面有四個push,說明就是有四個引數了。

分析這四個引數來解剖該函式:

首先這裡有4個push和一個mov ecx,eax。前面在學習反彙編C++的時候就得注意這個ecx,ecx很有可能是類裡面的this指標,所以這次給第一個push edx打斷點然後一直分析到呼叫函式:

edx == 00000000
ebx == 00000000
ecx == 字串的首地址
edx == 6A1E8600
ecx == 2334FD68
//前面的edx ebx ecx edx都是入棧,ecx應該是一個物件的值把,這裡猜測一下。
//然後再多呼叫幾次看看有啥變化
//結論是不管多少次都只有ecx == 字串首地址這個值做了變化

這裡先利用程式碼注入器試一下:

注意:這裡需要在一個空白的地方先放置字串的資料,因為一會要用到字串的首地址:

但是跟我們輸入的字串不一樣,很有可能是編碼的問題,這裡改成unicode試試:

這樣就ok了。

但是這個同樣也只能臨時用一下,所以還得往上找基址。

需要找的只有edx和ecx,因為別的都是0,或者是記憶體裡的字串,還有一個就是call的地址是一個靜態地址也不用找。

就用前面的教程繼續找edx和ecx的基址:https://www.cnblogs.com/Sna1lGo/p/14897870.html