遊戲外掛是怎麼煉成的 原

本人曾經幫朋友開發了一款DNF外掛程序,其重要功能是使用賬戶列表中的用戶名密碼自動登錄DNF,後面的事情交給按鍵精靈完成。

外掛是一條黑色產業鏈,由於騰訊的保護程序相當強悍,如今要做出一個外掛將非常困難。外掛是怎麼贏利的?很多人瞭解的模式是直接把外掛賣給需要外掛的人。而在本例中,外掛的作用是給那些機器自動代打,獲取遊戲幣,再通過渠道將遊戲幣換成人民幣。運行這些代打機器的作坊有一個專用的名稱叫“工作室”。當然此工作室非彼工作室。這些工作室會購買最廉價的電腦,每臺電腦可以同時運行幾個對系統要求不高的遊戲,24小時不間斷自動代打,雖然有的遊戲會限制在線時間,但是由於賬號衆多,可以輪番使用。這些賬號從哪裏來的?有一批人專門會養號,然後再賣給工作室。

在早期,遊戲知名度比較低的情況下,遊戲廠商希望有更多的人氣,所以對工作室的行爲是睜一隻眼閉一隻眼。

言歸正傳,要實現自動登錄DNF,需要以下幾個步驟

  1. 清理系統緩存
  2. 選擇網卡撥號(多個寬帶賬號,防止被識別爲同一個使用者)
  3. 自動啓動DNF遊戲程序
  4. 選擇登錄賬號
  5. 啓動外掛主程序(通過啓動rootkit服務,隱藏外掛進程)

這些功能都沒有什麼太多技術含量,前期使用MFC開發,爲了開發方便,後面就轉成WPF實現。 守護程序

守護程序除了上述正常流程外,還有日誌記錄,通過郵件發送,自動重啓等功能。

自動登錄

外掛主程序用到了一個大名鼎鼎的大漠插件,而且使用該插件需要付費。付費後會給你一個dll文件。

首先,我們需要從配置文件中讀取遊戲大區數據,然後我們需要註冊大漠插件dm.reg()

然後,通過調用dm.find_wnd函數查找遊戲主窗口。找到後需要綁定主窗口,方便使用按鍵精靈進行自動點擊遊戲中的區域。

狀態自動機

在自動登錄的過程中,有些流程會有所變化,比如可能會彈出輸入驗證碼窗口,還有就是每一個步驟需要等待一個不確定的動畫等。所以就使用了狀態自動機去做。提前設置好每一種狀態在遇到特定動作的時候進入某一個下一個狀態。

確定當前步驟

如何確定當前畫面中是否有輸入框呢? 這就要用到dm的圖片匹配功能。我們事先將遊戲畫面中有特徵的畫面截取一小部分,作爲判斷依據。例如判斷是否是選擇大區的狀態。則用提前準備的截圖去匹配屏幕。 選擇大區截圖

總體流程就是,選擇服務器->選擇大區->輸入用戶名密碼->登錄成功。

驗證碼自動輸入

有時候登錄的時候會彈出輸入驗證碼,這驗證碼很變態,是四個輪流閃爍的圖。機器肯定無法識別。這時候就誕生了產業鏈中的另外一環,就是人工識別驗證碼。 打碼兔 在某個偏遠的地區,公司僱傭一堆平時沒事做的大媽,盯着屏幕發送過來的驗證碼,人工識別然後把驗證碼打入消息框傳回外掛程序中,程序再用按鍵精靈去打入驗證碼框中。 這個服務也需要付費的。所以外掛也是需要付出成本的。利潤會分配的產業鏈中的各個環節。

避免被騰訊保護程序查殺

騰訊的保護程序——DProtector會隨着遊戲的啓動而啓動,不可以被殺,否則遊戲不會正常運行。這個保護程序可以監控進程列表中的可疑程序,並阻止可疑程序的執行。那麼如何才能避免被它發現呢?這就需要用到流氓軟件360使用的技術了——驅動級編程!

進程保護驅動程序

驅動程序的權限很高,可以訪問系統內核,而普通程序則不行。所以很多計算機病毒都是驅動級的程序,查殺比較困難,普通的操作無法清除。 使用visual studio 開發windows驅動的時候,需要安裝WindowsKernelModeDriver8.1 工具集。配置類型選擇Driver。最後我們會生成一個sys文件。 在內核驅動中,我們可以偵測到對進程的所有的操作,我們可以篩選出需要保護的進程,當遇到諸如掛起進程,終止進程之類的操作的時候,我們可以攔截,這樣就無法終止該進程了。 無法中止進程

進程保護進階

還有更爲變態的方法,就是修改系統的SSDT表。

ssdt全稱爲System Services Descriptor Table,中文爲系統服務描述符表,ssdt表就是把ring3的Win32 API和ring0的內核API聯繫起來。SSDT並不僅僅只包含一個龐大的地址索引表,它還包含着一些其它有用的信息,諸如地址索引的基地址、服務函數個數等。

#pragma pack(1) //SSDT表的結構
typedef struct ServiceDescriptorEntry {
	unsigned int *ServiceTableBase;
	unsigned int *ServiceCounterTableBase; //Used only in checked build
	unsigned int NumberOfServices;
	unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; //變量名是不能變的,因爲是從外部導入
//這個是查詢某個函數的地址的一個宏
#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]

我們可以定義一個自己的函數,然後修改地址,讓系統調用API的時候調用我們自己的函數。

//修改 ZwOpenProcess 函數地址
	OldZwOpenProcess = (ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess));
	(SYSTEMSERVICE(ZwOpenProcess)) = NewZwOpenProcess;
NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL)
{//用來替換的新函數
	NTSTATUS nStatus = STATUS_SUCCESS;
	if ((long)ClientId->UniqueProcess == pid)
	{
		DbgPrint("保護進程 PID:%ld\n", pid);
		return STATUS_ACCESS_DENIED;
	}

	//剩下的交給我們的原函數
	nStatus = OldZwOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
	return STATUS_SUCCESS;
}

驅動程序安裝程序

驅動程序寫好了,我們還需要一個安裝程序去安裝這個驅動程序。這個也沒啥技術含量,就是一個自動化的過程,包括啓動驅動程序註冊好的系統服務,還有卸載功能。

反外掛

遊戲公司的反外掛和外掛之前就如同病毒和殺毒軟件一樣,是一個道高一尺魔高一丈的過程,上使用的這些手段,早已不是什麼新鮮玩意兒了。這場較量會一直持續下去,希望國家在這方面的法律能夠不斷健全,消滅灰色、黑色產業鏈,讓大家有一個健康的市場環境,把智慧用到正途上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章