内购伪造服务器证书,Xposed绕过元气骑士内购验证

申明:本文仅用于技术研究所用,请支持正版游戏!

一、APK反编译

解压并保存apk中的文件:classes.dex

使用dex2jar获取jar文件,到这里便可以使用jd-gui打开这个jar包并查看反编译的java代码。为了方便搜索,可以使用jd-gui的导出源代码功能导出所有反编译的文件。

<ignore_js_op>%0A%0A<img%20id=

1.png (170.05 KB, 下载次数: 2)

1

2020-2-14 23:04 上传

" alt="" />

二、内购功能点分析

走正常的购买流程购买任意物品,在付款前返回,得到如下的消息:

<ignore_js_op>%0A%0A<img%20id=

2.png (129.21 KB, 下载次数: 0)

2

2020-2-14 23:05 上传

" alt="" />

<ignore_js_op>%0A%0A<img%20id=

3.png (149.57 KB, 下载次数: 1)

3

2020-2-14 23:05 上传

" alt="" />

可以看到返回了两个消息:

订单取消user_calcelled.

null 校验订单失败:unpaid

以'订单取消'作为关键字搜索,定位到了以下点:

<ignore_js_op>%0A%0A<img%20id=

4.png (606.06 KB, 下载次数: 2)

4

2020-2-14 23:06 上传

" alt="" />

以'校验订单失败'作为关键字搜索,定位到以下两个点:

<ignore_js_op>%0A%0A<img%20id=

5.png (540.64 KB, 下载次数: 1)

5

2020-2-14 23:06 上传

" alt="" />

三、代码分析 + Xposed Hook

1、第一个点(订单取消)绕过

protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent) {

try {

if (paramInt1 == Pingpp.REQUEST_CODE_PAYMENT && paramIntent != null && paramIntent.getExtras() != null) {

String str3 = paramIntent.getExtras().getString("pay_result");

String str2 = paramIntent.getExtras().getString("error_msg");

String str1 = paramIntent.getExtras().getString("extra_msg");

if (this.payingOrderId != null && !"".equals(this.payingOrderId)) {

if ("success".equals(str3)) {

onPaySuccess(this.payingOrderId, "", "");

Toast.makeText((Context)this, "支付成功", 0).show();

} else {

StringBuilder stringBuilder;

if ("fail".equals(str3)) {

onPayFail(this.payingOrderId, "");

stringBuilder = new StringBuilder();

stringBuilder.append("支付失败:");

stringBuilder.append(str2);

stringBuilder.append(",");

stringBuilder.append(str1);

Toast.makeText((Context)this, stringBuilder.toString(), 1).show();

} else if ("cancel".equals(stringBuilder)) {

onPayCancel(this.payingOrderId, "");

stringBuilder = new StringBuilder();

stringBuilder.append("订单取消");

stringBuilder.append(str2);

stringBuilder.append(",");

stringBuilder.append(str1);

Toast.makeText((Context)this, stringBuilder.toString(), 0).show();

} else if ("invalid".equals(stringBuilder)) {

onPayFail(this.payingOrderId, "");

stringBuilder = new StringBuilder();

stringBuilder.append("支付失败:");

stringBuilder.append(str2);

stringBuilder.append(",");

stringBuilder.append(str1);

Toast.makeText((Context)this, stringBuilder.toString(), 1).show();

} else if ("unknown".equals(stringBuilder)) {

onPayUnknown(this.payingOrderId, "");

stringBuilder = new StringBuilder();

stringBuilder.append("未知错误:");

stringBuilder.append(str2);

stringBuilder.append(",");

stringBuilder.append(str1);

Toast.makeText((Context)this, stringBuilder.toString(), 1).show();

}

}

this.payingOrderId = null;

return;

}

}

} catch (Exception exception) {

Log.i("Unity", exception.toString());

}

}

可以看到只要让paramIntent.getExtras().getString("pay_result");的值为success便通过了此处验证。

Xposed Hook代码

<ignore_js_op>%0A%0A<img%20id=

6.png (148.88 KB, 下载次数: 1)

6

2020-2-14 23:07 上传

" alt="" />

2、第二个点(校验订单)绕过

com.chillyroomsdk.sdkbridge.order.https_task.OrderCheckTask

