首页
社区
课程
招聘
[原创]微信5.0 Android版飞机大战破解无敌模式手记
2013-8-14 23:27 60860

[原创]微信5.0 Android版飞机大战破解无敌模式手记

2013-8-14 23:27
60860
微信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.16):
     
有朋友反馈,按照我文中的步骤一步步下来,生成apk push到system/app下,程序无法正常运行起来。强制退出。

请查看log,是否报UnsatisfiedLinkError错误。
   
导致这类错误的原因是有些手机将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下载地址:点击下载
   

再次声明:本破解版游戏仅用作技术交流,严禁用于任何商业目的!违者后果自负!

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞2
打赏
分享
最新回复 (73)
雪    币: 5127
活跃值: (363)
能力值: (RANK:170 )
在线值:
发帖
回帖
粉丝
zmworm 4 2013-8-14 23:53
2
0
非常值得学习的好文 注入修改也不失为另外一种好方法。
雪    币: 1675
活跃值: (594)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
djxh 2013-8-15 00:04
3
0
感谢分享,向楼主学习
雪    币: 148
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sdasda 2013-8-15 02:56
4
0
谢谢您的分享,楼主能不能留下apk
雪    币: 13
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ollaa 2013-8-15 07:32
5
0
+1
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
伊风L 2013-8-15 09:57
6
0
精支!

楼主请留下APK吧~
雪    币: 2320
活跃值: (3971)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
熊猫正正 9 2013-8-15 10:04
7
0
非常不错,学习,学习,非常简单明了,其实重点就是:修改精灵的属性和游戏的逻辑~~"cocos2d主要采用C++开发,而libgdx则主要采用java方式开发"这里有一个小错误,指证一下,cocos2d是apple专用2d引擎,采用oc编写,不能跨平台,然后国内牛人又将cocos2d改为就c++实现的cocos2d-x,可以跨平台~~楼主分析安卓上飞机游戏是用libgdx,我想apple上的应该是用cocos2d写的了
雪    币: 102
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
lgwinner 2013-8-15 10:23
8
0
LZ是真正高手!!
第一天我也拆开看了,找到了shoot里面的函数,里面的函数功能还是很明显比较容易改的
但是修改后一直启动不起来。
后来也发现了MD5的问题,改了文件MD5,修改完签名还是跑不起来!我还是没有理解到更深层原理
支持楼主!
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 11:21
9
0
呵呵,措辞疏忽了。本意是指cocos-2d系列游戏引擎的。
雪    币: 2320
活跃值: (3971)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
熊猫正正 9 2013-8-15 11:28
10
0
看了你之前的几篇文章,学习了,谢谢分享~~
雪    币: 761
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
赤子Anatta 2013-8-15 13:09
11
0
顶一个~  不知道淘宝上的代打飞机是不是这个。。
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 14:10
12
0
呵呵,互相学习~
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fishisjava 2013-8-15 14:23
13
0
楼主能否分享下apk啊,翡翠感谢
雪    币: 10042
活跃值: (15979)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhczf 2013-8-15 14:45
14
0
楼主牛人啊,这么快就找到漏洞破解了
雪    币: 307
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
痞子辉 1 2013-8-15 15:22
15
0
我按照楼主一步一步试了,不行,文件夹都变成D:\11\smali\com\tencent\mm\plugin\shootstub了
雪    币: 7300
活跃值: (3758)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 22 2013-8-15 15:23
16
0
最后一步的安全漏洞好像有点难度

我这里,copy到/system/app/里面后,点微信,过了十几秒,提示微信已停止
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 16:20
17
0
报什么错呢?
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 16:33
18
0
这个文件夹不对哦。你这份是微信的反编译代码吧?
要取assets\preload\下的jar包哦。
雪    币: 427
活跃值: (49)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pwelyn 2013-8-15 16:44
19
0
这个相当强悍 学习一下
雪    币: 7300
活跃值: (3758)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
海风月影 22 2013-8-15 17:26
20
0
没任何报错,只有提示,微信已停止

可能还没弄明白
雪    币: 27
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
CoyLiu 2013-8-15 19:26
21
0
膜拜,感谢楼主分享。
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
glliuxueke 2013-8-15 19:45
22
0
楼主,为什么我用apktool d 微信.apk,反编译过程中有些错误信息,类似这样的形式:Could not decode file, replacing by FASLE value: drawable-hdpi/xxxx.png. 有没有其它大侠遇到过这样的错误。你们都能正常反编译吗?
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
muyiqiusuo 2013-8-15 19:47
23
0
多谢分享
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 23:08
24
0
资源问题,不用管它。我们只需要classes.dex就行。
雪    币: 480
活跃值: (185)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
ZhWeir 6 2013-8-15 23:09
25
0
Log里应该有报错吧?有一些机型有这个问题。我马上会编辑主贴,做个补充说明。
游客
登录 | 注册 方可回帖
返回