前言
現如今,有很多游戲外掛軟體,它們可以修改游戲顯示的資料和內部代碼,來達到謀取利益的目的,在實作反外掛技術前,我先介紹一下常見的三種外掛:
1.模擬類外掛:該外掛可以說是最早的外掛了,它是往游戲發送偽造的按鍵訊息來模擬人的手工操作,實作的思路為:
1.在Ring3層使用SendMassage、PostMassage、keybd_event、mouse_event等向訊息佇列中發送按鍵訊息
2.使用回呼函式KeyboardClassServiceCallback和MouseClassServiceCallback往類驅動輸入摁鍵訊息,
2.內部Call呼叫外掛:使用逆向技術分析出游戲內部的匯編代碼,把里面對游戲玩家有利的函式作為外掛的實作功能,實作的思路為:
1.使用逆向工具,去除殼和里面的反除錯功能
2.分析游戲的使用程序、玩家自身的資訊、背包資訊、敵人資訊等
3.逆向分析出游戲的明文發包功能
4.根據游戲的明文發包函式和報文資訊分析游戲內部功能實作的函式
3.脫機外掛:分析出游戲客戶端和服務端之間的通信邏輯,使用自己發送和接受資料來跟服務端進行互動,實作的思路如下:
1.使用逆向工具,去除殼和里面的反除錯功能
2.逆向分析游戲中的匯編代碼,分析出加解密演算法及各種資源資訊
3.分析出登錄封包,獲取各種跟游戲相關的資訊
4.整合尋路演算法,實作掛機
保護call函式和基址資料
1.最近玩植物大戰僵尸和連連看等游戲的時候發現,這些游戲需要通過啟動程式才能正常運行,那么我突發奇想,如果在程式運行前,修改游戲中的部分代碼段資料,等需要運行游戲時再通過另一個程式恢復代碼段資料,那么就可以起到保護游戲的作用,

2.對于游戲外掛制作者,他們經常習慣性的使用OD工具和CE工具、ida工具等,找出游戲的基址資料(也為全域變數)和內部call,然后修改基址資料或者修改執行流程,呼叫內部call,那么在游戲運行前就對基址資料地址和某些call后接地址進行修改,等需要運行游戲時,再修改回基址地址和call呼叫的地址,就可以起到反外掛的作用,

3.接下來,介紹一下這樣做的作用:

4.簡單介紹一下實作的流程:
1.讀取PE檔案資訊到記憶體中,遍歷PE檔案中的代碼段,找到函式頭部地址和使用的全域變數地址;
2.在代碼段中,找出呼叫函式的call指令,把call后接地址進行修改,對于資料,找到使用全域變數的mov指令,修改地址運算元;
3.運行時,使用CreateProcess函式創建執行緒并掛起,然后恢復代碼段中的資料并運行行程

5.我開發了一款反游戲外掛工具(該工具及其原始碼可在文章末尾下載)來模擬這個程序,在檔案選擇框選擇要保護的PE檔案,把需要保護的函式及資料添加到左邊欄中,執行保護時,在PE檔案目錄下會生成已保護的PE檔案,點擊運行時,就能正常運行,


檢測代碼段
1.在游戲沒有運行之前,修改、添加或洗掉PE檔案的二進制資訊可以起到修改程式流程的作用,從而起到外掛的作用,實作的技術有:在代碼段的空白區域添加"洞穴代碼",修改OEP的值,讓程式跳轉到洞穴代碼;使用Inline HOOK執行外掛功能函式;修改代碼段中的跳轉指令和call后接地址,執行游戲內部匯編指令或者調動內部call等

2.在游戲運行時,通過外掛工具動態修改、添加或洗掉行程代碼段資料或者動態注入shellcode同樣也能起到修改程式流程的作用,那么需要校驗PE檔案和游戲記憶體資料就可以檢測出游戲外掛,

3.在實際運用中,可以計算出PE檔案的校驗值,存放在游戲第三方程式的資料段中或者存放在游戲的服務器端,那么在游戲運行前校驗PE檔案值和運行時動態檢驗行程記憶體,接下來使用工具來模擬這個程序:
1.選擇PE檔案計算PE檔案校驗值和記錄代碼段資料;
2.選擇需要校驗的檔案,同樣也計算出校驗值并比較是否變化;
3.選擇正在運行的行程,比較代碼段資料是否變化,

4.實作的思路為:
1.使用MD5演算法計算出前后PE檔案的校驗值,并進行比較;
2.先使用陣列存放PE檔案代碼段資料,后讀取行程記憶體中的代碼段資料,然后比較陣列資料是否相同

