声明:本文只做技术交流,不提供源码,如有侵权,请告知删除,谢谢。
今天我们来看大众点评验证码的 window.f()函数。下面开始表演。
目标网址:
https://account.dianping.com/login?redir=http%3A%2F%2Fwww.dianping.com%2F
像往常一样,打开谷歌浏览器,并按下F12,地址栏输入网址,并回车,选择通过手机密码登录:
多点击 登录 按钮几次,调出验证码:
滑动滑块,抓包分析,验证API:
https://verify.meituan.com/v2/ext_api/login/verify?id=71
提交的参数如下:
我们来看看这个 behaior参数。
全局搜索 behaior,并打上断点:
继续点击登陆,滑动滑块,停在了断点处,跟进去看看:
t 是轨迹相关的参数,r 是请求某个api的返回值(request_code),
E[v][Jn] 是一个大函数里面的一个函数,可以将整个大函数扣出来,以返回对象的方式返回该函数:
再看这个 S[qn] 函数:
一直往下走,来到这个 k 函数:
跟进去看看:
这里的 定义了一个 r 变量,并赋值,这个等号右边的值:
这是个window对象里面的值,这个是怎么来的呢,肯定每次都不一样(读者可自行验证),看着代码都是一些乱七八糟的 名字,根本无从找起,这该怎么处理呢?
我们观察到,它的值有点像base64编码后的值,来看看能解码不:
可以解码,说明确实是base64编码后的值,既然这样,我们不就可以Hook window对象的btoa函数,看看那些地方调用它了?
写下如下脚本,对btoa函数进行Hook:
// ==UserScript==
// @name base64encode
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @include *
// @grant none
// ==/UserScript==
(function() {
'use strict';
var base64encode = window.btoa;
window.btoa = function(a) {
console.log("Detect window.btoa", a);
debugger;
return base64encode(a);
}
})();
保存后,关掉当前的大众点评页面,并重新打开,按照之前的操作进行登录,调出验证码,再点击登录,弹出验证码时,停在了这里:
确实Hook住了,这里的 a 值也我们之前 解码后的值比较像,我们看堆栈
有个 get函数,跟进去:
window[Wn] 就是 window.btoa函数,看到后面有个 window[ts] = void 0,这是用过之后就再也用不了了,反正已经返回了。
那window[ts] 是什么函数,跟进去看看:
原来在这里,注意,这是一段VM代码,说明可能是动态生成的,即每一次返回值都可能不一样。我们看看它是怎么来的。
继续跟堆栈,找到调用get的地方,也就是上一层:
代码如下:
看到有很多的window对象值,有些是atob和btoa,还有这个window[lo][U],我们在控制台看看是什么:
我们在 Network里面可以找到这些信息,其请求api:
https://verify.meituan.com/v2/ext_api/page_data
响应结果:
确实可以看到很多值都是一样的。其实了解这个函数的流程,也不难:
今天只讲这个 window.f 的值的来源及怎么生成。
来源就是上面这张图,怎么生成的就是 VM里面的代码,代码如下:
太长了,我就放个截图吧。
调试这段代码,非常的有意思,有很多的 case 语句和 条件表达式,如果有个条件不满足,得出的结果肯定是个错的。注意看下面这行:
navigator = undefined;
这段代码在浏览器环境不会改变什么,但是在node环境可就不一样了。
条件语句会检测一些window和navigator对象(暂时只遇到这两个),如果某个值不存在,或者存在但是为空,得到的结果肯定是个错的。
请读者自己去调试,真的非常的有意思,反正就是要薅掉你一些头发。
这个 behaior 参数已通过验证OK,说明步骤没错,主要学习方法就好了。
如果遇到有什么不懂的地方,可以私信我,也可以留言,我有空会解答一下。