最近我一直在編寫適用於Windows 10商店的游戲.這款游戲比較怕玩家用修改器改金錢,因為這種修改會導致某些內購失效並且損害公平性。於是我把自己見過的三種反修改器的方法給網友們介紹一下。
首先說明一下我總結的防止游戲作弊的理念:
1.預防修改,防患於未然,讓可用的修改手段減少。
比如說,你讓你的UWP在PC不可用,那么修改內存這個操作本身就變得十分艱難了。
用.NET Native編譯(或者干脆用c++而不是.net語言),可有效防止反編譯看你的加密和解密算法然后搜內存。
2.攔截修改,修改前就攔截掉
這通常需要特權,目前很多游戲的反外掛保護程序就是這樣做的。缺點很明顯,就是兼容性差,甚至可能導致整個操作系統崩潰。
還要注意,在UWP或者其它Windows Runtime環境下,提升特權不僅難而且違法商店規定。
3.免疫修改,簡單的修改后不影響游戲邏輯的正常工作或者干脆用一般的搜索手段找不到該改哪里。
這種方案可行性比較高,具體的實現方法我在后面列出來。
4.檢測修改,能夠在修改后發現被修改了,加強這種防范。
比如你的程序使用了一種代價低但是精確度不高的作弊檢查手段(比如每1分鍾掃描一次需要保護的數值,檢查是否作弊了),那么發現作弊后可以啟動更嚴格的作弊檢查(例如,改成每秒檢查是否作弊,或者是啟用其它保護方式)。
總結一下,防止作弊與我們看病是一樣的,對抗疾病,我們應該做好預防,早發現,早治療,還要防止后遺症。
轉載必須注明這是Nukepayload2原創的博文
下面開始介紹在UWP上比較可行的防內存修改作弊的方法。
一. 用Hash驗證數值是否被修改過
一個需要保護的數值被賦值時計算新值的Hash值,在讀取的時候就可以驗證Hash值是否正確,如果發現讀取的時候存儲的數值與Hash值不對應,游戲就不應該繼續進行下去。
還有個問題是關於線程安全的。如果你修改了存儲的值,但是還沒來得及計算Hash值,另一個線程下一步修改了存儲的值,那么這個驗證就會發生錯誤。所以整個賦值的過程應該是互斥的。
下面的示例代碼描述了對讀寫過程的互斥,並且要計算Hash值。讀取的時候要驗證Hash值。
VB
Public Property Value As T Get SyncLock lock If GetHashCode() = Hash Then Return _Value Else Throw New CheatedException
End If End SyncLock End Get Set(value As T) SyncLock lock _Value = value Hash = GetHashCode() End SyncLock End Set End Property
驗證的時機可以調整,比如在游戲空閑的時候,存檔之前,交易之前,交易之后 等關鍵時刻進行。
二. 對需要保護的數值進行混淆
讓被保護的數值混淆,比較理想的情況是:實際值變大時存儲的值不一定變大,實際值變小時存儲值不一定變小,即使實際值變化后與原來的實際值等價存儲的值也可能變得不一樣。這樣的保護既可以防止精准查找,也可以防止變大或變小的模糊查找。
混淆的同時,還可以更新一個假的字段誘騙內存修改器上當(不過這樣可能會讓真的值暴露,所以混淆算法要好好設計,假的值在哪里放也要考慮清楚)
VB
Public Property Value As T Get Return TransformBack(_Value) End Get Set(value As T) baitValue = value _Value = ConfuseTransform(value) End Set End Property
三. 加密需要保護的數值
這種方法非常經典,與上面的方法接近,但是不會騙修改器。代碼很簡單,沒必要給大家寫了。
四.混合使用保護方法
你可以給需要保護的值算一個Hash值保存起來,然后對原有值混淆后加密,並且向某個遠離秘文和Hash值的地方寫入一個假的數值誤導修改器。
混合前面的方法時同樣要注意線程安全問題,考慮哪里需要互斥。
這是本文最后的代碼示例,描述了一種混合多種保護方式的值的讀寫方法。
這樣,使用簡單的內存修改器的玩家會先找到陷阱,發現那里的值改了不起作用,使用exe分析程序找到了加密用的key和iv,嘗試多種解密算法,可是解出來的值還是不能用常規的hash算法找到與內存中匹配的內容。這樣幾乎所有不會匯編的玩家會對內存修改這條路望而卻步(除非某個會匯編的人寫了修改器出來,不過要看懂.NET Native編譯的程序還是挺難的)。
VB
Public Property Value As T Get SyncLock lock Dim val = TransformBack(Decrypt(_Value)) If ComputeHash(val) = hashCode Then Return val Else Throw New CheatedException
End If End SyncLock End Get Set(value As T) SyncLock lock traps.Enqueue(value) If traps.Count > TrapSize Then traps.Dequeue() hashCode = ComputeHash(value) _Value = Encrypt(ConfuseTransform(value)) End SyncLock End Set End Property
至於發現作弊后做什么,我的選擇是終止游戲,而且異常提示也是具有迷惑性的。
圖中是我的UWP游戲強行改內存后崩潰的圖,我把游戲名稱抹掉了。