5.在游戲運行時,把游戲運行程序中使用過的函式及其相關的暫存器資訊存放在服務端,在服務端檢測函式的呼叫流程,就可以判斷游戲內部call有沒有非法呼叫,不過我這里模擬這個程序的方式是把函式運行時的資訊寫到日志檔案中,查看日志資訊來判斷游戲內部call是否被非法呼叫,

6.實作的思路為:
1.調式行程,回圈接受調式事件;
2.在剛開始調式時,把函式頭部修改為CC;
3.當發現中斷時,判斷發生中斷的地址是否為函式頭部地址,是的話,把執行緒背景關系資訊記錄在日志檔案中
//調式行程
DebugActiveProcess(pid):
//回圈等待調式事件
while (WaitForDebugEvent(&de, INFINITE))
{
......
PEXCEPTION_RECORD per = &pde->u.Exception.ExceptionRecord;
//觸發創建調式行程事件時
if (CREATE_PROCESS_DEBUG_EVENT == de.dwDebugEventCode)
//修改函式頭部
SetUserFunc(&de);
//觸發例外事件時
else if (EXCEPTION_DEBUG_EVENT == de.dwDebugEventCode)
//判斷觸發例外地址
if (OnExceptionDebugEvent(&de))
continue;
//繼續接受調式事件
ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);
}
HOOK檢測
1.現在,有各種各樣的HOOK技術,包括 InLine HOOK、IAT HOOK、API HOOK等,其中大部分需要注入dll來實作HOOK功能,那么游戲運行時,服務端或者游戲第三方程式可以檢測有無dll注入,有的話,及時清除掉,實作的思路為:
1.先記錄游戲運行程序中用的dll檔案名;2.游戲運行時遍歷行程使用的dll檔案名,若遇到不名dll檔案名,則進行釋放;

2.使用工具模擬這個程序:選擇行程,選中dll檔案所在目錄,點擊檢測dll,就可檢測出行程中是否有dll注入,

3.那么,除了檢測dll檔案外,還可以檢測 IAT表和函式內部代碼的跳轉指令來判斷游戲中是否有IAT HOOK或者InLine HOOK(跟API HOOK差不多,范圍比API HOOK小,我這里就不介紹了),實作的程序為:
1.選中游戲PE檔案后,定位到匯入表目錄,遍歷INT表中的_IMAGE_THUNK_DATA,通過里面的聯合體u1,來獲取游戲運行后IAT表中的函式地址;
2.選中行程,讀取行程記憶體中IAT表資訊并比較函式地址,不同則說明有 IAT HOOK;
3.對于InLine HOOK,讀取行程代碼段中函式區域的跳轉指令運算元,若發現跳轉到別的函式區域,則說明有InLine HOOK;


4.使用工具模擬這個程序:選中行程和PE檔案,再點擊 IAT HOOK按鈕或者InLine HOOK按鈕就可進行檢測,

多開檢測和動態調式工具檢測
1.現在的打金作業室可以同時開多個號來刷金幣,那么需要限制游戲多開,當動態調式行程時,在任務管理器中可以看到調式工具的主執行緒成了調式行程,那么調式器記憶體里面必然會有調式行程的記憶體資訊,那么找到調式工具后再查找里面是否含有游戲行程的記憶體資訊,若有則可以判斷,游戲處于調式狀態,

