android版微信打飞机无敌补丁分析及其制作方法

来源:互联网 发布:微信公众号加粉软件 编辑:程序博客网 时间:2024/05/04 12:12

本文出自:http://www.creturn.com/android版微信打飞机无敌补丁分析及其制作方法/

原创作品,转载请注明来源及其作者信息,负责后果自负!

最近微信5.0版本发布后增加了游戏中心,并且自带一款打飞机游戏,ios版本刚发布1天就被crack掉,并且除了一个无敌补丁,奈何手里没ios设备也没法测试.自己玩了下,感觉游戏真没多少技术含量,不过微信的优势很明显,集成了好友数据,所以结果就是最近天天听到那些家伙喊着”打飞机” ~。~

不过对于游戏一点都不感冒的我看到好友那么高的分数再对比下自己,额真有点那个啥。所以对于技术控来说去拼命玩那个玩意就有点浪费生命了,所以本着hack for fun 的思想就试试看看能crack掉不.

首先分析下游戏

游戏对象:

飞机,子弹,炸弹,敌机
实现方法就有多种成为无敌的方法:

1.让飞机无敌,也就是不死

2.让子弹威力变大,并且不消失,这样一个子弹就可以打多个敌机

3.给自己添加”大量”炸弹,这样也就无敌了

4.让敌机碰到自己无效,这样就相当于隐形模式了,同样无敌了

5.给自己多加几条名,这样既可以达到无敌的方式又可以死掉(方便提交分数)不然死都死不掉。

代码分析:

刚开始看到这个游戏以为用的是html5+js写的,不过解包后看到里面的东西就傻眼了,不过依然有方法.

1.下载 5.0 android的版本的微信,修改后缀名为zip然后解压,如图:


2.在解压的目录中找到assset目录然后打开里面的preload目录,如图:


可以看到这个目录放了一些jar包,猜测微信采用插件机制来实现功能模块的扩展,其中以”com.tencent.mm.plugin.shoot”开头的jar包,从名字中可以猜测到它就是我们的目标

这里要说后面需要用到的两款软件:

1.apktool :用来把apk或者jar包反编译成android的java虚拟机的机器码,方便修改代码逻辑

下载地址: https://code.google.com/p/android-apktool/

2.dex2jar :用来把dex文件反编译jar

下载地址: http://pan.baidu.com/share/link?shareid=2401317361&uk=2317334154

3.auto-sign: 用来对apk进行签名的

下载地址: http://pan.baidu.com/share/link?shareid=2387101337&uk=2317334154

4.jd-gui: 用来查看编译过的class java代码

下载地址: http://java.decompiler.free.fr/?q=jdgui
工具齐全后就开始对代码动刀

用dex2jar把com.tencent.mm.plugin.shoot开头的那个文件处理下,会得到以dex2jar.jar结尾的文件用jd-gui打开这个文件,我们就能看到编译出来的文件,不过腾讯的同学对代码进行了混淆处理所以里面有很多a,b,c,d,e这样的文件,不过很不幸的是腾讯的家伙估计太粗心了,把游戏对象和功能代码没做混淆,混淆的反而是gdx游戏框架的代码,如图:

在actor这个包里面明显能看出来各个类的作用,不知道腾讯的同学是妹子想多了还是不给发奖金了,核心部分不做混淆处理…

上面分析的时候说过无敌模式的几种方式,我这里采用最后一种给自己多加几条命这样也能死掉~~  不然分数都提交不了就没有意义了,看看Player类中的构造函数(或者叫做初始化函数也行):

1public Player()
2 {
3 setLiftCount(1);
4 setType(GameSprite.Type.HERO);
5 setState(GameSprite.State.FLIGTHING);
6 setSpeedVelocity(new ag(0.0F, 0.0F));
7 getBounds().height = HEIGHT;
8 getBounds().width = WIDTH;
9 this.mShootDelay = (4.0F * h.Ml().MC().Mi().cEP);
10 this.mShootDoubleTime = h.Ml().MC().Mi().cEQ;
11 }

明显能够看出来setLiftCount() 这个方法是用来初始化生命值的,如果把这里改大点,不就实现了我们的多条命了。

