中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

FPS游戲反作弊系統設計方法是什么

發布時間:2021-11-02 13:34:00 來源:億速云 閱讀:431 作者:iii 欄目:編程語言

這篇文章主要講解了“FPS游戲反作弊系統設計方法是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“FPS游戲反作弊系統設計方法是什么”吧!

游戲外掛常見注入方式

目前大部分游戲外掛不再是以前那種createremotethread + loadlibary注入方式了,因為大部分反作弊有自己的minifilter文件過濾驅動與imageloadcallback鏡像加載回調做判斷,大部分反作弊軟件在這種過濾鉤子中做這種操作:

if(!CheckFileCertificateByR3(FilePatch)){
  //把文件路徑傳回r3,r3判斷文件數字簽名是否在白名單數字簽名里面(比如微軟數字簽名),如果是白名單文件,就放行,如果不是白名單文件,就攔截
  //不是白名單文件...攔截
  block;
}
//放行
pass;

所以,外掛是特別難通過dll直接注入到游戲里面.因此大部分外掛通過一種 無文件落地注入方式 所謂無文件落地注入方式,就是直接在游戲進程里面開辟一個內存空間,把外掛的dll的shellcode寫入,之后手動修復輸入表,然后解析pe文件頭拿到dllmain,再通過createremotethread,apc或者hook方式讓游戲執行這塊內存地址,這樣子外掛就注入了

具體代碼如下(抄自google):