2.對于防多開,經常會用到下面的代碼,那么外掛制作者修改跳轉指令或者NOP掉匯編代碼就可以實作多開,為了防止這種情況,我這里把CreateMutex函式頭部修改為CC,使用調式器的方式不斷監控例外事件,當CreateMutex函式頭部觸發中斷例外時,獲取互斥體變數名(地址為:ESP+8),并判斷該變數名是否出現過,若出現過,則檢測出行程出現多開,實作的關鍵代碼如下:
//創建互斥體
HANDLE hMutex = CreateMutex(NULL,FALSE,"XXXXXX");
DWORD dret = GetLastError();
if(hMutex)
{
if (ERROR_ALREADY_EXISTS == dret)
{
CloseHandle(hMutex);
return 0;
}
}
.............
//WaitForSingleObject(hMutex,INFINITE);
............
ReleaseMutex(hMutex);
return 0;
}
檢測多開的關鍵代碼:
//解除HOOK 恢復原值
WriteProcessMemory(&pde->dwProcessId, g_pCreateMutex,&g_Orignal,sizeof(BYTE),NULL);
//獲取執行緒背景關系
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(g_cpdi2.hThread,&ctx);
//得到ESP+8的值
ReadProcessMemory(g_cpdi2.hProcess, LPVOID(ctx.Esp + 0x8), &EspContent, sizeof(DWORD), NULL);
printf("EspContent: %x\n", EspContent);
//取出地址并獲取字串
Name[NameNum++] = (char*)(EspContent);
//判斷有無重復互斥名
list<string> list1;
for (int i = 0; i < NameNum; i++)
{
list1.push_back(Name[i]);
}
int len1 = list1.size();
list1.unique();
int len2 = list1.size();
//長度不等,則有重復元素
if (len1 != len2)
{
IsOpenMore = 1;
return -1;
}
//讓EIP為當前地址
ctx.Eip = (DWORD)g_pCreateMutex;
//設定執行緒背景關系
SetThreadContext(g_cpdi2.hThread, &ctx);
//繼續調式
ContinueDebugEvent(pde->dwProcessId, pde->dwThreadId, DBG_CONTINUE);
3.對于多開檢測,我還想出了三種檢測方法:
1.獲取行程代碼段資訊,使用代碼段資訊匹配的方式來判斷是否有相同的行程運行;
2.獲取行程所有的視窗句柄,匹配查找有無跟視窗標題相同的視窗,有則說明多開;
3.對行程名進行匹配;


4.對于調式工具檢測,還是使用代碼段識別法:獲取OD工具中代碼段資訊匹配尋找相同行程,若有,則再識別內部有無游戲行程的記憶體資訊并且再判斷調式行程是否為調式工具的子行程,兩者有一成立,則說明游戲行程處于調式狀態,實作的關鍵代碼如下:
void ToolAndOpenMore::GetToolCode(BYTE* ToolCode, CString strPath)
{
//把PE檔案加載到記憶體中
PVOID PeBuffer =PEFileToMemory(CStringToCharSz(strPath));
//PE檔案頭
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)PeBuffer + pDosHeader->e_lfanew + 0x4);
//節表數量
DWORD SectionNum = pPEHeader->NumberOfSections;
//PE可選頭
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
DWORD EP = pOptionHeader->AddressOfEntryPoint;
//代碼段節表頭
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
tpSectionHeader = pSectionHeader;
int j = 0;
//遍歷OEP之后的代碼段資料
for (int i = tpSectionHeader->PointerToRawData; i < tpSectionHeader->PointerToRawData + tpSectionHeader->SizeOfRawData && j<SZLEN; i++)
{
if (DataHs.FoaToRva(PeBuffer, i) < EP)
continue;
ToolCode[j++] = *((BYTE*)((DWORD)PeBuffer + i));
}
return;
}
5.接下來,使用工具進行檢測:多開檢測只需選中行程點擊“多開檢測”按鈕即可;調式工具檢測要選中行程和調式工具,操作情況如下所示:

添加反調式法
1.在游戲的PE檔案中添加反除錯,不為是一種較好的反外掛方法,在PE檔案中修改TLS表資訊,擴大最后一個節表并在空白區域添加PIMAGE_TLS_DIRECTORY結構資訊、TLS回呼函式,并在TLS回呼函式中添加反除錯功能即可實作反除錯,

2.實作反除錯的思路為:
1.把PE檔案加載到記憶體中,使用偏移的方式定位到TLS資料目錄,修改其中的 RVA欄位值和Size欄位值,讓 RVA指向PIMAGE_TLS_DIRECTORY起始地址;
2.定位到最后的節表結構并增加SizeOfRawData的值和修改Characteristics的值,使最后的節表具有可執行特性,
3.最后把生成的PIMAGE_TLS_DIRECTORY結構資料和回呼函式ShellCode復制到最后的節表中,

3.除了往PE檔案添加TLS反調式外,還可以添加SEH反除錯,實作的思路為:
1.先在代碼段,尋找足夠大的空閑區域,若沒有找到,則新增最后節表大小;
2.確定空閑區域開始地址,修改OEP的值,在空閑區域添加觸發SEH例外的Shellcode,在該Shellcode中有例外處理函式,該例外處理函式會判斷游戲是否處于調式中,如果沒有處于調式狀態則跳回OEP中,否則中止;

4.接下來使用工具添加反除錯,選中檔案,點擊按鈕即可,

以上使用的工具和原始碼可在該處下載:https://github.com/chenpan01/Anti_GameAssist,希望該工具及原始碼對大家有所幫助,工具存在bug的話,歡迎提出,大家共同探討,共同提升!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/297586.html
標籤:python
