Android中Java编写的APK使用apktool反编译并修改smali

今天装了某个游戏,游戏中有“商店”,可以用金币购买相关物品。而获得金币的途径,是用人民币购买(1元100只)或者安装该公司的其他应用(安装3款得一点点)。

这显然不科学啊!

当然,程序在我机子上,我们当然能够用科学的手段来对付不科学的游戏货币商城制度。

1、使用apktool进行反编译,得到smali的字节码

假设游戏安装文件为my_game.apk,我们将把它反编译到mygame目录下。

这里下载apktool和对应的dependencies,把apktool和对应的dependencies加压缩到一起,并将该文件夹添加到path环境变量中。我在使用Windows系统,这时候apktool的解压文件夹有以下内容:

aapt.exe

apktool.bat

apktool.jar

然后对my_game.apk进行反编译,运行命令:

apktool d my_game.apk mygame

可以看到apktool将游戏反编译到mygame文件夹中。其中的smali就是对应的字节码。

2、修改smali字节码

关于smali字节码的寄存器可以参考这里,类型、函数和成员可以参考这里,操作符号可以参考这里

当然,由于程序已经混淆,所以不能从文件名和包名中猜测相关信息。这时候有好几个办法定位到要修改的地方。如调试设断点,在这里有教程。还可以通过资源和字符串定位,这是我现在使用的方法,因为我的调试环境还没搭好……

我注意到,某一个与购买相关的按钮图片的id编号为“0x7f020093”,于是在smali中搜索,最后在某个文件夹,也就对应Java的某个包中找到g.smali,这个文件包含了字符串“0x7f020093”。然后,点击购买时,会提示“金币不足,无法购买”,这是文本信息。也就是说,可以在g.smali中搜索该字符串,或者字符串子串来进行程序上下文的定位。当然,直接搜索中文字符串是一无所获的,因为反编译器将中文以utf8的裸编码格式表现。这时候在g.smali中搜索“\u91d1\u5e01\u4e0d\u8db3,\u65e0\u6cd5\u8d2d\u4e70”,找到详细位置!具体代码片段如下:

sget-object v0, La/f/c;->s:La/a/b/g;

iget-object v9, v0, La/a/b/g;->j:Ld/a/b;

iget v10, p2, La/d/n;->f:I

iget v0, v9, Ld/a/b;->v:I

if-ge v0, v10, :cond_0

invoke-static {}, Lcom/gale/manager/f;->a()Lcom/gale/manager/f;

move-result-object v0

const-string v1, "\u91d1\u5e01\u4e0d\u8db3,\u65e0\u6cd5\u8d2d\u4e70"

invoke-virtual {v0, v1}, Lcom/gale/manager/f;->a(Ljava/lang/String;)V

:goto_0
return-void

:cond_0
neg-int v0, v10

iput v0, v9, Ld/a/b;->x:I

需要关注的是“if-ge”这句,意思是如果v0大于等于v10,则跳到cond_0执行,否则显示“金币不足,无法购买”并返回。

我们可以直接将“if-ge”改成“if-le”解决问题,不过这时金币会在购买后变负数,说不定会把游戏crash。所以,更好的修改方法如下:

    sget-object v0, La/f/c;->s:La/a/b/g;

    iget-object v9, v0, La/a/b/g;->j:Ld/a/b;

    iget v10, p2, La/d/n;->f:I

    iget v0, v9, Ld/a/b;->v:I

    if-ge v0, v10, :cond_0
    goto/16 :cond_0

    :goto_0
    return-void

    :cond_0
    move v0, v10

    iput v0, v9, Ld/a/b;->x:I

意思是,即使当前金币小于购买所需金币,也跳到条件成立的地方执行。另外,执行时会将玩家的金币数加上所需金币的相反数,即“neg-int v0, v10”,将其改为“move v0, v10”就可以每次都把玩家的金币数加上所需金币数。最终效果则是,即使金币不足也可以购买,并且越买钱越多。

3、打包、签名和安装修改后的apk

修改完了,就可以打包回apk了。执行以下命令:

apktool b mygame

在mygame目录下的dist在会看到打包好的apk。

当然,现在一般是无法安装的,因为apk还没有签名。下面就来签名。签名需要keystore文件,我已经有专用的keystore了,如果还没有,请参阅这里进行生成。

执行以下命令为重新编译的my_game.apk签名:

jarsigner -verbose -keystore creke.keystore my_game.apk Alias_name

最后,在安装到手机前,需要把手机中的已有版本先卸载,因为如果签名不同,是不能覆盖安装的,会提示“应用程序未安装”错误。

4、其他

Windows下的aapt似乎不能对非本地磁盘进行读写,比如我原来在内存盘中进行操作,apktool总是提示aapt出错,不能打包apk。后来放到本地磁盘中进行才一切正常。

最后说一句,好的游戏从来不会用奇怪的货币和商城来吸引玩家或者玩家的钱财。

9 comments

  1. LitmusBlue says:

    大挽尊之术
    金币太多会不会爆?

    1. creke says:

      32位整数,你去点爆吧。

  2. Anonymous says:

    膜拜

  3. Anonymous says:

    我更喜欢 八门神器

  4. Anonymous says:

    你好,能教我如何改sDk包名吗?我想学习反编译。先谢谢了

    :

  5. Anonymous says:

    请问将中文转换成UTF-8裸码的工具有吗?

  6. Anonymous says:

    好游戏是不会把购买限制仅仅放在客户端的……

Leave a comment