安卓逆向之二__《全民捕鱼》游戏内购破解
环境简介
系统:Android 4.4
工具:Windows 10 64bit 夜神模拟器
Android Killer
Java Decompiler
全民捕鱼游戏简介
游戏名称:全民捕鱼
游戏类型:休闲益智
游戏版本:1.7
游戏界面如下:
逆向分析
首先我们进入商城点击付费金币的购买,弹出"购买失败"的Toast(吐司)
根据这个提示我们使用AndroidKiller分析这个APK.看到入口函数为LogoActivity很简单.
直接使用特征Toast字符串搜索,没有搜到.
再次测试把字符串转换为UniCode形式(下边的小a大A按钮),再次搜索,找到一个字符串结果
双击到使用处的语句,查看源码发现此处有购买成功失败函数的选择调用语句
我们通过这几个函数继续查找对比,最后在搜索payFail的最后一个结果,发现重要函数所在
支付失败,与支付成功函数离得很近,分析发现,函数参数也相似
所以我们使用的破解内购的办法可以是,把支付成功函数的函数体,整个复制到支付失败函数里边去,让支付永远成功.
两个函数smali代码
.method public payFailed(Ljava/util/Map;I)V
.locals 5
.param p1, "params" # Ljava/util/Map;
.param p2, "arg1" # I
.prologue
.line 208
const-string v0, "cocos2d-x debug info"
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "Failed DX_payCode2 == "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
sget-object v2, Lcom/payCom/org/IAPListener;->DX_PAYCODES:[Ljava/lang/String;
iget-object v3, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v3, v3, Lcom/payCom/org/IAPListener;->curPayIndex:I
aget-object v2, v2, v3
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 209
const-string v0, "cocos2d-x debug info"
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "FaildCode == "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 210
iget-object v0, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v0, v0, Lcom/payCom/org/IAPListener;->curPayIndex:I
const/4 v1, 0x0
invoke-static {v0, v1}, Lcom/payCom/org/GameJni;->OderFinish(II)V
.line 211
sget-object v0, Lcom/payCom/org/IAPListener;->iapHandler:Lcom/payCom/org/IAPHandler;
sget-object v1, Lcom/payCom/org/IAPListener;->iapHandler:Lcom/payCom/org/IAPHandler;
const/16 v2, 0x2715
sget-object v3, Lcom/payCom/org/IAPListener;->DX_PAYCODES:[Ljava/lang/String;
iget-object v4, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v4, v4, Lcom/payCom/org/IAPListener;->curPayIndex:I
aget-object v3, v3, v4
invoke-static {v1, v2, v3}, Landroid/os/Message;->obtain(Landroid/os/Handler;ILjava/lang/Object;)Landroid/os/Message;
move-result-object v1
invoke-virtual {v0, v1}, Lcom/payCom/org/IAPHandler;->sendMessage(Landroid/os/Message;)Z
.line 212
return-void
.end method
.method public paySuccess(Ljava/util/Map;)V
.locals 5
.param p1, "params" # Ljava/util/Map;
.prologue
.line 202
const-string v0, "cocos2d-x debug info"
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "Success DX_payCode1"
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
sget-object v2, Lcom/payCom/org/IAPListener;->DX_PAYCODES:[Ljava/lang/String;
iget-object v3, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v3, v3, Lcom/payCom/org/IAPListener;->curPayIndex:I
aget-object v2, v2, v3
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 203
iget-object v0, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v0, v0, Lcom/payCom/org/IAPListener;->curPayIndex:I
const/4 v1, 0x1
invoke-static {v0, v1}, Lcom/payCom/org/GameJni;->OderFinish(II)V
.line 204
sget-object v0, Lcom/payCom/org/IAPListener;->iapHandler:Lcom/payCom/org/IAPHandler;
sget-object v1, Lcom/payCom/org/IAPListener;->iapHandler:Lcom/payCom/org/IAPHandler;
const/16 v2, 0x271a
sget-object v3, Lcom/payCom/org/IAPListener;->DX_PAYCODES:[Ljava/lang/String;
iget-object v4, p0, Lcom/payCom/org/IAPListener$1;->this$0:Lcom/payCom/org/IAPListener;
iget v4, v4, Lcom/payCom/org/IAPListener;->curPayIndex:I
aget-object v3, v3, v4
invoke-static {v1, v2, v3}, Landroid/os/Message;->obtain(Landroid/os/Handler;ILjava/lang/Object;)Landroid/os/Message;
move-result-object v1
invoke-virtual {v0, v1}, Lcom/payCom/org/IAPHandler;->sendMessage(Landroid/os/Message;)Z
.line 205
return-void
.end method
修改完成后,保存,并重新编译
在夜神模拟器上卸载之前的原版游戏,安装破解后的游戏,实现了商城内购破解
添加个人信息的破解
为了更有趣一点,我们在购买成功的提示上添加自己的个人信息
我们再次搜索到"购买成功"提示,在字符串之前加入"Hades破解:",如下,最后再次编译,安装测试
完成破解:
总结:
安卓游戏内购的破解简单的思路都是大同小异,也可以更改调用的函数参数等.smail代码与伪Java代码很接近自然语言逻辑思路,在没有安卓加固(壳)的游戏上做一些内购破解还是很简单的.去网上Download几个游戏练习一下破解就很有成就感.