微信5.0 Android版飛機大戰破解無敵模式手記
最近微信出了5.0,新增了游戲中心,並內置了一個經典游戲《飛機大戰》。游戲其實很簡單,但由於可以和好友一起競爭排名,一時間受到大家的追捧,小伙伴們進入“全民打飛機”時代。
ios 版出來不久就被破解出了無敵模式。Android版出後好像一直風平浪靜。周末無事,加之看雪zmworm版主邀請,於是花了一天的工夫研究了下。也出了個Android版的無敵模式增強版。具體來說就是無敵、雙排子彈加無限炸彈。當然,這個不是重點,我們的重點當然是技術細節啦!
微信的游戲繼承了Android版手機QQ游戲中心的思想,也采用插件動態加載方式。具體來說,就是插件及游戲以jar包形式存在,jar包中有classes.dex及其他資源文件,在運行時動態加載資源及classes.dex代碼。這樣的好處是靈活管理,易於擴展。以後更多的游戲只要上架到微信的服務器,用戶就能在微信應用內部下載、安裝、運行。具體原理可以參考我2011年的一篇文章《Android類動態加載技術》 。
當然,那篇文章講的只是基本原理,而微信在代碼動態加載方面則走得更遠。針對插件的管理及安全,它有一套完整的框架,並自稱為sandbox。由於代碼有做混淆,加之代碼量挺大,所以我僅算管中窺豹,看到的也只是冰山一角。與實際情況有所出入,還請見諒!
一、微信游戲插件的安全校驗
其實說實話,微信在游戲插件的安全架構方面花了不少功夫。我能破解並不是利用微信在安全方面的漏洞,而是Android系統本身的安全漏洞。這個漏洞也就是我前段時間發的以為是bluebox上報google的漏洞,後來被證實不是。詳情請看《Bluebox Security最新提報Android漏洞的初步探討》 。
那微信是如何對游戲插件進行加載及安全校驗的呢?
飛機大戰的游戲插件以jar包的形式,放在微信apk的assets/preload文件夾下:
jar包中包括classex.dex、so本地庫及drawable圖片資源或者還有xml資源。微信處理插件加載的代碼在com.tencent.mm.compatible.loader包中。加載插件資源的類叫做PluginResourceLoader,它是android.content.res.Resources的子類。
而最核心的加載類應該是PluginClassLoader。上面說的PluginResourceLoader也是它的成員變量。它似乎負責整個插件加載的各個環節調度。
Android動態加載類有一個弊端,就是dex文件必須釋放為本地文件。這是dalvik虛擬機機制決定的。一直以為google或者dalvik會改,不過似乎到現在還沒見改進。釋放到本地緩存的dex是很容易受到攻擊的,不過微信在這些細節上處理得還挺好,沒有明顯漏洞。這個後面再說。
PluginClassLoader會在微信安裝後第一次啟動時,掃描插件的情況,並將插件拷貝到自己應用data下面的app_dex文件夾下。接下來會對插件進行處理。將so庫釋放到app_lib文件夾下,將jar包中的classes.dex重命名釋放到app_cache文件夾下。
在拷貝插件jar包的過程中,會對插件進行第一次校驗——簽名校驗。關於簽名校驗的原理,可以參看我2011年的另一篇文章《Android APK 簽名比對》 。微信的簽名校驗就是微信APK的簽名需要和插件jar包的簽名一致。這裡我考慮過用bluebox上報的ANDROID-8219321漏洞繞過插件jar包的簽名檢測。經過一段時間的研究發現了它還有第二次校驗。。。
由於是在拷貝之前進行簽名校驗,所以我考慮過拷貝完成後,直接替換app_dex和app_lib下的文件的方法。發現均不可行。繼續分析發現了第二次校驗——MD5校驗。一開始看到jar包命名就很疑惑,文件名後面一串數字是干嘛的。想過是MD5碼,沒做驗證。直到碰壁之後,才發現了這裡的奧秘。後面這一串數字就是jar包的MD5值。插件加載的時候會去解析這個MD5值,並存起來。在加載運行的時候會對這個MD5值進行校驗,如果緩存中的文件MD5值不同,會用重新釋放apk中的插件覆蓋。緩存中的dex應該也有類似的機制。這部分代碼分析得不是很透徹,大概原理如此,有感興趣的朋友可以繼續深入。
MD5值作文件名+簽名校驗,以為著利用ANDROID-8219321漏洞的企圖落空了。因為ANDROID-8219321漏洞的前提是apk中文件的文件名需要保持不變,這樣才能通過重名文件繞過簽名校驗。然而只要我們改了插件jar包,MD5值就必須得變,從而導致文件名改變。因此此路不通了。(也許可以通過修改MD5校驗和簽名校驗的smali繞過校驗,無奈我暫時沒找到具體MD5校驗的代碼,只能作罷)。
MD5值作文件名+插件簽名校驗,再加上安裝APK本身的簽名校驗。三重校驗保證了微信游戲的安全性。
因此我只能采用《Bluebox Security最新提報Android漏洞的初步探討》 一文中所述的安全漏洞。此漏洞針對system/app和vendor/app下的apk只會校驗manifest.xml文件簽名。因此我可以任意修改插件jar包,在重新生成新包之後計算出新包的MD5值,並對新包進行重命名。對於插件的簽名校驗,則直接通過修改smali代碼,屏蔽掉微信簽名校驗的函數功能,直接返回true:
這就是我們修改插件之後得以正常運行的理論基礎及可行性保證。有了上面的理論,我們就可以開始修改游戲了!
二、飛機大戰游戲破解
飛機大戰這個游戲據說是騰訊一個程序員一周時間開發完成的作品。其實考慮到這個游戲的規模,除GUI和交互設計外,程序員一周時間應該也差不多了。沒有太大出入。
此游戲采用的游戲引擎是libgdx。相信做過Android游戲的朋友對此款引擎不會陌生。如果在Android平台開源游戲引擎裡,cocos2d當仁不讓地排第一的話,那麼libgdx也可以當仁不讓地排第二了。cocos2d主要采用C++開發,而libgdx則主要采用java方式開發。學習成本低,開發周期短,是它的優勢。當然它也是跨多平台的游戲引擎,運行效率方面稍有欠缺但也不錯。因此廣大的Android單機小游戲都是采用libgdx作為游戲引擎。
微信飛機大戰的代碼量不大,有興趣的朋友可以研究下,移植成為一款獨立的單機游戲應該也不難。下面我詳細介紹下飛機大戰游戲破解的技術細節。
第一步就是將飛機大戰游戲的插件包從apk中釋放出來。我們可以采用反編譯APK的方式反編譯這個插件包。修改smali代碼之後,再打包回jar包文件。如果還有朋友對APK破解流程不熟悉的話,可以參考我以前的一篇文章《APK Crack》 。這裡我們主要介紹游戲的架構及破解思路。
解壓之後,smali部分其實可以分為兩個包:com.badlogic.gdx和com.tencent.mm.plugin.shoot。前面一個是libgdx導入的jar包,這個不是我們關心的內容。我們的重點就在com.tencent.mm.plugin.shoot這個包中。
游戲主要有兩個Activity:ShootMainUI和ShootFlashUI。它們都繼承自com.badlogic.gdx.backends.android.AndroidApplication,這個類事實上繼承自Android系統的Activity。它們一個是主加載界面,一個是我們停留時間最長的游戲界面。當然需要了解,但都不是重點,重點是我們游戲中的各種角色:
這些角色構成了整個游戲的演員,他們都繼承自同一個類:GameSprite。相當於游戲引擎中精靈的概念。它們都有生命值、寬高、速度、類型、狀態等屬性。這些類的定義都在actor子包內。在游戲過程中會對每個精靈做碰撞檢測,當你發現你的飛機爆炸時,就是碰撞檢測在起作用。順便說一下,libgdx引擎采用的物理引擎是C++版的box2d,性能非常不錯。
好了,我們具體的破解特性,我會以任務的形式一個一個娓娓道來。下面我們接到的第一個任務就是“永久雙子彈”!
任務1、永久雙子彈!
在玩飛機大戰時,雙子彈意味著更大的威力。可以消滅更多的敵機,化險為夷。然而在實際游戲中我們只有吃到PROPS_DOUBLE之後才能擁有一段有限時間的雙子彈狀態。
雙子彈屬性屬於HERO的,對應的類是Player和PlayerActor。Player繼承自GameSprite,而PlayerActor則是libgdx中的actor類的概念。兩個前者注重狀態和屬性,後者注重邏輯和動作。
Player在構造函數初始化時就會設置子彈類型:
我們只需要把BulletType從NORMAL改為DOUBLE就可以了。
PlayerActor會對子彈類型進行定時地檢測,檢測是會將雙子彈還原為單子彈。應該是為了處理吃到PROPS_DOUBLE後,一段時間子彈還原的問題。所以我們一並改掉:
OK,雙子彈破解任務完成!
任務2、炸彈無限!
炸彈是個好東西,威力無窮。關鍵時候全靠它清屏,消滅所有敵機!而且它還是刷分利器。當然,只有在它變為無限的時候,我們才能用它來刷分。
這裡我試圖修改Player的getBombNumber和setBombNumber方法,發現均不行。後來轉變思路,只要在使用炸彈後炸彈數量不減少,就能實現無限炸彈的功能。經過代碼追蹤,最後定位到一處混淆代碼處。將-0x1改為了0x0。
修改的結果,在吃到兩個炸彈後使用炸彈不會減少炸彈數量。吃一個炸彈時,使用炸彈後炸彈按鈕消失,因此無法做到無限。請記住一定要存到兩個炸彈之後才能無限炸彈。無限炸彈破解任務完成!
任務3、開啟無敵模式!
長生不死一直是我們人類的終極夢想,在游戲中也不例外。iphone版微信也是因為有了飛機大戰無敵模式而被各大新聞站點競相轉載。讓我們Android版也無敵一下吧~
前面提到了GameSprite是所有角色的父類,在游戲用物理引擎做碰撞檢測後,會調用GameSprite類的hit方法。hit方法中將GameSprite的liftCount減一,如果減到0則將狀態設置為DEAD。
GameSprite的狀態有如下一些:
DEAD
EXPLODING
FLIGTHING
HITING
INVINCIBLE
在飛機正常的死亡過程中,是先HITING,再EXPLODING,再DEAD。FLIGTHING我不清楚干嘛的,INVINCIBLE應該是無敵模式。但是在我的破解裡,並沒有使用這個模式,而是強制在碰撞檢測結果中,把它列在了生死薄之外。至於INVINCIBLE的方式,大家可以試試能不能很好的維護這個狀態。
具體來說就是hit方法不管GameSprite是hero也好,enemy也罷,均一視同仁,生命值減一,或者死掉。然而我們可以通過修改smali代碼,將hero列在生死薄之外:
其中goto_1標簽跳轉到return-void。這樣我們的hero將永遠不會被hit,因此也就無敵啦!
任務4、獨孤求敗。。。
本以為完成任務3就大功告成了,誰知我們缺遇到了無敵的尴尬——死不了。。。死不了,意味著永遠無法結束游戲,永遠不會有機會上傳自己的得分進入排行榜。哎,現在終於明白為什麼獨孤求敗了。。。
基於此,我們得想個辦法觸發飛機非自然死亡。想來想去,我還是覺得讓飛機自己決定自己的生死最合理。具體就是當飛機飛到屏幕最上方時觸發死亡。因為一般情況,我們不會把飛機飛到屏幕最上方,所以誤操作概率極低。
通過前面我們知道hero飛機的類就是Player。而Player中有一個函數更新飛機的坐標位置:updatePosition。所以我們可以在這個函數中進行我們想要的操作:
其中0x64就是我指定的y坐標下限100。當飛機坐標y在100以內時,我會把飛機的LiftCount設置為0,然後再將狀態設置為EXPLODING。飛機就會爆炸死亡了~
OK,任務完成,打完收工!
三、一些掃尾工作
插件包修改完成後,我們通過apktool,將其打包回jar包。res資源包需要手動添加會jar包中。然後按照第一節所說的,生成jar報的MD5碼,重命名jar包。
微信APK也需要按第一節的方法,將插件的簽名校驗屏蔽掉。編譯出classes.dex,替換微信原始包中的classes.dex。
再將APK包中的飛機大戰插件換為我們編譯出來重命名的這個jar包。
OK,APK准備好了。
由於我利用的是《Bluebox Security最新提報Android漏洞的初步探討》 一文中所述的安全漏洞,所以安裝此APK的過程並不是菜鳥能玩的。。。簡單來說,你需要root權限,並能將system分區mount為可寫。
然後卸載你原本的微信。將這個apk放到/system/app/文件夾下。稍等片刻,你就是打飛機的高手了!
如需技術交流,請與我聯系。新浪微博: @囧虎張建偉
轉載請注明出處: http://www.blogjava.net/zh-weir/archive/2013/08/14/402821.html
附排行榜:
注:游戲作弊有一定的封號風險,請大家慎重使用。本帖只作技術交流,不用於其他任何商業目的。
補充說明(2013.8.15):
有朋友反饋,按照我文中的步驟一步步下來,生成apk push到system/app下,程序無法正常運行起來。強制退出。
請查看log,是否有類似如下錯誤:
Caused by: java.lang.UnsatisfiedLinkError: Couldn't load CrashMonitorForJni: findLibrary returned null .....
at com.tencent.mm.sdk.platformtools.CrashMonitorForJni.init(SourceFile:26)
at com.tencent.mm.sdk.platformtools.aq.(SourceFile:62)
導致這類錯誤的原因是有些手機將apk push到system/app下後,安裝過程不會釋放拷貝so庫。
你需要手動將微信lib下對應你手機平台的so庫拷貝到/data/data/com.tencent.mm/lib對應的文件夾下。
由於我的手機沒這個問題,所以之前沒有發現。特在此做補充說明。
補充說明2暨可安裝版APK發布(2013.8.18):
本文發出後,得到廣大網友的熱烈響應。一些網友因本文對軟件安全產生了極大興趣。
許多朋友按照文中的方法破解成功,而也有不少朋友還有一些關鍵點沒有突破。很高興看到大家在論壇、微博、博客和郵件中與我交流,我也盡量答復大家技術相關的問題。但仍有不少朋友的問題沒來得及答復,在此向你們表示歉意!
在大家的提問中,很多朋友希望我能直接提供APK,以供深入研究。之前由於安裝步驟過於繁瑣,所以一直沒有發布APK。
好消息是在網友的不斷提問和更多的信息提供之後,我發現最新的微信版本似乎將我文中提及的安全校驗機制關閉掉了。因此,我們可以采用重簽名的方法得到可以直接安裝的APK。值得注意的是:1、插件jar包和APK包都需要簽名,且簽名一致;2、MD5校驗似乎也失效,不用重命名插件包。
(我確信這在我之前破解的版本是不行的,嚴重懷疑微信是不是把內部debug的版本給放出來了。。。)
APK下載地址:點擊下載 。
再次聲明:本破解版游戲僅用作技術交流,嚴禁用於任何商業目的!違者後果自負!