這里主要總結一下單機手機游戲里一些保護措施。雖然看似簡單,但效果也還可以,能讓試圖破解你游戲的人稍微費點功夫。當然完全防止破解是不太現實的,這本身就是個成本問題,破解者全力以赴于破解,開發者還是要全力以赴于游戲邏輯的。
內存加密
我記得我十幾年前玩一些PC單機游戲的時候,使用過一個叫金山游俠的工具修改內存,把游戲里的錢或者其他屬性改成我想要的。基本原理是,游戲運行的時候里面的一些數值比如金錢、生命值之類的都是存儲在內存中的,修改器就通過搜索游戲進程中中所有特定數值的內存并返回,讓你可以修改。比如你在一個游戲里有22222金幣,然后你用修改器搜索內存,找到了一個地方存著這么個值,那你就基本可以肯定這個地址就是游戲程序用來存放金幣的內存地址,然后只要修改這個地址上的值,你游戲里的錢就也被改了;如果第一次搜索搜到多個結果,可以玩一會兒游戲等數值變了再搜,多試幾次,幾次的數值變動情況都對應到同一個地址也就能確認位置了。
應對這種作弊方式很簡單,一種是加密存儲一些關鍵性數值,每次代碼中要讀取/賦值也都要走一遍加密/解密的步驟,內存中永遠存放的是密文。當然這樣別人也很容易發現,游戲中明明有的某個數值搜內存竟然搜不到,那他也許就會采取措施來定位你的密文然后試圖解密了。所以最好還是在內存中放一份明文的數值,讓玩家可以搜到,當然等他們改了你就能知道,因為和密文對比不一致,然后就能知道這個家伙是個作弊玩家了。
至于檢測到作弊玩家后如何處理,這就取決于開發者的腦洞了。可以對設備封號,可以偷偷的把這個玩家游戲里需要花錢地方的數值調高,或者讓他的游戲變成另一個完全不同的樣子,甚至我們的策劃表示可以直接告訴作弊玩家“我們發現你是個作弊玩家,現在給你一個機會,只要充值10塊錢,立馬轉正成正版玩家”。
存檔加密
由于是單機游戲,所以存檔都存儲在本地的文件系統上。在Android和越獄的iOS上,是可以很容易得到這個存檔文件的。如果直接使用某種文本格式來存儲游戲進度,比如把存檔序列化成xml或者json之類,那簡直就是不設防,隨便用一個文本編輯器打開稍微看一下就能知道怎么改;稍微好一點的用二進制來存放,但這也是可以很容易找到規律,或者干脆用像修改內存那樣的方式來修改存檔。
基于以上的情況,游戲存檔最好加密進行存儲,而且最好使用密鑰加密的算法來做而不要把加密解密算法寫死。這樣以后哪天發現被破解了可以再更換密鑰。
存檔綁定
雖然存檔加密了,破解起來稍微費點勁,但是還是可以拷貝存檔啊!誰誰誰玩出一個很不錯的存檔,分享出存檔文件給大家。其實這是很破壞游戲樂趣的一件事,正常點的玩家都不太會去做。但如果你的單機游戲還是有點玩家間交互的,比如有排行榜,看著那些作弊玩家占據著高名次,肯定覺得挺沒意思的,然后就刪游戲了吧。
其實處理這種情況很容易,讓存檔跟設備綁定就好了,而且存檔肯定要加密,不然什么都白搭。具體做法分兩種,一種是在玩家第一次玩游戲存檔被創建的時候把這臺設備的device id也寫到存檔里,之后每次要讀存檔的時候都比較存檔里的device id和本機的device id是否一致,不一致則不讓進游戲或者開啟新的存檔;另一種方式是把本機的device id來作為加密存檔的密鑰來使用,這樣存檔被拷貝到別的機器上之后也是無法正常讀取的。
內購驗證
如果一個游戲里可以花錢購買金幣道具之類的,作弊者就可以通過內購破解來不花錢就得到那些東西。內購破解是一件比較通用的事情,因為玩家不是通過直接破解你的游戲而是破解了AppStore或者GooglePlay的支付來達到的;一般是在越獄的iOS設備和root的Android設備上進行的。
由于這種事情是在游戲以外的部分做了手腳,從游戲的層面上無法判斷,在你游戲里你會收到正確的購買成功回調。不過好在AppStore和GooglePlay都提供了額外的協議允許你去驗證訂單,所以你可以在客戶端的支付完成后再去蘋果或谷歌的服務器查證剛剛的那筆訂單的真實性。這一步都是放在自己的服務器上來進行的(我不確定手機端是否也能驗證訂單,不過即便可以放在手機端做也是不安全的),也就是你在手機端支付完成后再和自己的服務器通信把訂單的信息傳給自己服務器,自己的服務器再去跟蘋果或谷歌的服務器驗證這筆訂單然后再告訴手機端這筆交易是不是有效。
這樣做的話首先自己需要架設服務器專門用于內購驗證,這是額外的開銷;另外玩家在游戲中購買一個東西的時間會變長,稍微影響一些體驗。當然堵死了內購破解這條路并不意味著能賺到原本內購破解所損失的錢,很多作弊玩家大不了就當免費玩家好了,另外還有一些情商高不放棄的會繼續嘗試其他的方法。
強制更新
雖然是單機游戲,一般感覺是不該做強制更新這種事的,當然使用了熱更新技術的人也可以忽略這條。
這一步需要一個服務器,當然一般的CDN服務器就可以了(這只需要錢,不需寫服務器代碼),把一些基本的配置信息放在上面,每次游戲開啟的時候都下載一下并存到本地(當然不一定要每次都下載,可以先下載一個放版本號的小文本,只有配置文件的版本比本地新才下)。然后這種配置信息里面可以保存一個游戲最低版本號的字段,如果發現當前運行的游戲版本低于該版本就把游戲鎖定不讓玩并引導玩家去更新游戲版本就好了(這種配置文件最好好也加密)。
其實這么做的意義在安全方面就是可以把以前發布的有嚴重漏洞可以利用的那些版本給干掉。
改時間限制
這一條主要是針對那些對時間敏感的單機游戲,比如掛機游戲這種。如果只是取本地時間的話,至少可以做成每次寫存檔都把當前時間寫進去,然后玩家改時間作弊通常是改到未來把未來該得到的東西都得到了然后再改回來,只要你發現時間倒退了就對玩家做出一定的懲罰或者怎么樣就可以了。
還有一種是聯機獲取網絡時間,不時的獲取網絡時間來跟本地時間進行對比以判斷玩家是否在時間上作弊了,或者在某些比較重要的邏輯進行的時候只使用網絡時間(比如每日登錄獎勵)。具體的做法可以是自己架設一個服務器來提供時間,當然也可以從網絡上免費的授時服務器來直接獲取時間。
不過使用授時服務器獲取網絡時間有一些問題,由于獲取時間使用的是NTP協議(參看RFC 1305),而NTP是基于UDP報文進行傳輸的,所以其實不是那么穩定,實測下來有的時候失敗率挺高的;還有一個就是發現國內部分地區的運營商的網絡環境下一直無法獲取到時間,由于是玩家報告的,所以無法得知究竟是那個地方連不到國家授時中心還是那個運營商封了NTP協議。
遷存檔限制
之前我所做的單機游戲里有一個功能,遷存檔。雖然做了防止存檔拷貝,但是為了讓玩家可以在換手機的時候繼續在新手機上沿著她(這里用“她”因為那個游戲的大部分玩家是妹紙)的老存檔進行我們的游戲,我們提供了官方的存檔遷移功能。
具體的做法就是先把存檔上傳到我們服務器,并返回給玩家一個隨機碼,然后客戶端鎖定上傳了存檔的游戲,讓玩家通過那個碼再從新設備里把存檔下載下來,只能下載一次。
這個功能給很多作弊者帶來了新的機遇,他們紛紛在淘寶上開店,通過遷移存檔的方式,遠程收錢幫助其他玩家修改存檔。當時我們還沒有做內購驗證,很多賣家先把其他玩家的存檔遷移到自己手機上然后用內購破解購買了很多充值幣再把存檔返還給買家。當然后來做了內購驗證后一些只會內購破解的淘寶賣家被淘汰了,但還是有人能繼續做這個生意,這充分了說明道高一尺,魔高一丈。
所以我覺得這種功能的使用應該是要受到一定限制的,比如固定的次數限制或者玩滿多少個小時之后才有一次遷移的機會之類。
代碼混淆
這個大家基本都知道,其實就是在游戲的源代碼層面,在保持代碼功能不改變的情況下將代碼變的面目全非。一般就是通過大量的替換原有標識符的名字來達到這樣的目的,不過這肯定不是人工來做,都是用代碼混淆器來自動完成的。
當然對于某些寫代碼自帶混淆的人來說,這一步其實沒什么意義。(對吧,天王~)
游戲加殼
這個其實大家也都知道的,在游戲的包編譯出來之后進行的。iOS的ipa我不是很清楚,但是對Android的apk來說,這一步還是挺有必要的。不加殼的話,別人可以很輕易的反編譯你的包,加一點他自己的廣告(或替換掉原有的)后重新打包在別的應用市場上發布;加殼的話,別人要稍微費點事來破解你的包。。。
現在國內的有些渠道甚至會要求你把包提交給他們之前先加個殼,不過不知道為什么一般是指定了用360加固寶,其實也是有一些比較安全的加殼工具比如APK Protect這種。
好了,暫時就想到這些。