网址:aHR0cHM6Ly9wYXNzcG9ydC5tZWl0dWFuLmNvbS9hY2NvdW50L3VuaXRpdmVsb2dpbg==
整体流程:
1、获取主页参数
2、逆向pwd、h5Fingerprint
3、请求page_data链接
4、逆向Authencation、behavior、token_
5、最终请求验证
一、获取主页参数
url_ = "https://passport.meituan.com" + re.search(r'id="J-normal-form" action="(.*?)"', response).group(1).replace('=', '=').replace('amp;', '')
csrf = re.search(r'"csrf" value="(.*?)"', response).group(1)
uuid = re.search(r'uuid=(.*?)&', url_).group(1)
token_id = re.search(r'token_id=(.*?)&', url_).group(1)
continues = url_.split('continue=')[1]
二、逆向pwd、h5Fingerprint
继续跟进这个混淆后的js,看到是通过n生成sign的,n是主页返回的一些东西
然后到这里,将sign赋值给C,再加密,ts和cts稍微改下,其他固定即可(注意这里的环境值,后面滑块也会有,需要保持一致)
注:这个js如果觉得看得麻烦可以用ast反混淆下变量名,代码如下:
// 这个文件是run.js,demo.js放需要需要解混淆的js,decrypt_func.js是解密函数
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
const _0x24f5 = require("./decrypt_func");
let jscode = fs.readFileSync("./demo.js", {
encoding: "utf-8"
});
let ast = parse(jscode);
// 十六进制转换
function delete_unicode(path){
if (path.node.extra == undefined){return;}
delete path.node.extra
path.skip()
}
// 找到需要替换的调用函数,push到数组
name_array = ['a7_0x3a83']
function find_decode_name(path){
let node = path.node;
if (!node.declarations || node.declarations[0].init == null || node.declarations[0].init.name == undefined){return}
let call_name = node.declarations[0].id.name;
let binding = path.scope.getBinding(call_name);
if (call_name == '_0x41c885' || binding.references<=0){return}
if (name_array.indexOf(call_name) == -1){
name_array.push(call_name)
}
}
// 替换字符串
function replace_name(path){
let node = path.node;
if (!node.arguments[0]){return}
if(node.arguments[0].type == 'NumericLiteral' && node.callee.type == 'Identifier'){
const key = node.callee.name;
const value = node.arguments[0].value;
if (key == '_0x24f5'){
let value_new = _0x24f5(value);
console.log(value_new,"<-->",key,"<-->",value)
let string_node = types.stringLiteral(value_new)
path.replaceWith(string_node)
}
}
}
traverse(ast,{"NumericLiteral|StringLiteral": delete_unicode})
console.log("十六进制还原结束~~")
traverse(ast,{"CallExpression": replace_name})
console.log("变量名还原结束~~")
let {code} = generator(ast,opts = {jsescOption:{"minimal":true}});
fs.writeFile('decode.js', code, (err)=>{});
//这个文件是decrypt_func.js
function _0x5b47() {
var _0x25463d = ["Freefrm721 Blk BT", "postInfo", "slice", "NETWORK_FAILURE_TIP", "\n ", "Vivaldi", "YodaKNB", "RISK_GET_VERIFYINFO_LIMIT", "Date", "getUniformIndices", "121011", "OscillatorNode", "121042", "HIGH_FLOAT", "Vagabond", "SimSun-ExtB", "FrankRuehl", "127032", "setTimeout", "fill", "Bradley Hand", "isMobile", "AvantGarde Md BT", "Float32Array", "FRUTIGER", "Adobe Garamond", "pay", "request_code", "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf", "Tw Cen MT", "Geeza Pro", "_yoda_riskLevel", "NEVIS", "cts", "assign", "-9999px", "MAX_COMBINED_UNIFORM_BLOCKS", " : null", "globalLoadModel", "GOTHAM BOLD", "getActiveUniformBlockName", "toFixed", "TRIANGLES", "Cambria", "121125", "_timelimit", "resetVariable", "root", "yodaCommonThemeColor", "failCallbackFun", "__core-js_shared__", "name", "Serifa BT", "RISK_FACE_POLICE_DATABASE_NOT_FOUND", "RISK_MOBILE_NOT_VALID", "isNeedLoad", "quickapp_miniProgram", "yodaMoveingBar", "rejected", "getContext", "MT Extra", "Bradley Hand ITC", "Arial", "write", "AliApp", "decode", "boxError", "_selenium", "classof", "COMPILE_STATUS", "isLoading", "sliderMaxLenth", "bindEvents", "MS Reference Specialty", "buttonName", "Lithograph Light", "setValueAtTime", "TypoUpright BT", "symbol-registry", "getExtension", "121005", "Khmer UI", "uniform4uiv", "byteOffset", "RISK_USER_NOT_LOAD", "2.2.2", "Vladimir Script", "toDataURL", "MS PGothic", "getUniformBlockIndex", "abnormal", "checkRiskLevel", "EUROSTILE", "customElements", "succCallbackFun", "last", "Noteworthy", "121053", "111", "wRU", "findChild", "00101", "substr", "b_techportal_property_mv", "language", "return (function() ", "bind", "waimai", "precision", "RISK_GET_VERIFY_INFO_ERROR_RETRY", "scrollLeft", "Freestyle Script", "A promise cannot be resolved with itself.", "CordiaUPC", "Footlight MT Light", "Centaur", "121064", "121133", "setResult", "MY_miniProgram", "passive", "padding: .3em .8em; border: 1px solid #999; border-radius: .3em; background: transparent; margin: .6em auto; outline: none; color: ", "floor", "MingLiU_HKSCS-ExtB", "getQuery", "navigator", "_bytes", " \n 请求地址", "51d7c9ad", "apply", "Gill Sans", "Timestamp", "function", "options", "pathname", "[object]", "removeHandler", "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", "makeDOMException", "121001", "Raavi", "切换验证方式", "RISK_VERIFY_REQUEST_TIME_OUT", "pageX", "NewsGoth BT", "key", "#A4A3A3", "Mrs Eaves", "title", "request_null", "GeoSlab 703 Lt BT", "Pickwick", "121057", "getProgramParameter", "delta", "Iskoola Pota", "' src='https://s3plus.meituan.net/v1/mss_f231eb419c414559a1837748d11d4312/yoda-resources/help_icon.png'>\n
\n \n
\n
", "customStyle", "ALPHA", "Harrington", "Aparajita", "getInt32", "MUSEO", "exponentialRampToValueAtTime", "\n
\n , "__selenium_evaluate", "none", "Serifa Th BT", "121050", "call", "Cuckoo", "pageY", "allSettled", "webgl", "moveTo", "RISK_COMMON_PARAMS_LOST", "Lucida Calligraphy", "localStorage", "DFKai-SB", "_setter", "Viner Hand ITC", "Onyx BT", "isKNBEnv", "Kalinga", "getBoundingClientRect", "boxOk ", "arc", "setUint8", "'>\n ", "Gill Sans MT Condensed", "Niagara Solid", "fontSize", "Tubular", "Internet Explorer", "normal", "103", "Error: ", "Century Schoolbook", "Bookshelf Symbol 7", "RISK_AUTHORIZE_CODE_EXPIRE", "charCodeAt", "Marion", "Bodoni 72 Smallcaps", "nativeSign sign fail", "Sketch Rockwell", "targetTouches", "新版签名异常", "ネットワークのつなぎ状態が不安定です", "'>\n , "rangeMin", "getStringHashMD5", "availWidth", "Bernard MT Condensed", "drawArrays", "jump", "https://s3plus.meituan.net/v1/mss_f231eb419c414559a1837748d11d4312/yoda-resources/slider/m_loading.png", "invalidateFramebuffer", "top", "Uint16Array", "loadSource", "moveingBarError ", "Vrinda", "withCredentials", "Heiti SC", "label", "Wingdings 3", "Kannada Sangam MN", "[null]", "not a function", "Curlz MT", "Forte", "Constantia", "Amazone BT", "iterator", "动态签名", "121002", "Bandy", "op-symbols", "Pegasus", "RISK_NO_SUCH_METHOD", "getShaderPrecisionFormat", "getwd", "hash", "done", "succCallbackUrl", "Can't call method on ", "MONO", "Tahoma", "BankGothic Md BT", "MAX_COLOR_ATTACHMENTS", "forEach", "safari", "127021", "code=", "FILLPHONENUMBER", "Old English Text MT", "startX", "Bodoni 72", "'>\n \n ", "webdriverScriptFn", "Gloucester MT Extra Condensed", "valueOf", "'>为了您的账号安全请选择一种方式完成验证\n
\n
"ALPHA_BITS", "INPUT", "toBytes", "121139", "writable", "getHash", "table", "\n
\n
\"padding-top: 50%;\">\n \"line-height: 32px;font-size: 1.2em;font-weight: bold; color: #333;\">出错了
\n \"line-height:32px; font-size: 1em; color: #333;\">", "drawArraysInstanced", "preventExtensions", "Snap ITC", "get", "PTBarnum BT", "
\"text-align: center;\">\n \n \n "Uint8ClampedArray", "Simplified Arabic", "Wide Latin", "使用新版签名", "MODULE_VERSION", "appendChild", "NETWORK_TIMEOUT_CODE", "core", "setInt16", "custom", "styles", "sent", "font", "lineHeight", "yodaInitTime", "yodaVersion", "Gill Sans MT Ext Condensed Bold", "16118iwsyfk", "Chalkduster", "titleWrapper", "highp", "Yes", "jsVersion", "auto", "RISK_UP_SMS_OUT_OF_SERVICE", "setAttribute", "deleteVertexArray", "calledSelenium", "CaslonOpnface BT", "MAX_ELEMENT_INDEX", "maxDecibels", "left", "propertyIsEnumerable", "Cornerstone", "Marker Felt", "100oksGWu", "getUint16", "Sherwood", "getAttribute", "ARNO PRO", "f_e_s_e", "CT_PRESIGN_FAIL", "uniformBlockBinding", "addEventListener", "Univers CE 55 Medium", "now", "startDrag", "IE_PROTO", "contentWindow", "Bodoni MT", "121018", "Mongolian Baiti", "Times", "reload", "Authencation", "David", "MAX_COMBINED_TEXTURE_IMAGE_UNITS", "ids", "reason", "set", "wrapper", "yoda-language", "mousemove", "VOICE", "max", "GeoSlab 703 XBd BT", "RISK_ERROR_OUT_OF_LIMIT_AND_DOWNLOAD_APP", "removeEventListener", "ownKeys", "'>\n ", "getActiveUniformBlockParameter", "vertexAttribPointer", "vertexAttribDivisor", "RISK_GET_VERIFYINFO_TIMES_LIMIT_ONE_DAY", "Gisha", "event", "Futura Lt BT", "MS LineDraw", "isSealed", "selenium-evaluate", "BUTTON", "FangSong", "Futura Md BT", "moveingbar", "121138", "Apple Color Emoji", "GoudyHandtooled BT", "btn", "IMAGE", "2397388dcLsoC", "&request_code=", "phantom", "iframe", "vertexAttribI4iv", "AVENIR", "sliderType", "encryptToBase64", "ArrayBuffer", "defineProperties", "RISK_VOICE_SEND_TIMES_LIMIT_ONE_DAY", "letterSpacing", "__$webdriverAsyncExecutor", "init", "PC_FACE", "rohr_", "DEPTH_BITS", "canvas", "isDoubleTap", "Script MT Bold", "innerHeight", "cd_frame_id_", "ontouchstart", "GOTHAM", "getTransformFeedbackVarying", "getInternalformatParameter", "mousedown", "Lithograph", "MAX_SAMPLES", "getWebGlReport", "RISK_REAL_NAME_AUTH_STATUS_ERROR", "outline", "Edge", "initSlider", "Zurich BlkEx BT", "Bazooka", "Long Island", "compressedTexImage3D", "OSAKA", "MS Mincho", "Segoe UI", "useProgram", "0123456789ABCDEF", "RISK_LEVEL", "length is not a small enough positive integer.", "getUint8", "LINK_STATUS", "OPTIMA", "Microsoft Tai Le", "_Selenium_IDE_Recorder", "getQueryParameter", "#F4F4F2", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "Poor Richard", "Arial Unicode MS", "cententWrapper", "Bad UTF-8 encoding 0x", "'>\n
, "clear", "miniProgram", "当前请求状态", "サーバーが異常です。しばらくしてからもう一度お試しください", "createRadialGradient", "domAutomation", "MAX_SERVER_WAIT_TIMEOUT", "Modern", "message", "Arabic Typesetting", "tabindex", "clearColor", "timeoutCount", "Microsoft Uighur", "RISK_NO_AUTH", " : ", "block", "substring", "l_d_s_c", "Coronet", "invalidateSubFramebuffer", "div", "RISK_MERCHANT_ID_NOT_VALID", "Humanst 521 Cn BT", "jsonp_", "bindBufferRange", "121126", "webView", "textShadow", "Arial Rounded MT Bold", "Tw Cen MT Condensed Extra Bold", "/feedback/manmachine/#/?requestCode=", "ALIASED_LINE_WIDTH_RANGE", "Rage Italic", "publish", "#E10909", "Yes, D3D11", "stencil", "src", "moveingBarY", "attachShader", "'>\n
](_0x4356e7['shift']());
} catch (_0x4f5641) {
_0x4356e7['push'](_0x4356e7['shift']());
}
}
})(_0x5b47, 0xedc46)
function _0x24f5(_0x3b92fb, _0x1d45ea) {
var _0x1fbea5 = _0x5b47();
return _0x24f5 = function(_0x1415da, _0x306f35) {
_0x1415da = _0x1415da - 0x0;
var _0x534c81 = _0x1fbea5[_0x1415da];
return _0x534c81;
}
,
_0x24f5(_0x3b92fb, _0x1d45ea);
}
module.exports = _0x24f5;
三、请求page_data链接
这里用之前返回的requestCode作为参数请求,session、sign、timestamp、verifyMethodVersion、yodaVersion后面都会用到
四、逆向Authencation、behavior、token_
(1)behavior,参数定位:
注:这里的point轨迹t和后面token加密的mt轨迹是相互验证的
继续往后跟会到这里
这里对之前拿到的session进行atob,生成一段代码再eval下,会决定接下来走switch的那个case。
再继续往后跟,到这里
这个f是一开始就生成的,这里是拿了一开始返回的session和sign生成一段代码,最后再执行这段代码得到f,位置如下:
这里他自己hook了这个window.f
这里需要补的环境如下(这个滑块也就这点环境,如果发现还检测了其他东西删掉即可,不影响整个算法的生成):
window = global;
var md5 = require('md5-node');
var Buffer_ = window.Buffer;
window.Buffer = undefined;
screen = {
'availHeight':1040,
'availLeft':0,
'availTop':0,
'availWidth':1920,
'colorDepth':24,
'height':1080,
'pixelDepth':24,
'width':1920,
'isExtended':true
}
localStorage = {
Storage:{
'length':0
}
}
navigator = {}
navigator.geolocation = new (class Geolocation{});
navigator.geolocation.getCurrentPosition = function getCurrentPosition(){
debugger;
};
navigator.geolocation.clearWatch = function clearWatch(){
debugger;
};
navigator.geolocation.watchPosition = function watchPosition(){
debugger;
};
HTMLBodyElement = function HTMLBodyElement(){debugger;}
!function(){
this.atob = function(encodeBase64){
// debugger;
return Buffer_.from(encodeBase64, "base64").toString("binary")
}
this.btoa = function(decodeBase64){
// debugger;
return Buffer_.from(decodeBase64, "binary").toString("base64")
}
}()
;
(2)token,参数定位:
token和behavior的生成算法是一样的,所以只说下需要注意的地方
这里同样是ts和cts需要改下,mt是轨迹,检测较为严格,其他都不怎么检测,再次提醒这个mt和behavior的point是有关联的,打印下对比下就知道了
(3)Authencation,参数定位
这里用到了很多之前的返回的参数
注:这个timestamp是返回的,不是实时获取的,后面的验证请求也是这个timestamp