微信乘车卡是怎么判断手机是否 ROOT 的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
azh7138m
V2EX    微信

微信乘车卡是怎么判断手机是否 ROOT 的?

  •  
  •   azh7138m 2019-04-12 23:14:28 +08:00 6137 次点击
    这是一个创建于 2448 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以下为我观察到的行为,不保证正确。

    乘车卡小程序下载

    tldr

    接口 https://wlx.tenpay.com/cgi-bin/wx/hce/ccm_hce_account_info.cgi 返回的数据存在 retcode: "912320107",也就是 DEVICE_IS_ROOT: "912320107"

    代码节选

    节选自 pages/index/index.js

    { var e = require("../../utils/config.js"), t = require("../../utils/util.js"), o = require("../../common/request.js"), a = require("../../utils/lib.js"), n = requirePlugin("vfcPlugin").vfc, i = require("../../logic/login.js"), c = require("../../logic/uiHelper.js"), r = require("../../logic/uiShare.js"), s = require("../../logic/report"), d = require("../../common/token.js"), l = require("../../logic/location.js"), u = require("../../logic/elementData.js"), g = require("../../utils/thirdparty/aes.js").CryptoJS, _ = require("../../utils/thirdparty/rsa.js"), f = require("../../utils/thirdparty/md5.js"), p = getApp(), request = o.request, h = { RIGHT: "/img/right.png", FALSE: "/img/false.png" }, w = { BAL: "余额不足", FAIL: "该城市暂不支持使用乘车卡" }, y = { normal: "刷新", refresh: "已刷新" }, C = {}; Page({ requestCardInfo: function() { arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; var e = this; t.compare(C.SDKVersion, "2.6.2", !0) >= 0 ? wx.getWxSecData({ complete: function(t) { e.qryAccInfo({ sec_data_enc: t.encryptedData, sec_data_enc_iv: t.iv }); } }) : e.qryAccInfo({ sec_data_enc: "", sec_data_enc_iv: "", wx_version: C.version, sdk_version: C.SDKVersion }); }, qryAccInfo: function() { var request_raw_data = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, o = this, request_data = Object.assign( { ykt_id: o.data.ykt_id, city_code: o.data.city_code, card_id: i.getCardId() || "" }, request_raw_data ); request({ url: e.GET_CARD_INFO, showLoading: !0, data: request_data, success: function(resp) { var resp_data = resp.data; if ((console.log(resp), "0" === resp_data.retcode)) if ("0" === resp_data.open_state) { var n = { cloud_card_id: resp_data.cloud_card_id, vfc_card_id: resp_data.vfc_card_id, vfc_user_id: resp_data.vfc_user_id, vfc_user_name: resp_data.vfc_user_name, acc_no: resp_data.acc_no, card_id: resp_data.card_id }; wx.setStorageSync(e.USER_INFO_KEY, n); var i = resp_data.cloud_card_id || ""; o.setData({ loading: !1, acc_no: resp_data.acc_no, cloudCardId: i, formatCloudCardId: i.replace(/(\d{4})/g, "$1 ") }), p.setGlobalData({ acc_no: resp_data.acc_no }), wx.getStorageSync(e.HCETOKEN) ? wx.getStorageSync(e.CERT_NO) ? o.updateCardInfo() : o.reqCertNo() : o.requestToken(); } else wx.redirectTo({ url: "/pages/card/pre/pre?cardImg=" + o.data.cardImg }); else switch (resp_data.retcode) { case e.RETCODE.USER_NOT_EXIST: case e.RETCODE.USER_STOPPED: case e.RETCODE.NEW_USER_NOT_NEED_PHONE_AUTH: wx.redirectTo({ url: "/pages/card/pre/pre?retcode=" + resp_data.retcode + "&cardImg=" + o.data.cardImg }); break; case e.RETCODE.OPEN_NOT_IN_WHITELIST: case e.RETCODE.OPEN_NOT_ALLOWED: o.setData({ loading: !1, InWhiteList: !1 }); break; case e.RETCODE.DEVICE_IS_ROOT: wx.redirectTo({ url: "/pages/notSupport/notSupport?type=isRoot" }); break; default: c.commonModal({ confirmText: "重试", retcode: resp_data.retcode, success: function(e) { e.confirm && o.render(); } }); } }, fail: function(e) { wx.showModal({ title: "提示", content: "系统繁忙,请重试", confirmText: "重试", success: function(e) { e.confirm && o.render(); } }); } }); } }); } 

    节选自 common/request.js

    function request(user_query) { function isLoginUrl() { return real_query.url === n.LOGIN_CGI; } var real_query = Object.assign( { retry: !0, method: "POST", header: { "content-type": "application/x-www-form-urlencoded" }, isReport: !0 }, user_query ); real_query.data || (real_query.data = {}), (real_query.data.s_tk = token.getSysInfoToken()), (real_query.data.g_tk = token.getACSRFToken()), (real_query.data.version = n.APP_VERSION); var l = new Date().getTime().toString(); (real_query.data.timestamp = l.substr(0, 10)), real_query.showLoading && wx.showLoading({ title: "加载中..." }); var login_data = logic_login.getLoginData(); if (login_data && "POST" == real_query.method) for (var d in login_data) ("wlx_app_id" !== d && "wlx_open_id" !== d && "wlx_skey" !== d && "wlx_skey_type" !== d) || (real_query.data[d] = login_data[d]); real_query.success = function(resp) { console.log(resp); var a = resp.data || {}; 200 == resp.statusCode ? !1 === isLoginUrl() && real_query.retry && "object" == (void 0 === a ? "undefined" : t(a)) && logic_login.needAutoLogin(a.retcode) ? !0 !== request.retryMap[user_query.url] ? ((request.retryMap[user_query.url] = !0), o({ fromCache: !1, showLoading: user_query.showLoading, success: function(o) { request(user_query); } })) : wx.showModal({ title: "提示", content: "登录失效,请重新登录?", showCancel: !0, success: function(t) { t.confirm ? o({ fromCache: !1, success: function(o) { request(user_query); } }) : wx.navigateBack({ delta: 5 }); } }) : (!1 === isLoginUrl() && !0 === request.retryMap[user_query.url] && (request.retryMap[user_query.url] = !1), user_query.success(resp)) : user_query.fail && user_query.fail(); }; (real_query.complete = function(e) { real_query.showLoading && wx.hideLoading(), user_query.complete && user_query.complete(e); }), console.log(real_query), wx.request(real_query); } 

    节选自 logic/login.js

    function getLoginData() { try { var e = wx.getStorageSync(r.LOGIN_DATA_KEY); if ( "" !== e.wlx_app_id && "" !== e.wlx_open_id && "" !== e.wlx_skey && "" !== e.wlx_skey_type ) { var n = getApp(); return n && n.globalData && (n.globalData.wlx_open_id = e.wlx_open_id), e; } return null; } catch (e) { return null; } } 

    节选自 common/token.js

    { function e() { try { var e = wx.getSystemInfoSync(), t = { model: e.model, pixelRatio: e.pixelRatio, screenWidth: e.screenWidth, screenHeight: e.screenHeight }; return r(JSON.stringify(t)); } catch (e) { console.log("getSysInfoMd5Old"); } } function t() { var e = o.getOpenIdFromStorage(); return e ? r(e + n.SYSINFO_SALT) : (console.log("getSysInfoMd5"), ""); } var r = require("../utils/thirdparty/md5.js"), n = require("../utils/config.js"), o = require("../logic/login.js"); module.exports = { getSysInfoToken: function() { return e().substr(-4); }, getACSRFToken: function() { try { var e = wx.getStorageSync(n.LOGIN_DATA_KEY); if (e) { for (var t = 5381, r = e.wlx_skey, o = 0, i = r.length; o < i; ++o) t += (t << 5) + r.charAt(o).charCodeAt(); return 2147483647 & t; } } catch (e) { return ""; } return ""; }, getSysInfoMd5: t, getGuidMd5: function() { return t(); }, md5: r }; } 

    这判断很有趣,清空数据后第一次打开就能用,再次打开就不行了。

    最后

    腾讯能不能因为我 ROOT 了设备就不让我用呢?

    四 服务中止 /终止

    1、财付通有权基于业务调整或风险管控的需要,暂停、中断或终止向您提供本服务的全部或部分功能。

    ----- 乘车卡使用协议

    12 条回复    2019-10-08 14:32:59 +08:00
    lpd0155
        1
    lpd0155  
       2019-04-12 23:26:22 +08:00 via Android   1
    小白问一句,压缩包里的东西怎么打开?
    azh7138m
        2
    azh7138m  
    OP
       2019-04-12 23:30:13 +08:00
    @lpd0155 那我补充下...
    "_-"开头这个是主包,剩下俩是分包
    解包的方法比较多了,比如 http://bfy.tw/NCNX
    tony601818
        3
    tony601818  
       2019-04-13 04:00:33 +08:00 via Android
    安卓系统有 SafetyNet
    lpd0155
        4
    lpd0155  
       2019-04-13 07:53:47 +08:00 via Android
    @tony601818 没用的,实测过了 SAFETY NET 依然被检测到 ROOT
    kokutou
        5
    kokutou  
       2019-04-13 09:38:56 +08:00 via Android
    magisk+edxposed。。。
    乘车码我昨天试了下开通了,今天还是可以打开。。。
    azh7138m
        6
    azh7138m  
    OP
       2019-04-13 10:09:40 +08:00 via Android
    @kokutou 我清空数据后第一次也是可以用的,过一会就不行了,不知道微信是怎么判断的,这里只是说乘车卡是怎么判断用户是否 root,这个接口的数据是怎么来的就不清楚了。
    kokutou
        7
    kokutou  
       2019-04-13 11:51:17 +08:00 via Android
    @azh7138m
    用支付宝的不就行了。。。

    还没听说支付宝因为 root 不让用什么东西的吧。。。

    说白了就是腾讯懒得担责任,一刀切,技术不行
    azh7138m
        8
    azh7138m  
    OP
       2019-04-13 11:57:51 +08:00
    @kokutou 我不用乘车卡(也不支持杭州),只是好奇一个小程序怎么判断手机是不是 root 了
    kokutou
        9
    kokutou  
       2019-04-13 12:47:05 +08:00 via Android
    @azh7138m
    从接口返回的,可能是微信本身检测的发回服务器,小程序再获取。
    fyooo
        10
    fyooo  
       2019-05-29 09:22:47 +08:00
    @tony601818 国内的手机不支持 GMS,应该是没有 SafetyNet API 的。估计是小程序调用微信的接口检查是否 root 的,https://stackoverflow.com/questions/27291676/root-detection-methodology-in-android-which-cannot-be-bypassed
    UchihaJay
        11
    UchihaJay  
       2019-08-23 13:17:55 +08:00
    绝对坑,用之前不说,充值开通了告诉我不能用,我为你个乘车吗换手机?行我不要了,告诉我哪里退钱
    sadfQED2
        12
    sadfQED2  
       2019-10-08 14:32:59 +08:00
    @UchihaJay #11 我特么也是,充完钱跟我说不能用,用了面具的隐藏功能也不行
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5204 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 05:48 PVG 13:48 LAX 21:48 JFK 00:48
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86