看雪編輯按:如今很大一部分人會透過遊戲來進行適當的娛樂放鬆,在這個過程中玩家最關心的就是遊戲的公平性問題,然而由於外掛的存在使得一些玩家輕輕鬆鬆就開啟了“上帝模式”,因此如何反外掛就成了眾多遊戲公司最頭疼的問題。但畢竟技術無止境,攻與防的江湖在今後很長一段時間內仍將延續下去,作為防守方,我們更多能做的是想辦法增大遊戲外掛的開發難度。本次議題是由騰訊遊戲安全中心胡和君為我們帶來的遊戲反外掛方面的安全實踐,相信能給相關工作者帶來一定的啟發。
胡和君
胡和君,騰訊遊戲安全高階工程師,現就職於騰訊遊戲安全中心,從事PC端遊戲安全相關工作8年多,涵蓋新遊戲安全評審、遊戲外掛分析與對抗、遊戲漏洞分析與應對、安全方案開發等方面,長期負責公司多款頭部FPS類遊戲安全對抗工作,積累了豐富的遊戲安全實踐經驗,尤其擅長定製化分析及應對FPS類遊戲安全風險。
胡和君:大家好,今天我分享的議題是“定製化對抗——遊戲反外掛的安全實踐”。我來自騰訊遊戲安全中心,09年就開始做穿越火線的外掛對抗,現在也是負責多款FPS類遊戲的安全工作。與透視、自瞄這樣的外掛功能對抗了8年,因此今天來分享一下在這8年的實踐中,積累的一些解決思路。
遊戲的抽象
定製化對抗是什麼?就是三個字母——IPO。看著好像挺熟悉,想想也挺激動。可是我這裡的這個IPO,並不是為了做公司上市的IPO,而是對遊戲的一個抽象。
遊戲被抽象成什麼呢?被抽象成為了一個輸入,一個輸出,和一個處理過程。遊戲其實也就是透過一些輸入,比如動動滑鼠、敲敲鍵盤、劃劃螢幕、或是搖搖手機。然後透過遊戲的一些邏輯或是處理流程,最終給到玩家一個反饋,比如移動了、攻擊了、成功了、失敗了、吃雞了等等。
而其實除了遊戲以外,其他任何的虛擬世界的一個場景或是一個是業務都是可以被抽象成一個IPO的過程。而我們的安全問題,其實也就是和這個IPO過程相關。
安全的問題,往往要麼是製造一些非法的輸入,比如透過精心構造的引數進行漏洞的觸發和利用,要麼是對中間過程進行一些篡改,比如病毒對系統的劫持感染,又或是對輸出的結果的攻擊,比如勒索病毒將正常的檔案進行加密,或是詐騙木馬將瀏覽器劫持訪問一些非法的網站。
對於遊戲來看,常見的一些外掛功能,比如模擬按鍵是針對輸入的攻擊、比如修改記憶體實現的秒殺無敵等功能是針對中間過程的攻擊、而透視這樣的外掛功能則是給遊戲的輸出進行了攻擊,讓你看到了本來不應該看到的東西。
通用的防禦
說到防禦,通常的方案往往是鑄建一個類似城牆的東西,把所有的各式各樣的攻擊攔截在外面,使得我們的遊戲或是其他業務邏輯的IPO能夠正常並順利的執行下去。
但是我們是知道的,天下沒有不透風的牆。所以世上沒有絕對的安全。那我們還可以怎麼做呢?自然就是需要將防禦方案深入到業務邏輯當中去,實施定製化的方案。
假設右圖是遊戲邏輯的一個抽象,而所謂的定製化對抗,就是在除了外城的圍牆以外,在具體的每個節點進行防禦。而每個節點自身其實也就是一個IPO的過程。所以所謂定製化的對抗,就是從最小單元的IPO所展開進行的,在每一個遊戲邏輯的節點以及遊戲的路徑上進行安全方案的防禦和安全方案的部署。
定製化對抗
下面就用FPS類遊戲常見的自瞄外掛對抗的一個例子,來介紹如何進行定製化方案的建設。因為要深入到遊戲邏輯中去進行防禦,因此我們先要對遊戲自身的邏輯進行IPO的分解。
遊戲的瞄準邏輯非常容易理解,且很簡單。其輸入就是滑鼠移動後的delta值,不同的遊戲對這個delta值的處理不一樣,而對FPS遊戲來講,其中間過程就是把滑鼠這類裝置輸入的delta值轉換為遊戲邏輯中的Rotation,可以理解為一個朝向。
如果形象一點來理解,可以把朝向認為就是現實生活中的腦袋。就是透過旋轉腦袋來改變視野,而當瞄準以後,也就是所謂的輸出,則往往是透過遊戲內紅名,或是人物描邊等方式來展現。
基於遊戲的邏輯
對遊戲的邏輯進行拆分以後,自然攻擊的方法也就非常的明顯。而我們防禦手段則可以依據攻擊方式進行見招拆招。
如何見招拆招?實際就是找不同,針對攻擊後的差異點分析。
首先,來看看輸入。直接秒想到的就是模擬按鍵。自瞄就是幫玩家瞄準,模擬按鍵就是一種幫忙的方式。而這種方式與正常的遊戲有什麼差異呢?最大的差別就是一種是真實按鍵,另一種是模擬按鍵。
不過判斷是否是真實安全的防禦檢測應該是外城牆所幹的事情。那從結合業務邏輯的角度來看,又有什麼差別呢?實際就是這個滑鼠移動的delta值的變化規律。
看看右圖的示例,假設要想控制滑鼠從A點移動到B點,對於模擬按鍵來看,這個變化規律是程一條直線,而人的正常移動則如第二個圖所示,會有抖動,不是那麼平滑。
我們只要透過獲取遊戲的滑鼠輸入資料,然後對移動數值進行建模就可以識別出人與機器的差別。當然,模擬按鍵也可以模擬人的滑鼠移動變得不是那麼的平滑,但是從最終的資料表現來看,人的不確定性和外掛的相對穩定性是一個非常明顯的差異。
在輸入這一層找到差異後,繼續往後,在中間過程這裡,沒有什麼影響,模擬按鍵的方式很難影響遊戲正常的Rotation轉換過程。但是到了輸出,也就是遊戲的表現層。則是很明顯自瞄的外掛比正常的玩家瞄得更準。
而這個準如何去判斷識別呢?可以從多個緯度去看,比如,因為瞄得準,因此殺人多,故KD比比較高,KD比也就是擊殺和死亡比。又比如因為瞄得準,所以爆頭率高。
因為FPS遊戲是兩兵相遇準者活,這個準除了指能命中,更深入一點就是命中部位。因此也可以針對命中部位的聚集性進行建模。瞄得準,那他的命中部位是會有更明顯的集中的。
然而在這個過程中可能也會遇到職業玩家的挑戰,因為水平高的玩家實際也就是瞄得準。所以接下來還需要看看正常瞄得準的和使用外掛瞄得準的差別,透過資料分析發現高手玩家瞄準和開槍這兩個步驟是一氣呵成的,非常連貫。但是作弊玩家這兩個環節往往容易出現分離,也就是中間會有時差。總之就是按照找不同的方法去進行,一定可以發現作弊與非作弊的差異。
至此,模擬按鍵方式實現自瞄的找不同也就結束,對應的我們主要也就形成了基於delta的變化規律檢測方案,結合擊殺、命中部位、開槍時機等資料的準度識別檢測方案。接下來我們再看看攻擊方式,除了針對輸入層進行攻擊以外,針對中間過程也是一個很直接的攻擊手段。大家也很容易想到,那就是可以透過修改記憶體,直接修改Rotation數值來達到瞄準的效果。
修改Rotation數值的方式在遊戲邏輯側有什麼差別?
從輸入層來看,因為修改中間過程靠後因此對輸入無影響。而從輸出來看其實也就是和前面提到的模擬按鍵的最終效果一致。結合開槍、命中、擊殺的準度識別檢測方案也能夠有所覆蓋。而重點來看中間過程這裡,實際最大的影響就是滑鼠移動的delta到Rotation的計算結果發生了變化。
這個計算結果怎麼去防禦呢?
一種常見的檢測方法就是進行影子變數的檢測方案。將遊戲計算的結果進行加密備份,在遊戲使用的時候,把使用的數值與備份的解密數值進行比較。加密的原因是使得原始的數值在記憶體中不是那麼容易的被發現。
在這個過程中,如果發現數值有變化,表明了Rotation數值被進行了修改。當然這種方法會比較有效,但是也有弱點,一方面攻擊者可以透過破解加密演算法,而同時修改你備份的數值。另一方面攻擊者可以直接修改計算邏輯,使得我們加密備份的數值自身就是遊戲被修改過邏輯的程式碼所產生的,這樣也就感知不到異常。所以一種相對更完備的方式則是進行Rotation的數值自計算。
安全方案作為純的旁入,獲取滑鼠移動的delta,然後透過與遊戲同樣的計算方式殘生Rotation數值,最後對比數值的差異。而這種方案對逆向還原能力的要求是非常高的。對遊戲中所有參與計算Rotation的邏輯都要進行精準的還原,否則就會導致方案的誤判。這樣針對修改Rotation的攻擊方式,進行了三層的大家來找茬以後,整體又新增了影子變數與朝向數值自計算方案。
接著我們再來看針對輸出層可以如何攻擊。在這裡實際就是直接修改瞄準的這個結果了。明明朝著門,確告知遊戲瞄著人。這個相對而言更容易識別。只需要在開槍的時候,把子彈的朝向與角色的朝向進行對比就好了,因為如果不開槍,這種方式的作弊也沒有任何收益。而但凡開槍,那麼遊戲中的異常表現就更是明顯。
越是表現層的差異,對遊戲作弊發現來看越是容易進行檢測。所以基於輸入-中間過程-輸出的方法,我們定製化的防禦,就做到了以上5個基本方案的部署。
基於外掛的實現
然而,這並不算完成,除了知己還需要知彼。接下來需要從外掛功能實現的角度,再進行IPO的拆解,可以發現還有很多事情可以做。
從自瞄外掛的實現角度,很容易進行IPO的分解和對應。對應過來就是定位-換算-瞄準。瞄準其實就對應從遊戲角度分析的攻擊方式。所以這裡主要就看看定位和換算。定位就是隻要瞄準的目標在哪裡?
一般有兩種方式,一種是透過螢幕取色,然後進行畫素比對的方式發現目標。但其實這種方式在現有的外掛中並不常見,原因是並不好用,識別還是比較複雜的事情。比較好用的還是另一種方式,就是獲取到目標在遊戲內的座標。然後到達第二步,進行換算,換算什麼?就是計算滑鼠移動的數值或是朝向瞄準的數值。
在這個過程中會涉及遊戲世界座標系到螢幕座標系的轉換,轉換為螢幕座標以後,也就是可以得到當前滑鼠與目標在螢幕上的關係如果是模擬按鍵則直接使用螢幕座標可以計算出滑鼠需要如何移動,而如果是修改朝向,則直接可以依據敵人座標與自己的槍口座標計算出命中射線的Rotation數值。
在對外掛實現方式的輸入-中間過程-輸出進行了分析以後,可以發現針對外掛的輸入,我們可以進行座標加密保護。其實這個更適合遊戲開發方進行,而實際上我們防守方也是可以做,類似前面提到過的影子變數保護方案,我們對座標的加密則是可以在遊戲所有寫的地方進行加密,然後在所有讀的地方進行解密。
而對於中間過程的換算,則是可以透過對遊戲進行座標轉換的函式進行呼叫鏈回溯而發現,因為大部分的遊戲世界座標和螢幕座標的轉換都是有差異的。
雖然外掛也可以自實現程式碼,但是當外掛自實現對應程式碼後,在記憶體中存在多份類似的程式碼,也是一種非常可疑的外掛特徵。這樣也就完成了對整個自瞄外掛知彼的分析和方案佈防。
再結合知己的視角所準備的5個基本方案。至此針對自瞄的外掛功能,從定製化的角度,就提出了以上的8個子方案,結業業務的邏輯進行安全對抗方案的佈局。
定製化方案的成本
在實際的遊戲反外掛實踐中,騰訊的多款FPS類遊戲都使用了以上的方案組合,基本實現了對自瞄類外掛的持續對抗。為什麼叫持續對抗,因為遊戲內容在不斷的變化,玩家水平也在不斷的變化,所以方案的模型也是持續的更新。這個也是定製化方案的一個成本,需要持續的維護,難以一勞永逸。而談到成本,其實定製化方案最大的運營成本就是方案的適配。
適配是個什麼東西?不是很好解釋,先說說為什麼需要適配。
從定製化方案的建設來看,會在遊戲的一些時機點獲取遊戲的資料。這些時機點和資料並不是遊戲提供的,大部分情況下都是安全方進行的二次開發。其實也就是利用HOOK來實現。要麼靜態的patch到客戶端,要麼動態的HOOK的執行。而利用HOOK,那麼也就會涉及到HOOK地址的問題,也包括函式頭、函式尾、或是函式中間的選擇。
而獲取資料的方式也就是依賴遊戲自身的資料結構。這些都是透過逆向分析所得。而問題就是遊戲版本是會持續變化的,所以這些我們所需要的地址和偏移也就是會變化的。所以適配也就是應對遊戲的變化而對定製化方案所需要用到的地址和偏移進行修復。
這裡舉一個適配的典型例子來說明適配的複雜度。假設一個函式原有邏輯是1,2,3。而我們的HOOK點就在3這個函式塊。如果遊戲邏輯發生了變化,在5這裡多了一個分支,那其實對我們的方案來看是沒有影響的,但是如果是出現圖中4的方式,那麼整個相關的遊戲邏輯就需要重新分析和確認,因為有了分支4,原本透過3可以直接獲取的資料或是感知的邏輯就不會走了。比如之前進行自瞄檢測的影子變數的例子,這裡多出來了一個對朝向數值的寫,而我們沒有能夠及時對寫的資料進行影子變數加密,那麼在遊戲正常讀取的地方,則會認為讀取到的資料和影子變數中的數值不匹配,從而帶來方案的失效。
除了適配,其實進行定製化對抗最大的成本還是在人。要做定製化的對抗,就需要對遊戲非常的熟悉。這種熟悉除了玩遊戲熟悉以外,更重要的是從逆向的角度對遊戲非常熟悉。畢竟我們不是遊戲開發,我們並沒有遊戲的程式碼,對遊戲的理解都是依賴對遊戲客戶端的各種逆向分析所產生的結論和沉澱。
與我們掌握一門技術類似,看過書和實踐過是有較大的差別,同樣一個遊戲,自己比較完整的逆向分析過,和看過其他人的逆向分析報告是在不同的層次的。
因此如果是一個新人接觸一個新的遊戲,都需要很長的一段時間來進行遊戲逆向的積累,即使前人有較多的結論可供參考。而另外一個角度,一個老人如果還一個新的遊戲,一樣也是需要一段時間的積累,才能相對準確的把握到定製化方案。
定製化才能解決問題
雖然定製化的成本比較高,但是為什麼我們還一直這麼做?
因為從目前的遊戲外掛對抗來看,只有定製化的對抗方式才能解決問題。這裡的解決並不是指完全的消失,而是能夠做到一種及時的壓制。對比沒有定製化邏輯的其他反外掛系統來看,確實是有他的效果。
雖然定製化的成本比較高,但是我們知道安全需求是屬於人類需求的低階需求,作為低階需求那就是必須要保障的。因此只要能夠解決安全的問題,不論成本多大,都是值得的。而所謂成本和效率則是在解決問題的基礎上再談的話題了。
而從目前來看,安全的問題越來越複雜,很難有通用的方法能夠搞定一切,而越是通用的方案越容易被針對,因此個人認為定製化的對抗方式,就如同定製化的商品一樣,貴,但是能更貼合的滿足客戶的需求。而自己也認為IPO的方式,除了對遊戲安全有效果,對其他的業務安全場景也會有幫助。
我的分享到這裡結束了,主要分享一下我們定製化方案實踐的IPO之路,謝謝大家。
本演講PPT下載:
https://bbs.pediy.com/thread-222880.htm