【文章标题】: 利用X动支付函数特征破解移动新游“猎魔X士1”
【文章作者】: Rlcupk(御剑)
【作者邮箱】: 408885352@qq.com
【作者主页】: 无
【作者QQ号】: 无
【软件名称】: 猎魔x士1
【下载地址】:
536K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4m8S2L8W2)9J5k6h3u0S2K9h3c8#2i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8U0q4Z5M7i4y4i4x3W2Z5$3i4K6t1$3L8X3u0K6M7q4)9K6b7W2)9J5y4X3&6T1M7%4m8Q4x3@1u0Q4c8e0c8Q4b7U0S2Q4b7V1q4Q4c8e0k6Q4z5e0k6Q4b7U0W2Q4c8e0c8Q4b7V1g2Q4b7V1k6Q4c8e0k6Q4z5e0k6Q4b7U0m8Q4c8e0k6Q4z5o6W2Q4z5p5u0Q4c8e0N6Q4b7e0m8Q4z5e0c8Q4c8e0N6Q4b7e0W2Q4b7U0k6Q4c8e0k6Q4z5o6S2Q4z5e0q4Q4c8e0g2Q4b7U0m8Q4b7U0q4Q4c8e0k6Q4z5p5q4Q4z5p5q4Q4c8e0S2Q4b7V1k6Q4z5e0W2Q4c8e0c8Q4b7U0S2Q4b7f1q4Q4c8e0N6Q4z5o6W2Q4z5o6S2Q4c8e0k6Q4z5f1y4Q4b7f1y4Q4c8e0c8Q4b7U0S2Q4z5p5q4Q4c8e0c8Q4b7V1y4Q4b7e0m8Q4c8e0N6Q4z5e0W2Q4b7V1g2Q4c8e0g2Q4b7V1q4Q4b7e0k6Q4c8e0N6Q4b7V1c8Q4z5e0q4Q4c8e0N6Q4z5f1u0Q4z5e0S2Q4c8e0g2Q4z5e0m8Q4b7e0M7`.
【加壳方式】: 无
【编写语言】: JAVA
【使用工具】: ApkIDE
【软件介绍】: 【安卓游戏】没什么好介绍的...
【作者声明】: 只是技术交流,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
小菜也只是刚接触移动安全,对JAVA并不是很了解. 如有失误之处还请见谅...
1.用ApkIDE 打开 猎魔x士1
2.搜索X动支付函数特征:onResult
请看图1

我们会来到X动支付特征函数的段首
# virtual methods
.method public onResult(ILjava/lang/String;Ljava/lang/Object;)V
.locals 4
.param p1, "resultCode" # I
.param p2, "billingIndex" # Ljava/lang/String;
.param p3, "obj" # Ljava/lang/Object;
.prologue
.line 285
const-string v1, ""
.line 286
.local v1, "result":Ljava/lang/String;
packed-switch p1, :pswitch_data_0
.line 304
:goto_0
return-void
.line 288
:pswitch_0
const-string v2, "001"
if-ne p2, v2, :cond_0
.line 289
const/4 v2, 0x6
invoke-static {v2}, Lcom/droidhen/defender/game/Shop;->getItem(I)V
goto :goto_0
.line 291
:cond_0
sget-object v2, Lcom/droidhen/defender/GameActivity;->currentItem:Ljava/lang/String;
invoke-static {v2}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/Integer;->intValue()I
move-result v0
.line 292
.local v0, "itemID":I
invoke-static {v0}, Lcom/droidhen/defender/game/Research;->billSuccess(I)V
goto :goto_0
.line 296
.end local v0 # "itemID":I
:pswitch_1
const-string v1, "\u8d2d\u4e70\u5931\u8d25\uff01"
.line 297
invoke-static {}, Lcom/droidhen/defender/GameActivity;->getContext()Landroid/content/Context;
move-result-object v2
const/4 v3, 0x0
invoke-static {v2, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v2
.line 298
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
goto :goto_0
.line 286
:pswitch_data_0
.packed-switch 0x1
:pswitch_0
:pswitch_1
.end packed-switch
.end method
第一次接触的童鞋肯定眼花了...
那么我们在打开JAVA源码看看
package com.droidhen.defender;
import android.widget.Toast;
import cn.cmgame.billing.api.GameInterface.IPayCallback;
import com.droidhen.defender.game.Research;
import com.droidhen.defender.game.Shop;
class GameActivity$1
implements GameInterface.IPayCallback
{
public void onResult(int paramInt, String paramString, Object paramObject)
{
switch (paramInt)
{
default:
return;
case 1:
if (paramString == "001")
{
Shop.getItem(6);
return;
}
Research.billSuccess(Integer.valueOf(GameActivity.currentItem).intValue());
return;
case 2:
}
Toast.makeText(GameActivity.getContext(), "购买失败!", 0).show();
}
}
感觉明了多了...有木有...
下面我们进行大概的分析下(注意看注释)
package com.droidhen.defender;
import android.widget.Toast;
import cn.cmgame.billing.api.GameInterface.IPayCallback;
import com.droidhen.defender.game.Research;
import com.droidhen.defender.game.Shop;
class GameActivity$1
implements GameInterface.IPayCallback
{
public void onResult(int paramInt, String paramString, Object paramObject)
{
switch (paramInt) //判断是否确认支付
{
default: //取消支付
return;
case 1: //支付成功
if (paramString == "001") //判断游戏内购所需支付的类型
{
Shop.getItem(6); //游戏道具
return;
}
Research.billSuccess(Integer.valueOf(GameActivity.currentItem).intValue()); //游戏激活
return;
case 2: //支付失败
}
Toast.makeText(GameActivity.getContext(), "购买失败!", 0).show();
}
}
# virtual methods
.method public onResult(ILjava/lang/String;Ljava/lang/Object;)V
.locals 4
.param p1, "resultCode" # I
.param p2, "billingIndex" # Ljava/lang/String;
.param p3, "obj" # Ljava/lang/Object;
.prologue
.line 285
const-string v1, ""
.line 286
.local v1, "result":Ljava/lang/String;
packed-switch p1, :pswitch_data_0 //判断是否确认支付 如确定支付则跳转到 :pswitch_data_0
//如取消支付则返回
.line 304
:goto_0
return-void //返回
.line 288
:pswitch_0
const-string v2, "001"
//猎魔勇士1 支付购买类型有两种...
//1.游戏商店
//2.游戏激活
if-ne p2, v2, :cond_0 //判断游戏内购所需支付的类型, 如果是游戏激活则跳转到:cond_0 否则往下执行(游戏道具购买)
.line 289
const/4 v2, 0x6
invoke-static {v2}, Lcom/droidhen/defender/game/Shop;->getItem(I)V
goto :goto_0
.line 291
:cond_0
sget-object v2, Lcom/droidhen/defender/GameActivity;->currentItem:Ljava/lang/String;
invoke-static {v2}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/Integer;->intValue()I
move-result v0
.line 292
.local v0, "itemID":I
invoke-static {v0}, Lcom/droidhen/defender/game/Research;->billSuccess(I)V
goto :goto_0
.line 296
.end local v0 # "itemID":I
:pswitch_1
const-string v1, "\u8d2d\u4e70\u5931\u8d25\uff01" // "\u8d2d\u4e70\u5931\u8d25\uff01" 转换为ASCII 就是“购买失败”
.line 297
invoke-static {}, Lcom/droidhen/defender/GameActivity;->getContext()Landroid/content/Context;
move-result-object v2
const/4 v3, 0x0
invoke-static {v2, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v2
.line 298
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
goto :goto_0
.line 286
:pswitch_data_0
.packed-switch 0x1 //判断是否购买成功
:pswitch_0 //购买成功则跳往:pswitch_0
:pswitch_1 //购买失败则跳往:pswitch_1
.end packed-switch
.end method
经过大概分析后 现在我们逆向起来就比较简单了吧! 相信后面的操作大家都可以自己做完了
现在由我来演示下吧...
# virtual methods
.method public onResult(ILjava/lang/String;Ljava/lang/Object;)V
.locals 4
.param p1, "resultCode" # I
.param p2, "billingIndex" # Ljava/lang/String;
.param p3, "obj" # Ljava/lang/Object;
.prologue
.line 285
const-string v1, ""
.line 286
.local v1, "result":Ljava/lang/String;
//经过分析我们已知大概流程...那么我们试试是否可以直接在判断是否购买之前就跳转到购买成功段 :pswitch_0 来实现,在提示购买界面时就已经购买成功了呢?
goto :pswitch_0 //我们使用goto 语句来看看我们的猜测是否正确
packed-switch p1, :pswitch_data_0 //判断是否确认购买 如确定支付则跳转到 :pswitch_data_0
//如取消购买则往下执行(返回)
.line 304
:goto_0
return-void //返回
.line 288
:pswitch_0
const-string v2, "001"
//猎魔勇士1 支付购买类型有两种...
//1.游戏商店
//2.游戏激活
if-ne p2, v2, :cond_0 //判断游戏内购所需支付的类型, 如果是游戏激活则跳转到:cond_0 否则往下执行(游戏道具购买)
.line 289
const/4 v2, 0x6
invoke-static {v2}, Lcom/droidhen/defender/game/Shop;->getItem(I)V
goto :goto_0
.line 291
:cond_0
sget-object v2, Lcom/droidhen/defender/GameActivity;->currentItem:Ljava/lang/String;
invoke-static {v2}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/Integer;->intValue()I
move-result v0
.line 292
.local v0, "itemID":I
invoke-static {v0}, Lcom/droidhen/defender/game/Research;->billSuccess(I)V
goto :goto_0
.line 296
.end local v0 # "itemID":I
:pswitch_1
const-string v1, "\u8d2d\u4e70\u5931\u8d25\uff01" // "\u8d2d\u4e70\u5931\u8d25\uff01" 转换为ASCII 就是“购买失败”
.line 297
invoke-static {}, Lcom/droidhen/defender/GameActivity;->getContext()Landroid/content/Context;
move-result-object v2
const/4 v3, 0x0
invoke-static {v2, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v2
.line 298
invoke-virtual {v2}, Landroid/widget/Toast;->show()V
goto :goto_0
.line 286
:pswitch_data_0
.packed-switch 0x1 //判断是否购买成功
:pswitch_0 //购买成功则跳往:pswitch_0
:pswitch_1 //购买失败则跳往:pswitch_1
.end packed-switch
.end method
OK 修改完毕...咱们在修改保存,重新编译,签名,测试
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课