2019年8月11日 星期日

Counter Strike Source - Aimbot

這篇是關於射擊遊戲的自動瞄準技術介紹,那麼什麼是自動瞄準 ? 顧名思義就是將射擊的準心自動移到敵人的頭部,有玩過射擊遊戲的人,多少有聽過此類外掛,然而卻不知道自動瞄準的外掛是如何製做的,接下來我們就準備探討它的相關技術。

自動瞄準實現方法大至如下:

1. Hook DirectX函式:DirectX是Windows提供的繪圖API (Application Programming Interface),遊戲開發者可以藉由這些API就能輕易完成繪製3D的圖形,因此我們攔截繪製人物模型的API,並且計算人物模型在螢幕上的座標差,這樣就達到自動瞄準的功能。

2. 計算敵人的頭部座標:獲取敵人和自己的座標以及滑鼠移動的弧度值(控制滑鼠移動的弧度),然後計算自己與敵人的弧度差,再將計算好的值,覆寫到滑鼠移動的弧度值裡,這樣就能輕易的瞄準敵人的頭部。

3. 分析Damage的結構:找出子彈射擊目的地座標,在發射前,將此座標改成敵人的頭部座標,就能完成自動瞄準。

我們已經知道自動瞄準實現方法有哪些,那麼此篇主要是說明利用Hook DirectX來完成自動瞄準,因為此方法不只能使用到單一的射擊遊戲裡,它亦可兼容其它的射擊遊戲,另外它用到的技術也比較特別,因此是本篇介紹的重點。

一、Hook DirectX

我們需要Hook DirectX如下:

1. DrawIndexedPrimitive:繪製3D模型的API (由於DirectX也有其它繪製3D模型的API,因此要確認此遊戲是使用哪種的API)。

2. EndScene:當繪製完成時,最後都會調用此API,來結束繪製此場景。

DrawIndexedPrimitive參數說明,此API有6個參數,不過我們只需要關注會用到的參數就好。NumVertices是繪製模型所使用的頂點數量,primCount是所使用的圖元數量,利用NumVertices和primCount來找出當前是在畫人物的模型還是場景的模型,這些資訊可能還不夠,因為還是有可能會遇到重複的問題,在保險一點可以使用GetStreamSource,其中它可以獲取在繪製圖的一些詳細的資訊,例如Stride是每個頂點所佔的記憶體空間大小,有了這些資訊就能判斷當前所畫的模型。

EndScene是說明繪製在Backbuffer已經就緒完成,但是還沒被替換成Frontbuffer,因此我們的自動瞄準程式碼放置在此,是在適合不過的。

二、找出人物的模型對應

在撰寫自動瞄準前,我們需要知道哪些模型是人物還是場景,因為我們要瞄準人物的頭部,所以需要判斷是否為人物的模型。

我們可以利用D3DXSaveTextureToFile的API來判斷人物模型的NumVertices、primCount和Stride,這邊要注意一點就是,每個人物在不同的距離會使用不同的NumVertices、primCount。



三、獲取Surface

我們需要利用CreateOffscreenPlainSurface和SetRenderTarget,幫助我們將當前的人物模型寫到Buffer,然後我們還要再撰寫掃描Buffer的座標,如下圖有三個人物模型在我們的Buffer,那麼從Buffer取值,如果是0就代表並不是人物模型的座標,反之非0,就代表此座標就是人物模型,接下來再計算瞄準頭部座標即可。



四、判斷人物是否在可視範圍

人物如果被牆或障礙物擋住,我們不能去瞄準它,因此我們需要利用3D模型的Z Buffer,將人物的Z Buffer關閉,此物件會被視為在平面上,任何的建築物都擋住不了它,那麼如果開啟Z Buffer,然後再獲取Surface,就可以判斷人物是否有被建築物擋住。

這是被建築物擋住的人物模型,並且畫上紅色的Texture。



如果沒有被建築物擋住,我們就畫上綠色的Texture。



藉由Z Buffer,我們可以輕易的判斷人物是否有被建築物擋住,如果沒有,我們就會將準心自動移到人物的頭部。



五、實作Aimbot

在實作Aimbot時,在不同的距離也能保持準度是相當不容易,因此會測試在不同距離是否也能精準的爆頭。