//以下代碼來自與谷歌搜索
void InjectorDLLByManualMap(const char* filepath, HANDLE hProcess)
{
    LPVOID lpBuffer;
    HANDLE hFile;
    DWORD dwLength;
    DWORD dwBytesRead;
    DWORD dwThreadId;
    ULONG_PTR lpReflectiveLoader;
    LPVOID lpRemoteDllBuffer;
    //打開文件
    hFile = CreateFileA(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    //得到文件大小
    dwLength = GetFileSize(hFile, NULL);
    lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwLength);
    //讀入文件
    ReadFile(hFile, lpBuffer, dwLength, &dwBytesRead, NULL);
    //修復導入表
    dwReflectiveLoaderOffset = GetReflectiveLoaderOffset(lpBuffer);
    //給游戲進程分配一段內存空間
    lpRemoteDllBuffer = VirtualAllocEx(hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    //寫入文件shellcode到分配的內存空間
    WriteProcessMemory(hProcess, lpRemoteDllBuffer, lpBuffer, dwLength, NULL)
    lpReflectiveLoader = (ULONG_PTR)lpRemoteDllBuffer + dwReflectiveLoaderOffset;
    //啟動進程
    CreateRemoteThread(hProcess, NULL, 1024*1024, (LPTHREAD_START_ROUTINE)lpReflectiveLoader, NULL, NULL, &dwThreadId)
}

其特點是:內存標志為PAGE_EXECUTE_READWRITE,MEM_PRIVATE,無文件,無模塊,不會觸發minifilter和imageloadcallbacks,無法通過正常方式枚舉到外掛模塊,隱蔽性非常高.

檢測內存加載外掛

之前的方法看起來非常的"無敵"實際上也是可以對抗的,因為其特征也非常明顯:

內存屬性為MEM_PRIVATE,內存標志為PAGE_EXECUTE_READWRITE.大小會很大.

所以檢測方法也有幾個:

1.暴力搜索PE頭,大部分這種內存加載的dll都有pe頭.一個內存屬性為mem_private居然還有pe頭,就說明是外掛了.目前大部分反作弊都有這個機制

外掛反制: 抹掉pe頭.不止pe頭,還可以抹掉一切pe特征.

2.createthreadcallbacks得到線程地址,判斷線程地址是否在一個內存屬性的mem_private的內存里面.如果是,說明就是外掛了.

外掛反制:不創建線程,使用hook方啟動外掛.

3.api調用回溯.顧名思義,外掛總要調用一些api地址的,我們可以通過回溯是誰調用了api地址,然后判斷這個調用地方內存屬性是不是mem_private.有兩種方法,一個是hook所有關鍵api,在hook部位用_returnaddres()得到調用地址(其實是讀ESP/RSP寄存器)第二種通過int3斷點觸發異常,使用異常處理函數處理這個異常,判斷調用者.

外掛反制: 第一種內聯hook方式,直接寫跳轉跳過hook,比如你hook的時候:

jmp 你的hook地址

push ebp

push eax

call xxxx;

外掛可以直接從push ebp調用,不再調用你jmp ,就可以繞過

第二種外掛反制目前沒有特別的能反制的地方.除非外掛自己構造api函數調用更底層的api.當然我們可以混淆原底層api的地址(無限套娃),具體以后在說.

實現調用回溯

為了實現調用回溯,我們需要實現如下步驟:

1. 設置異常處理程序去捕獲異常,代碼如下:

AddVectoredExceptionHandler

2. 拷貝原API地址到自己的內存區域,然后填充原API地址為int,代碼如下:

	LPVOID pHOOKAdress;
	pHOOKAdress = Megrez_GetProAdress(pszModuleName, pszProcName);
	vecInt3HookedAdress.push_back((DWORD)pHOOKAdress);		//用于檢測
	if (pHOOKAdress == 0)
	{
		return 0;
	}
	DWORD dProSize = 0;
	LPBYTE pTemp = (LPBYTE)pHOOKAdress;
	BYTE bTemp = 0;
	for (dProSize = 0; ; )
	{
		bTemp = *pTemp++;
		dProSize++;
		if (bTemp == 0xcc)
		{
			break;
		}
	}
	DWORD dFileSize = dProSize - 1;
	PVOID pNewAddr = VirtualAlloc(NULL, dFileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (pNewAddr == NULL)
	{
		return 0;
	}
	Megrez_SetMemoryAttr(pHOOKAdress, dProSize);
	memcpy(pNewAddr, pHOOKAdress, dProSize - 1);
	memset(pHOOKAdress, 0xcc, 1);
	memset((PBYTE)pHOOKAdress + 1, 0xc3, 1);
	memset((PBYTE)pHOOKAdress + 2, 0x90, dProSize - 1  -2);
	memset((PBYTE)pHOOKAdress + 2 + dProSize - 1 - 2 - 1, 0xcc, 1);
	//memset((PBYTE)pHOOKAdress + 2 + dProSize - 3 - 2 , 0xcc, 2);
	mapAdress.insert(pair<DWORD, DWORD>((DWORD)pHOOKAdress, (DWORD)pNewAddr));
	Megrez_SetMemoryAttr(pHOOKAdress, dProSize);
	Megrez_SetMemoryAttr(pNewAddr, dFileSize);

這樣子原api函數就會變成int3 當調用時候就回觸發int3異常 然后被我們的異常處理捕獲

3. 查詢異常位置內存信息,如果是meme_private者調用的代碼,則報告給服務端,代碼如下(記住,x32位下保存調用者地址的是esp,x64位下保存調用者地址的是rsp,):

        size_t sizeQuery = VirtualQuery((PVOID)caller_function, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION));
	bool non_commit = lpBuffer->State != MEM_COMMIT;
	bool foreign_image = lpBuffer->Type != MEM_IMAGE && lpBuffer->RegionSize > 0x2000;
	bool spoof = *(PWORD)caller_function == 0x23FF; // jmp qword ptr [rbx],這是為了防止被欺騙
	return sizeQuery || non_commit || foreign_image || spoof; //返回

處理完異常后,我們要跳到原來的保存的api內存里面正常調用(設置eip保存的內存地址)

 ExceptionInfo->ContextRecord->Eip = mapAdress[(DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress];
#ifdef DEBUG
        WCHAR _buf[256] = { 0 };
        swprintf_s(_buf, 256, L"eIP:0x%08X\n", ExceptionInfo->ContextRecord->Eip);
        OutputDebugStringW(_buf);
#endif
        //已經處理了異常要再調用下一個異常處理來處理此異常
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    //調用下一個處理器
    return EXCEPTION_CONTINUE_SEARCH;

可以看到,這樣子就得到了api調用者的信息,從而做出判斷.

FPS游戲反作弊系統設計方法是什么

這樣,一個能檢測出絕大部分內存加載外掛的東西就做好了(誰調用誰就會被檢測)

感謝各位的閱讀,以上就是“FPS游戲反作弊系統設計方法是什么”的內容了,經過本文的學習后,相信大家對FPS游戲反作弊系統設計方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

api
AI

青龙| 昭平县| 松江区| 石林| 元阳县| 临高县| 曲沃县| 元江| 苏尼特左旗| 阿克陶县| 肥东县| 江永县| 通辽市| 盐津县| 喀喇| 周至县| 岢岚县| 鄂伦春自治旗| 巫山县| 壤塘县| 昌平区| 都安| 安新县| 交口县| 碌曲县| 东源县| 庆城县| 盐津县| 福清市| 固原市| 利川市| 抚松县| 宁河县| 巴楚县| 郓城县| 石楼县| 吴川市| 永平县| 新干县| 洛川县| 喀什市|