protected void onPostExecute(String paramString) {

String str = TAG;

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append("onPostExecute: ");

stringBuilder.append(paramString);

Log.i(str, stringBuilder.toString());

if (paramString != null && !paramString.equals("")) {

OrderInfo orderInfo = new OrderInfo();

orderInfo.orderId = this.m_orderId;

try {

String str1;

JSONObject jSONObject = new JSONObject(paramString);

if (jSONObject.getInt("retcode") == 0) {

jSONObject = jSONObject.getJSONObject("order");

if (jSONObject.getInt("can_send") == 1) {

orderInfo.productName = jSONObject.getString("item_name");

orderInfo.productId = jSONObject.getString("item_id");

float f = jSONObject.getInt("total_price") / 100.0F;

((IPayAgent)UnityPlayer.currentActivity).onPayCheckSuccess(this.m_orderId, orderInfo.productId, orderInfo.productName, f, "");

if (this.m_dialog != null) {

this.m_dialog.dismiss();

return;

}

} else {

if (this.m_count > 0) {

StartTaskOnMainThread(this.m_dialog, this.m_orderId, this.m_count, this.m_time_count);

} else {

Toast.makeText(this.m_context, "订单支付失败。若发生丢单请勿重复支付,并联系客服", 1).show();

if (this.m_dialog != null)

this.m_dialog.dismiss();

}

str1 = TAG;

stringBuilder = new StringBuilder();

stringBuilder.append("此订单支付失败:");

stringBuilder.append(orderInfo.orderId);

Log.i(str1, stringBuilder.toString());

return;

}

} else {

str1 = str1.getString("msg");

Context context = this.m_context;

StringBuilder stringBuilder1 = new StringBuilder();

stringBuilder1.append(orderInfo.productName);

stringBuilder1.append(" 校验订单失败:");

stringBuilder1.append(str1);

Toast.makeText(context, stringBuilder1.toString(), 1).show();

if (this.m_count > 0) {

StringBuilder stringBuilder2 = new StringBuilder();

stringBuilder2.append("count : ");

stringBuilder2.append(this.m_count);

Log.i("Unity", stringBuilder2.toString());

StartTaskOnMainThread(this.m_dialog, this.m_orderId, this.m_count, this.m_time_count);

return;

}

if (this.m_dialog != null) {

this.m_dialog.dismiss();

return;

}

}

} catch (JSONException jSONException) {

jSONException.printStackTrace();

return;

}

} else {

if (this.m_count > 0) {

StartTaskOnMainThread(this.m_dialog, this.m_orderId, this.m_count, this.m_time_count);

return;

}

Toast.makeText(this.m_context, "订单支付失败。若发生丢单请勿重复支付,并联系客服", 1).show();

if (this.m_dialog != null)

this.m_dialog.dismiss();

}

}

通过代码逻辑可以分析得出:参数paramString是一个JSON字符串,格式如下时便可以通过校验:

{"retcode":0,"order":{"can_send":1,"item_name":"商品名称","item_id":商品编号,"total_price":0},"msg":"购买成功"}

基中的商品名称和商品编号暂时未知。

Xposed Hook代码

<ignore_js_op>%0A%0A<img%20id=

7.png (171.25 KB, 下载次数: 1)

7

2020-2-14 23:07 上传

" alt="" />

3、第三个点(校验订单)绕过

com.chillyroomsdk.sdkbridge.order.https_task.OrderRestoreTask

这个点是用来恢复有问题订单的,原理同第二个点,不再重复说明。

Xposed Hook代码

<ignore_js_op>%0A%0A<img%20id=

8.png (167.96 KB, 下载次数: 1)

8

2020-2-14 23:07 上传

" alt="" />

4、商品信息获取

上面第二和第三个点都需要商品名称和商品编号这个关键信息,通过DDMS的跟踪分析,发现了这个点:

com.chillyroomsdk.sdkbridge.order.BaseOrderAgent.requestOrder

<ignore_js_op>%0A%0A<img%20id=

9.png (355.56 KB, 下载次数: 2)

9

2020-2-14 23:08 上传

" alt="" />

<ignore_js_op>%0A%0A<img%20id=

10.png (521.59 KB, 下载次数: 1)

10

2020-2-14 23:08 上传

" alt="" />

可以看到商品名称、编号、价格这里都有了。因此Hook这个点,设置变量内容便可以在购买成功前设置购买商品的信息。

Xposed Hook代码

<ignore_js_op>%0A%0A<img%20id=

11.png (155.86 KB, 下载次数: 2)

11

2020-2-14 23:08 上传

" alt="" />

四、实际效果演示

<ignore_js_op>%0A%0A<img%20id=

12.png (118.7 KB, 下载次数: 1)

12

2020-2-14 23:09 上传

" alt="" />

<ignore_js_op>%0A%0A<img%20id=

yq.gif (942.66 KB, 下载次数: 2)

yq

2020-2-14 23:09 上传

" alt="" />

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值