信息安全技术大赛——破解apk
题目标题:可以用金币购买的key
题目描述:努力赚金币买key吧。
题目附件:Game.apk
下载附件后解压,在Android手机或模拟器中安装apk:
要求有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,搜索关键字"价格只能数字"
,就会转到判断金币的代码处:
可见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; 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.bz2
和apktool-install-macosx-r05-ibot.tar.bz2
,解压后和Game.apk放到一起,文件如下图所示:
用终端进入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的数值就行了,不妨改成:
这样的话999既不大于0x6363,也不等于0,而且大于0,所以会跳到购买key的地方。
保存后回到apktool文件夹,执行以下命令把smali文件编译成apk:
执行后在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金币购买,终于购买成功了: