火柴人联盟去签名验证去广告Android内购破解

—Creaked by B.S. 6/26/2017 9:22:40 PM

无聊练手,当作学习Android优秀源码的笔记

仅供学习研究,请勿用作商业用途,如若喜欢请支持正版!

最新版原程序:

百度下载

(v1.18.1)

http://www.anzhi.com/pkg/ced9_com.DBGame.DiabloLOL.anzhi.html

(v1.16.1)

http://www.appchina.com/app/com.DBGame.DiabloLOL.yyh

http://android.myapp.com/myapp/detail.htm?apkName=com.DBGame.DiabloLOL

火柴人联盟官网: http://huo.hoolaigames.com/

B.S.去签名去广告内购破解版:(无限内购)

百度下载(移动联通电信全网通+第三方支付接口版)

(v1.18.1) 链接: https://pan.baidu.com/s/1kRKTw96hJh1k7RHTrJowwQ 密码: rscw

(v1.16.1) 链接: https://pan.baidu.com/s/1i5OiXNZ 密码: vh7u

(v1.15.1) 链接: https://pan.baidu.com/s/1bLxtjo 密码: teyv

(v1.14.1) 链接: https://pan.baidu.com/s/1slTpHUH 密码: rt4r

联通接口的游戏联盟会员包月可以直接领铂金会员礼包无限内购版

也可以去各大安卓市场搜索下载最新版本:(推荐支付接口比较熟悉的移动,咪咕游戏,爱游戏)

爱游戏: http://www.play.cn/

咪咕游戏: http://g.10086.cn/

中国移动应用商城: http://mm.10086.cn/android

腾讯应用宝: http://android.myapp.com/

360手机助手: http://zhushou.360.cn/

百度旗下安卓市场: http://apk.hiapk.com/

安智市场: http://www.anzhi.com/

应用汇安卓市场: http://www.appchina.com/

魅族应用商店: http://app.flyme.cn/

小米游戏中心: http://game.xiaomi.com/index.php

华为应用市场: http://appstore.huawei.com/

有图有真相:

运营商网络 特征码 备注
中国移动 46000、46002、46007、46020 return 0 getMobileType
中国联通 46001、46006、46010 return 2 getOperatorType
中国电信 46003、46005、46011 return 1 getSimType

1. 去签名验证:

android killer不修改直接回编译后,是有签名验证的,检测提示盗版破解游戏.

签名验证盗版提示

当然是先跑一遍原程序,看看logcat有没有敏感信息可以用;现在搜索字符串了,

signatures

getAPPSecretString

有侵权

BLACK_NAME

找到第一条添加黑名单的工具类就是,向上回溯查看哪里引用了getAPPSecretString这个方法

.class public Lcn/mycompany/addblackname/utils/utils;

.super Ljava/lang/Object;

.source “utils.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.method public static getAPPSecretString(Landroid/content/Context;)Ljava/lang/String;
.prologue
.line 21
invoke-virtual {p0}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
move-result-object v4
.line 22
.local v4, "pkgname":Ljava/lang/String;
const-string v1, ""
return-object v1 #去签名验证从:try_start_0开始到:catch_0,但里面的返回留着.直接返回空的字符串
.end method

去验证的修改方法很多种,还可以在下面的类里定位到check方法函数.

根据经验可以去看看onCreate有没可用的信息,一般初始化在这里有处理.

.class public Lcom/DBGame/DiabloLOL/DiabloLOL;

.super Lorg/cocos2dx/lib/Cocos2dxActivity;

.source “DiabloLOL.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.method protected onCreate(Landroid/os/Bundle;)V
#前面还有若干代码
###黑名单功能开始
.line 240
new-instance v0, Lcn/mycompany/addblackname/AddBlackName;
invoke-direct {v0, p0}, Lcn/mycompany/addblackname/AddBlackName;-><init>(Landroid/content/Context;)V
.line 241
.local v0, "blackName":Lcn/mycompany/addblackname/AddBlackName;
#invoke-static {}, Lcn/mycompany/addblackname/AddBlackName;->Check()V
###黑名单功能结束
#后面还有若干代码

顺便广告的也可以看看能不能处理了

1
2
3
4
5
6
7
8
9
#前面还有若干代码
###广告的初始化开始
.line 260
#invoke-static {p0, v7}, Lcn/cmgame/billing/api/game/main/Tool;->adIntervalInit(Landroid/app/Activity;Lcn/cmgame/billing/api/game/main/Listener;)V
.line 262
#invoke-static {p0, v7}, Lcn/cmgame/billing/api/game/main/Tool;->adNativeInit(Landroid/app/Activity;Lcn/cmgame/billing/api/game/main/Listener;)V
###广告的初始化结束
#后面还有若干代码

看到Lcn/mycompany/addblackname/AddBlackName;->Check()V是在添加黑名单的类里,
查看方法,处理check()V

1
2
3
4
5
6
7
8
9
10
11
12
13
.method public static Check()V
.locals 6
.prologue
######插入代码开始 coded by B.S.
const-string v0, "Lcn/mycompany/addblackname/AddBlackName;->check()V \n -- by B.S."
invoke-static {v0}, Lcom/android/BS/Log;->LogStr(Ljava/lang/String;)V
######插入代码结束 coded by B.S.
return-void #直接返回使签名验证失效.
.end method

2. 去广告:

去除返回退出的横幅广告:

点返回按钮,logcat找到敏感字符

—– showInterAD –exit

反编译后,搜索

—– showInterAD

HANDLER_SHOW_INTER_AD

在下面类修改

.class public Lcom/DBGame/Common/BLHelper;

.super Ljava/lang/Object;

.source “BLHelper.java”

不让他发送显示广告的消息

public static final int HANDLER_SHOW_INTER_AD = 211;

.field public static final HANDLER_SHOW_INTER_AD:I = 0xd3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
.method public static showInterAD(Ljava/lang/String;)V
.locals 6
.param p0, "tag" # Ljava/lang/String;
.prologue
.line 360
const-string v3, "ad"
new-instance v4, Ljava/lang/StringBuilder;
invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V
const-string v5, "----- showInterAD --"
invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v4
invoke-virtual {v4, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v4
invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v4
invoke-static {v3, v4}, Landroid/util/Log;->w(Ljava/lang/String;Ljava/lang/String;)I
.line 361
const/4 v1, 0x0
.line 362
.local v1, "index":I
const/4 v0, 0x0
.local v0, "i":I
:goto_0
sget-object v3, Lcom/DBGame/Common/BLHelper;->adTags:[Ljava/lang/String;
array-length v3, v3
if-ge v0, v3, :cond_0
.line 363
sget-object v3, Lcom/DBGame/Common/BLHelper;->adTags:[Ljava/lang/String;
aget-object v3, v3, v0
invoke-virtual {v3, p0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v3
if-eqz v3, :cond_1
.line 364
move v1, v0
.line 368
:cond_0
new-instance v2, Landroid/os/Message;
invoke-direct {v2}, Landroid/os/Message;-><init>()V
.line 369
.local v2, "msg":Landroid/os/Message;
const/16 v3, 0xd3
iput v3, v2, Landroid/os/Message;->what:I
.line 370
iput v1, v2, Landroid/os/Message;->arg1:I
.line 371
sget-object v3, Lcom/DBGame/Common/BLHelper;->sContext:Lcom/DBGame/DiabloLOL/DiabloLOL;
#去退出广告,不让他发送显示广告的消息,下面一句给注释或删掉
#invoke-virtual {v3, v2}, Lcom/DBGame/DiabloLOL/DiabloLOL;->sendMessage(Landroid/os/Message;)V
.line 372
return-void
.line 362
.end local v2 # "msg":Landroid/os/Message;
:cond_1
add-int/lit8 v0, v0, 0x1
goto :goto_0
.end method
去除选英雄和副本的横幅广告:
1
2
3
4
5
6
7
8
public static final int HANDLER_SHOWBANNER = 200;
public static final int HANDLER_HIDEBANNER = 210;
case DiabloLOL.HANDLER_HIDEBANNER /*210*/:
DiabloLOL.this.hideBanner();
case 200:
DiabloLOL.this.showBanner();

修改下面类里的方法

.class public Lcom/DBGame/Common/BLHelper;

.super Ljava/lang/Object;

.source “BLHelper.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.method public static showBanner(Ljava/lang/String;)V
.locals 2
.param p0, "tag" # Ljava/lang/String;
.prologue
.line 375
new-instance v0, Landroid/os/Message;
invoke-direct {v0}, Landroid/os/Message;-><init>()V
.line 376
.local v0, "msg":Landroid/os/Message;
const/16 v1, 0xd2 #const/16 v1, 0xc8 #显示横幅广告的发送消息的代码 0xc8=200 修改为 0xd2=210 隐藏横幅
iput v1, v0, Landroid/os/Message;->what:I
.line 377
sget-object v1, Lcom/DBGame/Common/BLHelper;->sContext:Lcom/DBGame/DiabloLOL/DiabloLOL;
#去横幅广告,或者不让他发送显示广告的消息,
invoke-virtual {v1, v0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->sendMessage(Landroid/os/Message;)V
.line 378
return-void
.end method

可以再去下面类里看看,消息处理的地方
.method public handleMessage(Landroid/os/Message;)V

.class Lcom/DBGame/DiabloLOL/DiabloLOL$3;

.super Landroid/os/Handler;

.source “DiabloLOL.java”

1
2
3
4
5
6
7
8
9
10
case 200:
//DiabloLOL.access$400(this.this$0);
return;
case 210:
//DiabloLOL.access$500(this.this$0);
return;
case 211:
Log.e("qq", "HANDLER_SHOW_INTER_AD==========");
//DiabloLOL.access$600(this.this$0, paramMessage.arg1);
return;

对应的smali

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.line 650
#去除显示横幅sswitch_8
:sswitch_8
iget-object v2, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$3;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL;
# invokes: Lcom/DBGame/DiabloLOL/DiabloLOL;->showBanner()V
#invoke-static {v2}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$400(Lcom/DBGame/DiabloLOL/DiabloLOL;)V
goto :goto_0
.line 654
#去除隐藏横幅sswitch_9
:sswitch_9
iget-object v2, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$3;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL;
# invokes: Lcom/DBGame/DiabloLOL/DiabloLOL;->hideBanner()V
#invoke-static {v2}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$500(Lcom/DBGame/DiabloLOL/DiabloLOL;)V
goto :goto_0
.line 658
#去除显示嵌入式广告sswitch_a
:sswitch_a
const-string v2, "qq"
const-string v3, "HANDLER_SHOW_INTER_AD=========="
invoke-static {v2, v3}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 659
iget-object v2, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$3;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL;
iget v3, p1, Landroid/os/Message;->arg1:I
# invokes: Lcom/DBGame/DiabloLOL/DiabloLOL;->showInterAd(I)V
#invoke-static {v2, v3}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$600(Lcom/DBGame/DiabloLOL/DiabloLOL;I)V
goto/16 :goto_0

消息处理的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public void handleMessage(Message msg) {
switch (msg.what) {
case 10:
DiabloLOL.this.exitGame();
return;
case 11:
((ClipboardManager) Cocos2dxActivity.getContext().getSystemService("clipboard")).setPrimaryClip(ClipData.newPlainText(MiniDefine.ax, BLHelper.copyString));
Toast.makeText(DiabloLOL.this, "拷贝成功!", 0).show();
return;
case 30:
if (BLHelper.IPAYTAYPE == 1) {
DiabloLOL.this.payInDuanXin();
return;
} else if (BLHelper.IPAYTAYPE != 2 && DiabloLOL.RECHARGE_CHANNELS.indexOf(String.valueOf(DiabloLOL.this.iFromPay)) != -1) {
DiabloLOL.this.payInDuanXin();
return;
} else {
return;
}
case 102:
OGPub.Instance().closeLoad();
return;
case 200:
DiabloLOL.this.showBanner();
return;
case DiabloLOL.HANDLER_HIDEBANNER /*210*/:
DiabloLOL.this.hideBanner();
return;
case DiabloLOL.HANDLER_SHOW_INTER_AD /*211*/:
Log.e("qq", "HANDLER_SHOW_INTER_AD==========");
DiabloLOL.this.showInterAd(msg.arg1);
return;
case DiabloLOL.HANDLER_REYUN_EXIT /*400*/:
ReYun.exitSdk();
return;
case DiabloLOL.HANDLER_SHOWSHARE /*420*/:
DiabloLOL.this.showShareDialog();
return;
case DiabloLOL.HANDLER_SAVEPIC /*450*/:
BLHelper.savePic();
return;
case DiabloLOL.HANDLER_MONTHCONTRA /*470*/:
DiabloLOL.this.purchaseMonthlyContract(msg.arg1);
return;
case DiabloLOL.HANDLER_HIDEWEBDATA /*998*/:
BLHelper.webout();
return;
default:
return;
}
}

顺便也解决下其他的函数,
.method private showBanner()V和.method private showInterAd(I)V
处理掉直接返回

.class public Lcom/DBGame/DiabloLOL/DiabloLOL;

.super Lorg/cocos2dx/lib/Cocos2dxActivity;

.source “DiabloLOL.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
.method private showBanner()V
.locals 5
.prologue
.line 338
return-void #直接返回
const v1, 0x3e4ccccd # 0.2f
const v2, 0x3f4ccccd # 0.8f
const v3, 0x3f19999a # 0.6f
const v4, 0x3e19999a # 0.15f
:try_start_0
invoke-static {p0, v1, v2, v3, v4}, Lcn/cmgame/billing/api/game/main/Tool;->adNativeShow(Landroid/app/Activity;FFFF)V
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
.line 342
:goto_0
return-void
.line 339
:catch_0
move-exception v0
.line 340
.local v0, "e":Ljava/lang/Exception;
invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V
goto :goto_0
.end method
.method private showInterAd(I)V
.locals 1
.param p1, "index" # I
.prologue
.line 354
return-void #直接返回
:try_start_0
invoke-static {p0, p1}, Lcn/cmgame/billing/api/game/main/Tool;->adIntervalShow(Landroid/app/Activity;I)V
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
.line 358
:goto_0
return-void
.line 355
:catch_0
move-exception v0
.line 356
.local v0, "e":Ljava/lang/Exception;
invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V
goto :goto_0
.end method
去除今日推荐5秒闪屏广告:

.class public Lcn/cmgame/billing/api/game/main/Tool;

.super Ljava/lang/Object;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.method public static adSplashShow(Landroid/app/Activity;Ljava/lang/Class;Ljava/lang/Class;Landroid/os/Handler;)Z
.locals 7
const/4 v0, 0x1
const/4 v1, 0x0
const-string v2, "---adSplashShow----"
invoke-static {v2}, Lcn/cmgame/billing/api/game/e/d;->b(Ljava/lang/String;)V
sput-object p0, Lcn/cmgame/billing/api/game/main/Tool;->splashActivity:Landroid/app/Activity;
:try_start_0
###### 自带日志输出 appSign
const-string v3, "---B.S.---Tool.adSplashShow"
#move-object/from16 v2, v2 #v0是要打印输出的内容
invoke-static {v3, v2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
move v0, v1 #这里要,返回为0去今日推荐5秒闪屏广告,返回为1会一直黑屏
goto :goto_0
######

3. 内购破解:

去除可能会产生费用的危险权限:

AndroidManifest.xml里搜索

android.permission.SEND_SMS

android.permission.CALL_PHONE

删掉

1
2
3
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
补充一个强大的函数
不需要支付购买?!!!竟然有这函数(分析v1.15.1腾讯渠道第三方支付版发现的)

invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->buyWithoutPay()V

在第三方支付里可以直接调用上面的函数,直接购买成功

.method public payThird(Ljava/lang/String;)V

1
2
3
4
5
6
7
8
public void paySuccess(Map<String, String> paramAnonymousMap)
{
DiabloLOL.this.setPayment();
BLHelper.purchaseComplete(DiabloLOL.this.PRO_ID_Str[DiabloLOL.this.mPayIndex], 1);
BLHelper.closeShieldLayer();
Log.e("B.S.", "模拟Egame支付成功 --by B.S.");
DiabloLOL.access$202(DiabloLOL.this, -1);
}

将原来的buyWithoutPay模拟上面的paySuccess成功代码处理一下,要不然只能第一次购买成功.

1
2
3
4
5
6
private void buyWithoutPay()
{
setPayment();
BLHelper.purchaseComplete(this.PRO_ID_Str[this.mPayIndex], 1);
BLHelper.closeShieldLayer();
}

经过修正过的不支付购买函数

1
2
3
4
5
6
7
8
private void buyWithoutPay() {
com.android.BS.Log.LogStr("无限内购B.S.破解版\n www.appleos.xyz \n 爱淫荡 多合一 \n www.allin1.xyz \n buyWithoutPay -- by B.S.");
setPayment();
BLHelper.purchaseComplete(this.PRO_ID_Str[this.mPayIndex], 1);
BLHelper.closeShieldLayer();
Log.e("---B.S.---", "模拟EGame支付成功 --by B.S.");
this.mPayIndex = -1;
}

修正后的buyWithoutPay对应的smali

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.method private buyWithoutPay()V
.locals 2
.prologue
.line 730
######插入代码开始 coded by B.S.
const-string v0, "\u65e0\u9650\u5185\u8d2dB.S.\u7834\u89e3\u7248\n www.appleos.xyz \n \u7231\u6DEB\u8361 \u591A\u5408\u4E00 \n www.allin1.xyz \n buyWithoutPay -- by B.S."
invoke-static {v0}, Lcom/android/BS/Log;->LogStr(Ljava/lang/String;)V
######插入代码结束 coded by B.S.
invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->setPayment()V
.line 731
iget-object v0, p0, Lcom/DBGame/DiabloLOL/DiabloLOL;->PRO_ID_Str:[Ljava/lang/String;
iget v1, p0, Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
aget-object v0, v0, v1
const/4 v1, 0x1
invoke-static {v0, v1}, Lcom/DBGame/Common/BLHelper;->purchaseComplete(Ljava/lang/String;I)V
.line 732
invoke-static {}, Lcom/DBGame/Common/BLHelper;->closeShieldLayer()V
###
const-string v0, "---B.S.---"
const-string v1, "\u6a21\u62dfEGame\u652f\u4ed8\u6210\u529f --by B.S."
invoke-static {v0, v1}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
const/4 v1, -0x1
# setter for: Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
#invoke-static {p0, v1}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$202(Lcom/DBGame/DiabloLOL/DiabloLOL;I)I
######下面是上一句代码里面的简写形式 setter for: Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
iput v1, p0, Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
###
.line 733
return-void
.end method
电信支付接口:

logcat字符串定位,

Egame支付成功

Egame支付Cancel

order id:

搜索上面字符串,向上分析,回溯分析.

.class public Lcn/egame/terminal/paysdk/EgamePay;

.super Ljava/lang/Object;

.source “EgamePay.java”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.method public static pay(Landroid/app/Activity;Ljava/util/Map;Lcn/egame/terminal/paysdk/EgamePayListener;)V
.locals 1
.param p0, "activity" # Landroid/app/Activity;
.param p2, "listener" # Lcn/egame/terminal/paysdk/EgamePayListener;
.annotation system Ldalvik/annotation/Signature;
value = {
"(",
"Landroid/app/Activity;",
"Ljava/util/Map",
"<",
"Ljava/lang/String;",
"Ljava/lang/String;",
">;",
"Lcn/egame/terminal/paysdk/EgamePayListener;",
")V"
}
.end annotation
.prologue
.line 78
#注意paySuccess这个函数只有一个参数.method public abstract paySuccess(Ljava/util/Map;)V
#而失败payFailed这个函数有第二个整型参数 .method public abstract payFailed(Ljava/util/Map;I)V
# Egame支付成功
invoke-interface {p2, p1}, Lcn/egame/terminal/paysdk/EgamePayListener;->paySuccess(Ljava/util/Map;)V
return-void
.end method

还可以用paySuccess函数体代替payCancel和payFailed.在下面的类里,

.class Lcom/DBGame/DiabloLOL/DiabloLOL$6;

.super Ljava/lang/Object;

.source “DiabloLOL.java”

联通支付接口:

logcat字符串定位啊,

Unicom支付成功

Unicom支付cancel

在下面类修改处理,可以用goto大法或者switch大法.

.class Lcom/DBGame/DiabloLOL/DiabloLOL$4;

.super Ljava/lang/Object;

.source “DiabloLOL.java”

1
2
3
4
5
6
.method public PayResult(Ljava/lang/String;IILjava/lang/String;)V
.prologue
.line 694
goto :pswitch_0 #联通支付接口,直接JMP无条件跳到支付成功
packed-switch p2, :pswitch_data_0
移动支付接口:

logcat定位字符串,

购买道具:[

] 成功!

] 失败!

在下面类修改

.class Lcom/DBGame/DiabloLOL/DiabloLOL$5;

.super Ljava/lang/Object;

.source “DiabloLOL.java”

1
2
3
4
5
6
7
8
9
10
11
.method public onResult(ILjava/lang/String;Ljava/lang/Object;)V
.prologue
.line 735
const-string v0, ""
.line 736
.local v0, "result":Ljava/lang/String;
goto :pswitch_0 #移动支付接口,直接JMP无条件跳到支付成功
packed-switch p1, :pswitch_data_0

4. 统一支付接口:

统一为电信的吧.可以直接成功,没那么多弹窗支付

定位字符串

电信初始化成功

1
2
3
4
5
6
7
8
.method protected onCreate(Landroid/os/Bundle;)V
.line 254
invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->getSimType()I
move-result v4
iput v4, p0, Lcom/DBGame/DiabloLOL/DiabloLOL;->iFromPay:I

进入getSimType方法函数处理结果然后赋值给iFromPay

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private int getSimType() {
int type = 0;
String sOperator = ((TelephonyManager) getSystemService("phone")).getSimOperator().trim();
if (sOperator == null || sOperator.equals("")) {
return 0;
}
switch (Integer.valueOf(sOperator).intValue()) {
case 46000:
case 46002:
case 46007:
case 46020:
type = 0;
break;
case 46001:
case 46006:
type = 2;
break;
case 46003:
case 46005:
case 46011:
type = 1;
break;
}
return type;
}

直接return 1;伪装为电信,支付接口统一完毕.请参看本文开头的SIM类型表格

我第一次比较麻烦的改法如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
.method private getSimType()I
.locals 6
.prologue
.line 267
const/4 v3, 0x1 #const/4 v3, 0x0 #初始化为0是移动
.line 268
.local v3, "type":I
const-string v5, "phone"
.line 269
invoke-virtual {p0, v5}, Lcom/DBGame/DiabloLOL/DiabloLOL;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;
move-result-object v2
check-cast v2, Landroid/telephony/TelephonyManager;
.line 270
.local v2, "tm":Landroid/telephony/TelephonyManager;
invoke-virtual {v2}, Landroid/telephony/TelephonyManager;->getSimOperator()Ljava/lang/String;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/String;->trim()Ljava/lang/String;
move-result-object v1
######插入自定义log开始
invoke-static {v1}, Lcom/android/BS/Log;->LogStr(Ljava/lang/String;)V
######插入自定义log结束
######插入自定义log开始
const-string v0, "\n\u65e0\u9650\u5185\u8d2dB.S.\u7834\u89e3\u7248\n www.appleos.xyz \n-- by B.S."
invoke-static {v0}, Lcom/android/BS/Log;->LogStr(Ljava/lang/String;)V
######插入自定义log结束
.line 271
.local v1, "sOperator":Ljava/lang/String;
if-eqz v1, :cond_0
const-string v5, ""
invoke-virtual {v1, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v5
if-eqz v5, :cond_1
:cond_0
move v4, v3 #移动为0
.line 295
.end local v3 # "type":I
.local v4, "type":I
:goto_0
return v4
.line 274
.end local v4 # "type":I
.restart local v3 # "type":I
:cond_1
invoke-static {v1}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/Integer;->intValue()I
move-result v0
.line 275
.local v0, "sCode":I
packed-switch v0, :pswitch_data_0
:goto_1
:pswitch_0
move v4, v3
.line 295
.end local v3 # "type":I
.restart local v4 # "type":I
goto :goto_0
.line 280
.end local v4 # "type":I
.restart local v3 # "type":I
:pswitch_1
const/4 v3, 0x1 #const/4 v3, 0x0 #移动
.line 281
goto :goto_1
.line 284
:pswitch_2
const/4 v3, 0x1 #const/4 v3, 0x2 #联通
.line 285
goto :goto_1
.line 289
:pswitch_3
const/4 v3, 0x1 #电信
.line 290
goto :goto_1
.line 275
:pswitch_data_0
.packed-switch 0xb3b0
:pswitch_1
:pswitch_2
:pswitch_1
:pswitch_3
:pswitch_0
:pswitch_3
:pswitch_2
:pswitch_1
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_3
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_0
:pswitch_1
.end packed-switch
.end method

也可以直接return 0,伪装为移动,统一为移动支付.

1
2
3
4
5
6
7
8
.method private getSimType()I
.locals 6
###统一为移动短信支付接口直接返回为0
const/4 v4, 0x0
return v4
.end method

然后处理移动短信支付的函数方法payInYidong(),移动短信支付的另外一种破解方法,

.class Lcom/DBGame/DiabloLOL/DiabloLOL$5;

.super Ljava/lang/Object;

.source “DiabloLOL.java”

把移动购买成功的代码,就是:pswitch_0里两个goto :goto_0之间的有效代码,直接搬到payInYidong()里,放到:cond_0和return-void之间.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
.line 755
:goto_0
invoke-static {}, Lcom/DBGame/Common/BLHelper;->closeShieldLayer()V
.line 756
return-void
.line 738
:pswitch_0
const-string v1, "10"
invoke-virtual {p3}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v1
if-eqz v1, :cond_0
.line 739
const-string v0, "\u77ed\u4fe1\u8ba1\u8d39\u8d85\u65f6"
goto :goto_0
.line 741
:cond_0 ###从下面一句开始购买成功,不弹窗.
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "\u8d2d\u4e70\u9053\u5177\uff1a["
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
iget-object v2, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$5;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL; #和下一语句合并
iget-object v2, v2, Lcom/DBGame/DiabloLOL/DiabloLOL;->PAY_NAME:[Ljava/lang/String;
iget-object v3, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$5;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL; #和下一语句合并
# getter for: Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
invoke-static {v3}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$800(Lcom/DBGame/DiabloLOL/DiabloLOL;)I
move-result v3
aget-object v2, v2, v3
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
const-string v2, "] \u6210\u529f\uff01"
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 v0
.line 742
iget-object v1, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$5;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL; #和下一语句合并
iget-object v1, v1, Lcom/DBGame/DiabloLOL/DiabloLOL;->PRO_ID_Str:[Ljava/lang/String;
iget-object v2, p0, Lcom/DBGame/DiabloLOL/DiabloLOL$5;->this$0:Lcom/DBGame/DiabloLOL/DiabloLOL; #和下一语句合并
# getter for: Lcom/DBGame/DiabloLOL/DiabloLOL;->mPayIndex:I
invoke-static {v2}, Lcom/DBGame/DiabloLOL/DiabloLOL;->access$800(Lcom/DBGame/DiabloLOL/DiabloLOL;)I
move-result v2
aget-object v1, v1, v2
const/4 v2, 0x1
invoke-static {v1, v2}, Lcom/DBGame/Common/BLHelper;->purchaseComplete(Ljava/lang/String;I)V
goto :goto_0 ###购买成功不弹窗到goto那边的closeShieldLayer语句然后返回结束
.line 748
:pswitch_1

最后应该变为java源码如下面的样子:

1
2
3
4
5
6
7
8
private void payInYidong() {
if (LOLConstant.sCMCC_OPEN == 0) {
BLHelper.showShieldLayer("正在处理,请稍后.....");
}
String str = "购买道具:[" + this.PAY_NAME[this.mPayIndex] + "] 成功!";
BLHelper.purchaseComplete(this.PRO_ID_Str[this.mPayIndex], 1);
BLHelper.closeShieldLayer();
}

有童靴反应真机内购,会卡在”正在处理,请稍后…..”,其实这个要等一会的,等一会儿就消失了.
不愿意等太长时间,那么就干脆干掉她,如下,只要上面说的两个goto :goto_0夹着那段代码,另外记得这里面的代码,需要合并处理this指针问题哟.

1
2
3
4
private void payInYidong() {
String str = "购买道具:[" + this.PAY_NAME[this.mPayIndex] + "] 成功!";
BLHelper.purchaseComplete(this.PRO_ID_Str[this.mPayIndex], 1);
}
补充一个统一伪装为联通,游戏联盟支付后,直接领取游戏联盟包月,铂金会员礼包

找字符串

purchaseMonthlyContract>>>command is {“command”:”month_order_25”

purchaseMonthlyContract>>>respond is {“md5”:””,”msg”:”用户取消”,”result”:3,”firstOrder”:””}

purchaseMonthlyContract>>>respond is

purchaseMonthlyContract>>>command is

修改purchaseMonthlyContract函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
.method public purchaseMonthlyContract(I)V
.locals 5
.param p1, "command" # I
.prologue
.line 996
new-instance v1, Lorg/json/JSONObject;
invoke-direct {v1}, Lorg/json/JSONObject;-><init>()V
.line 998
.local v1, "object":Lorg/json/JSONObject;
:try_start_0
const-string v2, "command"
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "month_order_"
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3, p1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
invoke-virtual {v1, v2, v3}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
:try_end_0
.catch Lorg/json/JSONException; {:try_start_0 .. :try_end_0} :catch_0
.line 1002
:goto_0
sget-object v2, Lcom/DBGame/DiabloLOL/DiabloLOL;->LOG_TAG:Ljava/lang/String;
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "purchaseMonthlyContract>>>command is "
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
.line 1003
invoke-virtual {v1}, Lorg/json/JSONObject;->toString()Ljava/lang/String;
move-result-object v4
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v3
.line 1002
invoke-static {v2, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 1004
#invoke-static {}, Lcom/unicom/dcLoader/Utils;->getInstances()Lcom/unicom/dcLoader/Utils;
#move-result-object v2
#invoke-virtual {v1}, Lorg/json/JSONObject;->toString()Ljava/lang/String;
#move-result-object v3
#new-instance v4, Lcom/DBGame/DiabloLOL/DiabloLOL$10;
#invoke-direct {v4, p0}, Lcom/DBGame/DiabloLOL/DiabloLOL$10;-><init>(Lcom/DBGame/DiabloLOL/DiabloLOL;)V
#invoke-virtual {v2, p0, v3, v4}, Lcom/unicom/dcLoader/Utils;->customCommand(Landroid/content/Context;Ljava/lang/String;Lcom/unicom/dcLoader/Utils$UnipayCommandResultListener;)V
######
.line 1019
const/4 v4, 0x1 #游戏联盟铂金已经包月0x1
invoke-static {v4}, Lcom/DBGame/Common/BLHelper;->onMonthlyContractPurchased(Z)V
######
.line 1032
return-void
.line 999
:catch_0
move-exception v0
.line 1000
.local v0, "e":Lorg/json/JSONException;
invoke-virtual {v0}, Lorg/json/JSONException;->printStackTrace()V
goto :goto_0
.end method
几种支付方式如下:(短信,联通,移动,Egame支付)

其中电信用的是Egame支付

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
private void payInDuanXin() {
if (RECHARGE_CHANNELS.indexOf(String.valueOf(this.iFromPay)) != -1) {
if (this.iFromPay == 2) {
payInUnicom();
} else if (this.iFromPay == 0) {
payInYidong();
} else if (this.iFromPay == 1) {
payInEgame();
}
}
}
private void payInUnicom() {
Utils.getInstances().pay(this, this.PAY_CODE_UNICOM[this.mPayIndex], new UnipayPayResultListener() {
public void PayResult(String arg0, int arg1, int arg2, String arg3) {
switch (arg1) {
case 1:
DiabloLOL.this.setPayment();
BLHelper.purchaseComplete(DiabloLOL.this.PRO_ID_Str[DiabloLOL.this.mPayIndex], 1);
BLHelper.closeShieldLayer();
Log.e("qq", "Unicom支付成功");
return;
case 2:
BLHelper.closeShieldLayer();
Log.e("qq", "Unicom支付Fail");
return;
case 3:
BLHelper.closeShieldLayer();
Log.e("qq", "Unicom支付cancel");
return;
default:
Log.e("qq", "Unicom支付Default");
return;
}
}
});
}
private void payInYidong() {
if (LOLConstant.sCMCC_OPEN == 0) {
BLHelper.showShieldLayer("正在处理,请稍后.....");
}
GameInterface.doBilling(this, true, true, this.PAY_CODE_MM[this.mPayIndex], null, this.payCallback);
}
public void payInEgame() {
HashMap<String, String> payParams = new HashMap();
payParams.put(EgamePay.PAY_PARAMS_KEY_TOOLS_ALIAS, this.PAY_CODE_SMS[this.mPayIndex]);
if (this.iOpen == -1) {
this.iOpen = BLHelper.getOpenCTCC("ctcc", this, true);
}
Log.e("qq", "iOpen=" + this.iOpen);
if (this.iOpen == 1) {
this.gameManager.gameConfig.PaySdkUIForCP = 1;
} else {
this.gameManager.gameConfig.PaySdkUIForCP = 0;
}
this.gameManager.EGamePay(payParams, new EgamePayListener() {
public void paySuccess(Map<String, String> map) {
DiabloLOL.this.setPayment();
BLHelper.purchaseComplete(DiabloLOL.this.PRO_ID_Str[DiabloLOL.this.mPayIndex], 1);
BLHelper.closeShieldLayer();
Log.e("qq", "Egame支付成功");
DiabloLOL.this.mPayIndex = -1;
}
public void payFailed(Map<String, String> map, int arg1) {
BLHelper.closeShieldLayer();
Log.e("qq", "Egame支付Fail==" + arg1);
DiabloLOL.this.mPayIndex = -1;
}
public void payCancel(Map<String, String> map) {
BLHelper.closeShieldLayer();
Log.e("qq", "Egame支付Cancel");
DiabloLOL.this.mPayIndex = -1;
}
});
}
另一种新的统一支付的方法:

短信支付统一调用 buyWithoutPay

例如,修改移动支付

1
2
3
4
5
.line 719
#invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->payInYidong()V
invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->buyWithoutPay()V
goto :goto_0

修改短信支付函数 payInDuanXin

1
2
3
4
5
6
7
8
9
10
11
12
private void payInDuanXin() {
if (RECHARGE_CHANNELS.indexOf(String.valueOf(this.iFromPay)) != -1) {
showFiles();
if (this.iFromPay == 2) {
payInUnicom();
} else if (this.iFromPay == 0) {
payInYidong();
} else if (this.iFromPay == 1) {
payInEgame();
}
}
}

修改后的 payInDuanXin 函数变为

1
2
3
4
5
6
7
8
9
10
11
12
private void payInDuanXin() {
if (RECHARGE_CHANNELS.indexOf(String.valueOf(this.iFromPay)) != -1) {
showFiles();
if (this.iFromPay == 2) {
buyWithoutPay();
} else if (this.iFromPay == 0) {
buyWithoutPay();
} else if (this.iFromPay == 1) {
buyWithoutPay();
}
}
}

统一为短信支付或者调用强大buyWithoutPay的函数

1
2
3
invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->payInDuanXin()V
### 不需要支付购买,竟然有这函数
invoke-direct {p0}, Lcom/DBGame/DiabloLOL/DiabloLOL;->buyWithoutPay()V

anzhi平台的 payInAnzhi 函数替换为 payInDuanXin 或者 buyWithoutPay

修改 handleMessage 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.class Lcom/DBGame/DiabloLOL/DiabloLOL$4;
.super Landroid/os/Handler;
.source "DiabloLOL.java"
# virtual methods
.method public handleMessage(Landroid/os/Message;)V
.line 623
:cond_0
sget v2, Lcom/DBGame/Common/BLHelper;->IPAYTAYPE:I
const/4 v3, 0x2
#if-ne v2, v3, :cond_1
### 无论支付类型 BLHelper.IPAYTAYPE 是否等于2都跳到短信支付
goto :cond_1

handleMessage 原函数为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public void handleMessage(Message msg) {
switch (msg.what) {
case 10:
DiabloLOL.this.exitGame();
return;
case 11:
((ClipboardManager) Cocos2dxActivity.getContext().getSystemService("clipboard")).setPrimaryClip(ClipData.newPlainText("text", BLHelper.copyString));
Toast.makeText(DiabloLOL.this, "拷贝成功!", 0).show();
return;
case 30:
Log.e("qq", "BLHelper.IPAYTAYPE==" + BLHelper.IPAYTAYPE);
if (BLHelper.IPAYTAYPE == 1) {
DiabloLOL.this.payInDuanXin();
return;
} else if (BLHelper.IPAYTAYPE == 2) {
DiabloLOL.this.payInAnzhi(DiabloLOL.this.mPayIndex);
return;
} else {
DiabloLOL.this.payInDuanXin();
return;
}
case 102:
OGPub.Instance().closeLoad();
return;
case 200:
DiabloLOL.this.showBanner();
return;
case DiabloLOL.HANDLER_HIDEBANNER /*210*/:
DiabloLOL.this.hideBanner();
return;
case DiabloLOL.HANDLER_SHOW_INTER_AD /*211*/:
DiabloLOL.this.showInterAd(msg.arg1);
return;
case DiabloLOL.HANDLER_SHOWLARGEBANNER /*212*/:
DiabloLOL.this.iSendMessage = msg.arg1;
Log.e("qq", "==iSendMessage" + DiabloLOL.this.iSendMessage);
DiabloLOL.this.showLargeBanner();
return;
case DiabloLOL.HANDLER_SHOWNYTOPBANNER /*213*/:
DiabloLOL.this.showTopBanner();
return;
case DiabloLOL.HANDLER_REYUN_EXIT /*400*/:
ReYun.exitSdk();
return;
case DiabloLOL.HANDLER_SHOWSHARE /*420*/:
DiabloLOL.this.showShareDialog();
return;
case DiabloLOL.HANDLER_SAVEPIC /*450*/:
BLHelper.savePic();
return;
case DiabloLOL.HANDLER_MONTHCONTRA /*470*/:
DiabloLOL.this.purchaseMonthlyContract(msg.arg1);
return;
case DiabloLOL.HANDLER_HIDEWEBDATA /*998*/:
BLHelper.webout();
return;
default:
return;
}
}
您觉得好,您就随意打赏点吧(*^__^*)您的鼓励,是我坚持的动力!