網絡游戲逆向分析-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
總結