今天装了某个游戏,游戏中有“商店”,可以用金币购买相关物品。而获得金币的途径,是用人民币购买(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, v10iput 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, v10iput 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。后来放到本地磁盘中进行才一切正常。
最后说一句,好的游戏从来不会用奇怪的货币和商城来吸引玩家或者玩家的钱财。
大挽尊之术
金币太多会不会爆?
32位整数,你去点爆吧。
膜拜
0
我更喜欢 八门神器
你好,能教我如何改sDk包名吗?我想学习反编译。先谢谢了
。
:
请问将中文转换成UTF-8裸码的工具有吗?
好游戏是不会把购买限制仅仅放在客户端的……