信息安全技术大赛——破解apk

时间:2013-05-25 | 分类:个人日志,学习园地 | 浏览:8022 | 评论:13 | 发表评论

题目标题:可以用金币购买的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文件夹,执行命令:

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,下面为验证金币的代码:

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代码里有一些跳转语句,但是在mac反编译出来的却没有。
根据上面的判断条件,如果金币在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:

./apktool d -f Game.apk game

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

.
├── 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,代码如下:

.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的数值就行了,不妨改成:

const/16 v2, 0x6363

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

./apktool b game

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

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

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

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

所以破解apk的一般流程是:
1、解压apk,获取里面的classes.dex。
2、用dex2jar把classes.dex反编译成jar。
3、用JD-GUI打开jar文件查看java代码,确定要修改代码的地方。
4、用apktool反编译apk,对照JD-GUI的java代码修改smali代码。
5、再把smali代码编译成apk。
6、给apk签名。

标签: , , ,
本文链接: 信息安全技术大赛——破解apk
版权所有: 破博客, 转载请注明本文出处。

13个评论

  1. 乌托邦
    2013/12/06 09:53:52

    :?: 终端是神马神器…
    “./apktool d -f Game.apk game”命令不受用- -.

  2. 狂奔的蜗牛
    2013/10/20 17:18:56

    :evil: 不错。
    网盘的外链不能用,修复下呗。

  3. fuck
    2013/10/06 23:04:02

    第二步还必须在linux下才行?

  4. 丸子
    2013/08/15 22:23:47

    我想要你啊。 :!:

  5. 小A
    2013/07/15 14:38:43

    APKtool是一个神器,这个APP是用来练手的么? :roll:

    • admin
      2013/07/15 15:06:51

      这个app是用来做教程的。

  6. osora
    2013/06/17 14:34:43

    妈妈再也不用担心安卓的收费应用了

  7. arthinking
    2013/05/29 23:53:38

    学习了 :wink: (没找到比较符合的表情,就用这个吧)

发表评论

您的昵称: *

您的邮箱: * (显示gravatar头像)

联系方式: