技術流:弱聯網手游如何防作弊?手游作弊攻防戰

>>>  創業先鋒 眾人拾柴火焰高  >>> 簡體     傳統


  樂元素CTO凌聰分析了作弊(主要是弱聯網休閑游戲的作弊)的影響,比如改變排行榜中的全局排行與好友排行,還會影響廣告投放,帶來經濟損失。他從弱聯網游戲可能存在的多種安全問題來分析玩家或破解者可能采用的手段以及研發商可以采取的對策。最后他總結了對各種問題的解決方案。

  存檔被篡改:AES、限制專一、限制降級
  協議被破解:AES、SSL/TLS、nonce防重放
  盜號或用戶偽裝:用戶標識符、社交賬號綁定
  工程被逆向破譯:符號隱藏、標識符混淆、邏輯混淆
  函數被Hook:隱藏和混淆、阻止跟蹤調試、組織外掛啟動
  二進制程序被修改:驗證校驗碼
  內存被修改:內存加密
  大招:上傳用戶操作和隨機種子,數據監控+回放+人工審核

以下是對凌聰演講內容的整理。

  一、為什么要防作弊

  (一)經濟損失


  據我們調查,在電商網站上有很多賣作弊手段的道具,搜索網頁也能發現非常多人在賣作弊手段,所以經濟損失肯定是第一位的,《開心消消樂》的作弊使我們損失幾百萬。

  (二)作弊的其他影響

  今天我們主要講弱聯網的休閑游戲,就是可聯網但是也支持離線玩。這是休閑游戲在當今市場環境里獲得地位的重要手段,因為不聯網的話相當于不能PK,不能跟好友對戰和每日登陸等功能,這是很壞的。

  弱聯網游戲影響最大的是排行榜,包括全局排名、地區排名和好友排名,如果你作弊了,這三個榜上用戶投訴很多,對我們影響很大,有些用戶發現有人作弊會流失掉,你就要用很多手段封殺那些作弊用戶。

  另外是重度游戲,很多重度游戲需要本地計算 ,凡是客戶端做的游戲都有可能作弊,所以重度游戲也需要防作弊 。

  第三個是廣告,因為廣告可以直接騙你錢,我們曾經買過一次廣告,當中居然有75%的量是假的。

  攻防戰只要有邏輯放在前端本身就是不安全設計,但是人家的手段是進化的,而且當一個作弊手段出來的時候就會在淘寶上賣,這個傳播是很嚴重的。有一種手段沒防住,它擴散了的話就沒有這么簡單,擴散就影響你整個系統。所以不是80%攔了就OK的。有些時候有一個手段就讓你的經濟系統崩潰,需要你不斷的優化。比如針對游戲攻擊函數鉤子,這個如果真的發生,損失就是很大。

  (三)弱聯網游戲可能存在的安全問題

  第一,存檔被篡改和復制,造成你的損失。
  第二,本地配置被篡改。在離線游戲、休閑游戲里面可能有些配置被篡改掉。
  第三,帳號被盜和惡意修改。
  第四,內存被修改。我們有三種內存,第一種是傳輸型的內存,傳輸性內存是不用加密的,因為傳輸型內存都是一次性的。另外一種是永久型內存 ,這肯定是要加密的,用戶狀態比如你的血、精力值這些都是永久狀態。第三種是暫態內存,比如《開心消消樂》打完一關,獲取的金幣和獲取的經驗都會暫存的,這個暫存它有可能查就的,這要進行一個加密。
  第五,網絡協議被破解和重放攻擊。
  第六,工程被逆向破譯。現在有很多技術高超的人,可以反匯編你的代碼 ,然后把你的工程逆向。
  第七,二進制程序可能被修改。剛才講到的只要涉及到加解密,都會把加解密函數鉤走,然后把它修改掉。
  第八,函數被掛起,被Hook。

  (四)防止存檔篡改

  方法:加密肯定是需要的,建議強加密,建議用AES 256 CBC PKCS#7。必須使用安全的對稱加密算法,建議使用AES加密算法,密鑰256位或以上,工業級、速度快。

  密鑰怎么保存?首先,密鑰不要直接保存在代碼里面,密鑰是生成的。第二,密鑰不要放在存檔里面,這是很危險的。第三,密鑰每次加密當場現算。第四,密鑰的生產需要有隨機度。

  (五)存檔協議設計

  第一,Magic number:標記存檔類型。
  第二,版本號:標記加密方法類型。如果一個休閑游戲需要兼容兩版本模式肯定需要版本號。
  第三,源數據哈希。源數據的哈希為什么要設計?要驗證你解密后的存檔數據是不是一致的。
  第四,初始向量。盡量每次都不要一樣,否則很容易被反向。

  (六)密鑰的產生

  密鑰必須有一定的隨機性,可以隨機數產生但需要一些技巧,也可以哈希產生。密鑰最好是生成,不要在代碼里面去。比如我們看過一些破解程序,發現密鑰直接寫在字符串里面。
  產生隨機密鑰的技巧:應使用工業級加密庫的產生函數,這樣更隨機。
  自己產生的隨機數,如以下算法,實際上最多只有2的31次方種密鑰,而加密算法要求2的256次方種。

  1. char key[32];

  2. srand(time(NULL));

  3. for(int i=0;i<32;++i){

  4. key = rand() % 256;

  5. }


  (七)初始向量的用法

  盡量不要使用ECB,它的加密強度不夠強,所以我們建議用CBC做加密比較穩妥。

  每次加密,初始向量都必須不同。

  (八)阻止存檔轉移

  玩家可能將存檔發給他人破解(如淘寶賣家),需阻止設備直接共享存檔文件。

  可通過使用UDID參與加密,來阻止存檔轉移。

  方法1:UDID參與密鑰產生
  – KEY = RAWKEY ⊕ SHA256(UDID)
  方法2:UDID參與IV產生
  – IV = RAWIV ⊕ SHA256(UDID)
  存檔協議中只存儲RAWIV

  當你復制存檔 給另外一個設備的時候設備打不開的,因為它的KEY不一樣。

  (九)限制存檔降級

  比如我們發現一個版本有漏洞,我們打了個補丁過去,結果用戶發現之后趕緊把代碼回滾到以前,然后再打開存檔 ,這樣的話就可以再次修改,這個就是存檔降級。

  存檔降級的解決辦法,舊版本的存檔被新版本程序讀取之后,要轉換為新存檔版本。而新存檔不能給舊程序讀取。我們還做了在服務端校驗,如果設備里面生了新存檔 ,不能再用舊存檔。 防止一個設備上來回存檔的問題。

  (十)內存修改

  剛才講了內存修改分三種內存,其中第二、第三種,暫存和永久性內存是必須要加密的。

  現在有兩個修改器:之前有個八門神器,它就是對比內存 ,內存值變了兩次之后,它找到你內存的偏移地址,可以定位到內存地址在哪里。八門神器我們當時比較好解決,用非常簡單的加減法可以解決加密問題,因為它找不到原來的數據,或者不是整數,這樣它也找不到。現在有一個更高級的,叫燒餅修改器,它能力挺強的,假設你修改的數加了個“038”,它一樣可以找到。另外,它支持加減法,如果你的數據是加減法或者乘除法它能找到,所以內存的加密函數需要變化。防止內存修改最簡單的方式是做一個加密的HashMap ,進的時候是加密的,出的時候是解密的,在函數里面加上一些較為強加密的算法就行了。

  (十一)協議破解的幾種可能性

  協議破解一種方式是通過抓包工具,抓包完之后,如果你的協議沒加密,用戶可以偽造請求 ,也可以偽造服務器響應。玩家通過攔截服務器的響應做重放,客戶端重放上次的請求。當然,玩家知道協議之后可以偽裝成另外一個玩家,這是更惡劣的情節。

  (十二)偽造請求的防范

  加密肯定是需要的,加密的通訊協議最好自己寫。建議AES。

  (十三)偽造響應的防范

  要么采用非對稱簽名驗證方式防范 ,但是這個速度比較慢,不建議用。

  另外一個是用TLS,如果我們要用TLS的話要注意校驗服務器的證書在客戶端那,因為服務器的證書很容易被篡改 。比如它通訊的時候可以用自己的證書,這樣的話是可以攔截你的協議的。如果程序破解了,函數直接就調用了。

  (十四)重放攻擊


  剛才講的響應服務器主要是不讓別人破解我們的協議,重放攻擊是什么?重復攻擊是我不需要了解你的加密協議,我只需要重放就行了。我們有一個版本的游戲是出現過這樣的問題,攻擊者攔截你的請求,然后多次重放,如果你沒有做校驗,很容易導致你的數據不斷的往上增加。這個最重要的是支付,比如你從APPLE拿到一個支付響應,回傳給你服務器的時候,它抓住這個請求不斷的重放,這樣很容易造成重放的攻擊。

  重放攻擊最好的解決方案是中間加一個nonce。服務器的響應,服務器辨別你的時候它要看到,如果這個nonce是以前已經用過的就把它丟棄掉,為啥?因為這肯定是作假。

  (十五)防范帳號偽裝


  首先一個過程是登陸的過程,登陸的過程拿到Session Key,其他所有的請求都要使用這個,這個是服務器端生成的,服務器端可以每次校驗這個SessionKey。我們是分開的,給用戶看User lD,所以我們不要在傳輸協議僅放一個Userld,這個用戶標識是服務器產生的,安全性就沒有了,客戶端把這個存起來,以后都用這個服務器標識跟后端通訊。

  SessionKey有兩個作用,一個是防止多Session登陸,另外,SessionKey和UserlD是關聯的,因為SessionKey每次都不一樣,所以要偽造比較難。為什么不用用戶標識?因為每次都傳安全性是低的,是很危險的。所以做這兩個主要是為了提高你的安全性。

  (十六)程序被破解的幾種情況

  最關鍵的一個是程序被逆向了,它造成的后果 是有可能你的二進制程序被修改,有可能函數被外掛 Hook了,當然,內存被修改也是可能的,因為它知道你的加解密算法之后內存就會給修改。

  (十七)防范程序被逆向破解的方法

  第一個關鍵是符號隱藏,函數符號表隱藏住。特別是加解密函數。

  第二,關鍵字混淆。
  第三,程序邏輯混淆。
  第四,內存加密。
  第五,阻止動態跟蹤調試。
  第六,二進制程序校驗。這里除了你提交的主程序之外,另外一個也要防止篡改。
  第七,Lua腳本加密也很重要。

  (十八)符號隱藏

  盡量不用系統的函數庫,因為系統的函數庫你沒有任何辦法把它隱藏 ,它都是暴露在那的,只要你用它,它就可以掛接到鉤子上去,所以盡量不要用。

  另外,重要的函數在模塊里面,盡量用static函數。

  第三,關鍵加密庫要設置關閉符號表導出。你把輸出函數符號表隱藏掉。

  第四,Xcode配置Symbols Hidden By Default。我看國外很多游戲已經這么做了。

  另外,你可以通過nm命令可以查詢到輸出函數 。如果沒有函數符號表輸出就比較安全了。

  (十九)標識符混淆

  class-dump可讀取Objc的類元數據,能看到類的方法和屬性。

  無法關閉類元數據的導出,因為ObjC的面向對象機制需要。

  只能對類名、方法名、屬性名進行字符串替換,讓破解者無法看出接口的用途。

  ObjC的混淆方案是,在prefix.pch中使用#define替換標識符。

  工具是ios-class-guard。

  標識符混淆的缺點有,當父類是第三方庫時,父類的函數無法混淆,但子類同名函數卻混淆,就會錯誤,需要對第三方庫的函數進行排除。不能使用ClassFromeNSString反射。接入Lua時需要查表才能調用正確方法。


  (二十)其他隱藏接口的方法

  通過用C語言的static函數實現

  通過ObjC-Runtime動態添加

  (二十一)程序邏輯混淆

  通過打亂代碼次序,增加花指令等手段,可以阻止駭客對工程進一步跟蹤和分析,類似加殼,但iOS項目目前沒有商用的加殼程序。

  或者用開源的程序邏輯混淆器obfuscator-llvm,用它替代XCode自帶的llvm編譯器。

  (二十二)組織跟蹤調試

  GDB等調試工具可以跟蹤程序運行,可以使用ptrace組織GDB依附APP進程。

  我們可以用GDB掛去調它的函數,只要看到有一個數字函數,我就可以看到你的輸入輸出參數 ,我只要會一點點匯編語言,就基本能看到你的參數 。所以我們需要防止這個GDB。

  (二十三)二進制文件校驗

  程序啟動時,需要判斷二進制是否被修改過,以防止代碼被篡改或被植入廣告。

  我們在編譯好包后,生成二進制文件的哈希,然后將版本號拼接起來作為校驗碼,用私鑰生成校驗碼的簽名,校驗碼和簽名都存入一個文件中。由于沒有私鑰,玩家無法偽造校驗碼。

  (二十四)反盜號

  反盜號,如果離線的話非常容易盜號,越獄機器什么都可以改,所以我們需要防止它做這個事。

  第一個,我們最好有個網絡帳戶,如果用它用網絡帳號登陸的話,就不讓它用本地帳戶校驗了。如果是本地校驗建議不要用可變的,自己在KeyChain里面存儲一個UUID,如果你做越獄了,很可能會丟掉,安卓 上面就自己建一個文件。如果是它用了網絡帳戶登陸的話,它如果要恢復,比如說它重裝了應用的話,可以通過這個網絡帳戶拿回它的信息,網絡帳戶有可能是Facebook、QQ、微博甚至自己用戶名密碼都是可以的。

  最后一個我們稱之它為“大招”,上傳用戶行為數據以及隨機種子以做到可重放。我們有一款游戲用了這個手段,我們把用戶的行為和隨機種子,因為我們所有的調入都是通過隨機種子搞的,所以我們認為是個隨機種子,這樣通過游戲的模擬可以把現場在一個客戶端重放,重放的話我們就可以看到這個用戶是不是作弊了。

  這里面如果做這點話需要有兩個手段,第一個,我們需要在客戶端讓這個傳輸數據和隨機種子做到重放,另外,需要監控到數據的異常,因為我們重放用戶數據行為之后很多時候需要人工判斷這個數據是不是作弊的,所以我們需要首先有個數據監控系統,我們監控到某些用戶的數據突然變了異常,接下來我們會重放這些用戶數據,看看這些用戶數據是不是有問題,如果用戶在重放的過程發現結果并不是這樣的,那他肯定作弊了。

  為什么說它是大招?因為有些時候是沒有辦法百分之百做到內存防篡改的,有些時候程序員忘了把顯示在界面上的數據放到加密里面,玩家會修改你的數據,修改你的數據來作弊。


(完)



GameRes游資網 2015-08-23 08:41:52

[新一篇] 《刀塔傳奇》的傳奇:一款國民手游的誕生

[舊一篇] “我啊,最討厭火影了!” 葡萄語錄
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表