抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

题目标题:可以用金币购买的key
题目描述:努力赚金币买key吧。
题目附件:Game.apk

下载附件后解压,在Android手机或模拟器中安装apk:
This is a picture without description

要求有999个金币才能买key,但是因为余额只有99,所以买不了。
接下来就是反编译apk的时刻,首先下载dex2jar:
https://code.google.com/p/dex2jar/downloads/list

将Game.apk改名为Game.zip,然后用压缩软件解压。
把解压后的classes.dex文件放到dex2jar文件夹里,执行命令:

1
sh d2j-dex2jar.sh classes.dex

执行后生成了classes_dex2jar.jar文件。

再下载JD-GUI软件,作用是查看jar文件反编译后的java代码:
http://java.decompiler.free.fr/?q=jdgui

用JD-GUI打开classes-dex2jar.jar,搜索关键字"价格只能数字",就会转到判断金币的代码处:
This is a picture without description

可见a.class的包名是syclover.jerryl3e.cuitinfosecgamelevel1,下面为验证金币的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class a
implements View.OnClickListener
{
a(MainActivity paramMainActivity)
{
}

public void onClick(View paramView)
{
try
{
// 获取文本框输入的数字
int j = Integer.parseInt(MainActivity.a(this.a).getEditableText().toString());
i = j;
// 如果输入的数字小于等于0或者大于99,就弹出提示
if ((i > 99) || (i == 0) || (i <= 0))
{
MainActivity.a(this.a, "价格只能数字,而且要不能大于当前余额");
return;
}
}
catch (Exception localException)
{
// 这里会跳出循环?好像反编译后的代码有问题。
while (true)
int i = 0;
// 向服务器提交加密后的金币
ProgressDialog localProgressDialog = ProgressDialog.show(paramView.getContext(), "", "正在购买……", true, true);
h localh = new h(paramView.getContext(), localProgressDialog);
String[] arrayOfString1 = { "price" };
String[] arrayOfString2 = new String[1];
arrayOfString2[0] = MainActivity.a(this.a, MainActivity.a(this.a).getEditableText().toString(), "JerryL3e");
String[] arrayOfString3 = { "flag", "key" };
localh.a("http://www.jerryl3e.com/cuitandroidgame/api.php");
localh.a(arrayOfString1);
localh.b(arrayOfString2);
localh.c(arrayOfString3);
localh.start();
}
}
}

之前在Windows下反编译出的Java代码里有一些跳转语句,但是在MacOS反编译出来的却没有。
根据上面的判断条件,如果金币在1到99之间的话,就会转到下面的分支执行,用金币购买key时用了不少加密算法,好像先把金币用DES加密后再提交数据,验证成功后再用AES解密key。

由于游戏界面显示要输入999才能购买成功,所以最简单的方法就是修改上面的判断条件,但是在这里改是不行的,因为这个jar不能再编译成apk。
支持正反编译apk的只有apktool了,但是apktool反编译后的代码是smali代码,比较难懂。
虽然语法难懂,但是多看看帮助文档就懂了,那么下载apktool。
https://code.google.com/p/android-apktool/downloads/list

需要下载apktool1.5.2.tar.bz2apktool-install-macosx-r05-ibot.tar.bz2,解压后和Game.apk放到一起,文件如下图所示:
This is a picture without description

用终端进入apktool的文件夹后用以下命令反编译apk:

1
./apktool d -f Game.apk game

执行后生成了一个名字为game的文件夹,以下是game目录的树状图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.
├── AndroidManifest.xml
├── apktool.yml
├── res
│ └── ......
└── smali
├── android
│ └── ......
└── syclover
└── jerryl3e
└── cuitinfosecgamelevel1
├── MainActivity.smali
├── a.smali
├── b.smali
├── c.smali
├── d.smali
├── e.smali
├── f.smali
├── g.smali
├── h.smali
└── i.smali

根据包名syclover.jerryl3e.cuitinfosecgamelevel1找到a.smali,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.method public onClick(Landroid/view/View;)V

// ......

:goto_0
// 把16位(两字节)的0x63(99)放入v2寄存器
const/16 v2, 0x63
// 如果v0的值(用户输入的金币)大于v2,就跳到标签cond_0
if-gt v0, v2, :cond_0
// 如果v0的值等于0,就跳到标签cond_0
if-eqz v0, :cond_0
// 如果v0大于0就跳到cond_1,也就是购买key的地方
if-gtz v0, :cond_1

:cond_0
// 提示"价格只能数字,而且要不能大于当前余额"
iget-object v0, p0, Lsyclover/jerryl3e/cuitinfosecgamelevel1/a;->a:Lsyclover/jerryl3e/cuitinfosecgamelevel1/MainActivity;
const-string v1, "\u4ef7\u683c\u53ea\u80fd\u6570\u5b57\uff0c\u800c\u4e14\u8981\u4e0d\u80fd\u5927\u4e8e\u5f53\u524d\u4f59\u989d"
invoke-static {v0, v1}, Lsyclover/jerryl3e/cuitinfosecgamelevel1/MainActivity;->a(Lsyclover/jerryl3e/cuitinfosecgamelevel1/MainActivity;Ljava/lang/String;)V

:goto_1
// 返回,不执行下面的代码
return-void

:catch_0
// 异常处理
move-exception v0
move v0, v1
goto :goto_0

:cond_1
// 购买key
invoke-virtual {p1}, Landroid/view/View;->getContext()Landroid/content/Context;
move-result-object v0
const-string v2, ""
const-string v3, "\u6b63\u5728\u8d2d\u4e70\u2026\u2026"

// ......

.end method

根据上面的判断条件,只要把0x63改成一个大于999的数值就行了,不妨改成:

1
const/16 v2, 0x6363

这样的话999既不大于0x6363,也不等于0,而且大于0,所以会跳到购买key的地方。
保存后回到apktool文件夹,执行以下命令把smali文件编译成apk:

1
./apktool b game

执行后在game目录下生成了一个dist目录,里面就是编译好的Game.apk。
但这个apk是不能安装到手机的,因为还没签名,所以要下载签名工具:
https://github.com/glitterballs/release-tools/tree/master/SignApk

把编译出来的Game.apk改名为Game.zip,放到SignApk目录里。
用终端进入SignApk目录,执行以下命令:

1
java -jar signapk.jar certificate.pem key.pk8 Game.zip Game_signed.zip

执行后生成了Game_signed.zip,再改名为Game_signed.apk就可以在手机安装了。
安装后输入999金币购买,终于购买成功了:
This is a picture without description

评论