用apktool工具对 com.tencent.mm.plugin.shoot开头的这个包进行反编译,命令如下:

1apktool d 文件名

后面的d参数是反编译,如果换成b就是再次编译回去。

解包后文件如下图所示:

其中smali目录就是反编译后的代码,里面的文件以 smali结尾,文件位置和包位置保持一致如下图:

用任意一款文本编辑器打开Player.smali文件,我们可以看到里面的代码,如下图:

仔细看有点像汇编,不过它却不是网上可以找到smali语法帮助,我们在这个文件中找到初始化方法,constructor <init>()看着是不是很眼熟:

1.method public constructor <init>()V
2 .locals 2
3 
4.prologue
5 const/4 v1, 0x0
6 
7.line 46
8 invoke-direct {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;-><init>()V
9 
10.line 32
11 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/Player$BulletType;->NORMAL:Lcom/tencent/mm/plugin/shoot/actor/Player$BulletType;
12 
13iput-object v0, p0, Lcom/tencent/mm/plugin/shoot/actor/Player;->mBulleType:Lcom/tencent/mm/plugin/shoot/actor/Player$BulletType;
14 
15.line 47
16 const/4 v0, 0x1
17 
18invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setLiftCount(I)V
19 
20.line 48
21 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->HERO:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
22 
23invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setType(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;)V
24 
25.line 49
26 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;->FLIGTHING:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;
27 
28invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setState(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;)V
29 
30.line 50
31 new-instance v0, Lcom/badlogic/gdx/math/ag;
32 
33invoke-direct {v0, v1, v1}, Lcom/badlogic/gdx/math/ag;-><init>(FF)V
34 
35invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setSpeedVelocity(Lcom/badlogic/gdx/math/ag;)V
36 
37.line 52
38 invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->getBounds()Lcom/badlogic/gdx/math/af;
39 
40move-result-object v0
41 
42sget v1, Lcom/tencent/mm/plugin/shoot/actor/Player;->HEIGHT:F
43 
44iput v1, v0, Lcom/badlogic/gdx/math/af;->height:F
45 
46.line 53
47 invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->getBounds()Lcom/badlogic/gdx/math/af;
48 
49move-result-object v0
50 
51sget v1, Lcom/tencent/mm/plugin/shoot/actor/Player;->WIDTH:F
52 
53iput v1, v0, Lcom/badlogic/gdx/math/af;->width:F
54 
55.line 55
56 invoke-static {}, Lcom/tencent/mm/plugin/shoot/a/h;->Ml()Lcom/tencent/mm/plugin/shoot/a/h;
57 
58move-result-object v0
59 
60invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/h;->MC()Lcom/tencent/mm/plugin/shoot/a/d;
61 
62move-result-object v0
63 
64invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/d;->Mi()Lcom/tencent/mm/plugin/shoot/a/b;
65 
66move-result-object v0
67 
68iget v0, v0, Lcom/tencent/mm/plugin/shoot/a/b;->cEP:F
69 
70const/high16 v1, 0x4080
71 
72mul-float/2addr v0, v1
73 
74iput v0, p0, Lcom/tencent/mm/plugin/shoot/actor/Player;->mShootDelay:F
75 
76.line 59
77 invoke-static {}, Lcom/tencent/mm/plugin/shoot/a/h;->Ml()Lcom/tencent/mm/plugin/shoot/a/h;
78 
79move-result-object v0
80 
81invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/h;->MC()Lcom/tencent/mm/plugin/shoot/a/d;
82 
83move-result-object v0
84 
85invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/d;->Mi()Lcom/tencent/mm/plugin/shoot/a/b;
86 
87move-result-object v0
88 
89iget v0, v0, Lcom/tencent/mm/plugin/shoot/a/b;->cEQ:I
90 
91int-to-long v0, v0
92 
93iput-wide v0, p0, Lcom/tencent/mm/plugin/shoot/actor/Player;->mShootDoubleTime:J
94 
95.line 60
96 return-void
97.end method

根据smali语法修改如下代码:

1.line 47
2const/4 v0, 0x1
3 
4invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setLiftCount(I)V

改为:

1.line 47
2const/4 v0, 0x7  # 注意这里修改成7
3 
4invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/Player;->setLiftCount(I)V
修改的地方把默认的1改成了7,也就是说有7条命了。不过别高兴太早,如果这样改了,是没有效果的。因为程序中判断飞机不在战斗状态时候
是不显示的,所以还需要修改一处代码,先看看原来的java代码GameSprite.smali:
1public void hit(boolean paramBoolean)
2 {
3this.liftCount = (-1 this.liftCount);
4if (this.liftCount <= 0)
5{
6if (paramBoolean)
7{
8setState(GameSprite.State.DEAD);
9setSpeedVelocity(this.speedZero);
10return;
11}
12if ((getType() == GameSprite.Type.ENEMY_AIRCAFT) || (getType() == GameSprite.Type.ENEMY_LARGE_AIRCAFT) || (getType() == GameSprite.Type.ENEMY_MIDDLE) || (getType() == GameSprite.Type.PROPS_BOMB) || (getType() == GameSprite.Type.PROPS_DOUBLE))
13h.Ml().MD().c(getType());
14while (true)
15{
16setState(GameSprite.State.EXPLODING);
17break;
18if (getType() == GameSprite.Type.HERO)
19h.Ml().MD().MT();
20}
21}
22setState(GameSprite.State.HITING);
23 }
这段代码是所有游戏对象基类里面的碰撞处理代码,当生命值小于1 就移除该对象,如果生命值大于1则更改属性为HITING ,不过飞机如果遇到这
个状态肯定不行的,撞机了还能继续飞?所以这里需要判断下如果是飞机,那么就要修改它的状态为:FLIGTHING
所以如果按照java代码修改的代码会和下面的代码一样:
1public void hit(boolean paramBoolean)
2{
3this.liftCount = (-1 this.liftCount);
4if (this.liftCount <= 0)
5{
6if (paramBoolean)
7{
8setState(GameSprite.State.DEAD);
9setSpeedVelocity(this.speedZero);
10return;
11}
12if ((getType() == GameSprite.Type.ENEMY_AIRCAFT) || (getType() == GameSprite.Type.ENEMY_LARGE_AIRCAFT) || (getType() == GameSprite.Type.ENEMY_MIDDLE) || (getType() == GameSprite.Type.PROPS_BOMB) || (getType() == GameSprite.Type.PROPS_DOUBLE))
13h.Ml().MD().c(getType());
14while (true)
15{
16setState(GameSprite.State.EXPLODING);
17break;
18if (getType() == GameSprite.Type.HERO)
19h.Ml().MD().MT();
20}
21}
22 
23//在这里添加我们的代码
24 
25if(getType==GameSprite.Type.HERO)
26 
27{
28 
29setState(GameSprite.State.FLIGTHING);
30 
31else {
32setState(GameSprite.State.HITING);
33 
34}
35}
java 代码我们知道怎么修改了,那么smali里面的代码同样根据这个逻辑处理下即可,当然这块稍微有点难度,得看下语法手册再来修改,
修改的代码如下所示:
1.method public hit(Z)V
2 .locals 2
3 .parameter
4 
5.prologue
6 .line 45
7 iget v0, p0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->liftCount:I
8 
9add-int/lit8 v0, v0, -0x1
10 
11iput v0, p0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->liftCount:I
12 
13.line 46
14 iget v0, p0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->liftCount:I
15 
16if-gtz v0, :cond_4
17 
18.line 47
19 if-eqz p1, :cond_0
20 
21.line 48
22 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;->DEAD:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;
23 
24invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->setState(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;)V
25 
26.line 57
27 :goto_0
28 iget-object v0, p0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->speedZero:Lcom/badlogic/gdx/math/ag;
29 
30invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->setSpeedVelocity(Lcom/badlogic/gdx/math/ag;)V
31 
32.line 61
33 :goto_1
34 return-void
35 
36.line 50
37 :cond_0
38 invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
39 
40move-result-object v0
41 
42sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->ENEMY_AIRCAFT:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
43 
44if-eq v0, v1, :cond_1
45 
46invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
47 
48move-result-object v0
49 
50sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->ENEMY_LARGE_AIRCAFT:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
51 
52if-eq v0, v1, :cond_1
53 
54invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
55 
56move-result-object v0
57 
58sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->ENEMY_MIDDLE:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
59 
60if-eq v0, v1, :cond_1
61 
62invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
63 
64move-result-object v0
65 
66sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->PROPS_BOMB:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
67 
68if-eq v0, v1, :cond_1
69 
70invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
71 
72move-result-object v0
73 
74sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->PROPS_DOUBLE:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
75 
76if-ne v0, v1, :cond_3
77 
78.line 51
79 :cond_1
80 invoke-static {}, Lcom/tencent/mm/plugin/shoot/a/h;->Ml()Lcom/tencent/mm/plugin/shoot/a/h;
81 
82move-result-object v0
83 
84invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/h;->MD()Lcom/tencent/mm/plugin/shoot/a/l;
85 
86move-result-object v0
87 
88invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
89 
90move-result-object v1
91 
92invoke-virtual {v0, v1}, Lcom/tencent/mm/plugin/shoot/a/l;->c(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;)V
93 
94.line 55
95 :cond_2
96 :goto_2
97 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;->EXPLODING:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;
98 
99invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->setState(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;)V
100 
101goto :goto_0
102 
103.line 52
104 :cond_3
105 invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
106 
107move-result-object v0
108 
109sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->HERO:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
110 
111if-ne v0, v1, :cond_2
112 
113.line 53
114 invoke-static {}, Lcom/tencent/mm/plugin/shoot/a/h;->Ml()Lcom/tencent/mm/plugin/shoot/a/h;
115 
116move-result-object v0
117 
118invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/h;->MD()Lcom/tencent/mm/plugin/shoot/a/l;
119 
120move-result-object v0
121 
122invoke-virtual {v0}, Lcom/tencent/mm/plugin/shoot/a/l;->MT()V
123 
124goto :goto_2
125 
126###注意这里是我家的代码
127 
128invoke-virtual {p0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->getType()Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
129 
130move-result-object v0
131 
132sget-object v1, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;->HERO:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$Type;
133 
134if-ne v0, v1, :cond_11
135 
136###本段结束
137 
138.line 59
139 :cond_4
140 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;->HITING:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;
141 
142invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->setState(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;)V
143 
144###注意这里是我家的代码
145 :cond_11
146 sget-object v0, Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;->FLIGTHING:Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;
147 
148invoke-virtual {p0, v0}, Lcom/tencent/mm/plugin/shoot/actor/GameSprite;->setState(Lcom/tencent/mm/plugin/shoot/actor/GameSprite$State;)V
149 
150###本段结束
151 
152goto :goto_1
153.end method

同理,需要给自己飞机多增加一些炸弹或者双子弹等都可以在palyer初始化的时候调用相应的方法,根据添加的方法写出对应的smali代码就能实现上面分析的无敌模式的多种情况 接下来我们需要进行打包,修改完代码后,用如下命令打包

1apk b 解包的包文件夹名称

这里需要注意的是,打包后必须进行签名,不然只对微信的apk包做签名处理是不起作用的。 签名命令如下:

1# 注意 update.zip 是需要签名的文件 update_signed.zip 是签名后的文件
2java -jar signapk.jar testkey.x509.pem testkey.pk8 update.zip update_signed.zip

签名后把微信的apk安装包重命名为zip结尾,然后用压缩工具打开,替换里面相应的com.tencent.mm.plugin.shoot.XXXXXX
替换后对微信安装包重新签名即可,注意用adb安装程序的话不管什么结尾的文件名都行,要是copy到内存卡中进行安装必须改成apk不然识别不了。
这里提供一个改好的apk安装包,下载地址:http://pan.baidu.com/share/link?shareid=1113420314&uk=2317334154
注意:修改别人的软件是不合法的,所以这里提供的修改版本安装包我可没说是自己改的或许是从网上找的,大家懂得就行。