某联招聘版某数反反爬— 2. 总体剖析

术语

1. 动态js

  • 在js运行期间,通过字符串拼接等形式生成一段js代码,然后通过eval或Function的方式动态执行
  • 某数的动态js是和页面配套的,ajax请求不会改变动态js
  • F5刷新页面或者浏览器输入网址得方式都会生成新的动态js
  • 动态js和生成他的页面有配套关系,不配套时生成的cookie或MmEwMD参数无效
  • 某数动态js每次改变的仅仅是变量名称,其他逻辑丝毫不变(敲黑板,划重点)
  • 动态js是某数反爬的核心代码,有上万行代码

2. $_ts

  • 某数中仅有的固定名称的变量
  • 是一个全局变量,页面js、动态js通过该全局变量互通有无
  • 全局变量再页面js、动态js均有替身,替身的名字随机生成

3. 变量名称池

  • 某数在生成动态js时维护了一个变量名称的数组,称为变量名称池
  • 页面代码根据这个变量名称池生成动态js的变量名
  • 对于不同的动态js可惜根据这个变量名称池的下标进行对应

4. MmEwMD 参数后缀

  • ajax请求的url地址信你自动添加的后缀参数
  • 在职位列表页面内点击翻页或者筛选时会发现ajax请求都再url中添加了后缀参数,其中 MmEwMD后缀参数有用,其他几个参数作用不大

5. FSSBBIl1UgzbN7N443T、FSSBBIl1UgzbN7N443S

  • cookie中存放的key值,其中FSSBBIl1UgzbN7N443S是服务器端返回的(httponly),FSSBBIl1UgzbN7N443T是通过js在浏览器生成的,目前来看443S服务器端未校验
  • 这个443其实是服务器的端口号,有的网站是FSSBBIl1UgzbN7N80T、FSSBBIl1UgzbN7N80S

6. 版本号

  • 443T的第一位、MmEwMD后缀参数的第一位都是数字,表示某数的版本,某联用的是5版本

7. localStorage

  • 动态js中部分信息会存储到localStorage中,localStorage不可用时回通过全局变量存储

8. 六个盒子

  • 在动态js中有6个长度为255的整数数组,在字符串转整数数组加密时会用到这些数组进行置换,我称之为六个盒子。

页面组成

1. meta content

  • 存放的是一些在动态js中要用到的字符串常量

2. js引用 iso编码的文件

  • 这个文件名和内容时目前是固定的(大大降低了难度)
  • 这个是动态js的主要内容来源

3. 页面js代码

  • 生成全局变量$ts,名称固定
  • 结合引用的外部js生成动态js
  • 动态js的变量名是随机生成的,形式为_$xx
  • 开头的几个函数都是在动态js中要调用的
  • 页面js还有requestid 目前来看没用处

正常访问流程

1. 访问页面

  • 生成并执行动态js代码
  • 动态js对xhr进行hook
  • 增加定时任务
  • 挂载各种鼠标、键盘等事件监听

2. 定时更新cookie

  • 动态js定时(50s)更新cookie中的FSSBBIl1UgzbN7N443T
  • 该有另外一个定时任务,用来投毒检验

3. 收集鼠标键盘事件

  • 如果有鼠标点击(按下、松开)、移动、滚轮滚动或者键盘按键封事件发生,会将相关数据写入一个数组,同时记录事件类型以及该事件类型的次数
  • 目前发现服务端没有进行检验

4. ajax请求

  • 对ajax请求进行拦截,基于cookie中的FSSBBIl1UgzbN7N443T生成一个新的FSSBBIl1UgzbN7N443T,再这个新的FSSBBIl1UgzbN7N443T后添加一个64位字符串行程MmEwMD后缀参数追加到url中
  • 除追加上述参数在,在此之前还会追加paeid、requestid等参数,实际发现不加这两个也没有影响

动态js主要逻辑分析

动态js的业务逻辑可以划分为

  • 初始化阶段
  • 定时任务阶段
  • ajax hook触发阶段

初始化阶段

也就是通过eval执行动态js的时候,这个过程主要工作有

  • 是对js代码的变量进行初始化赋值
  • 对页面meta中的content进行解析处理成字符串常量数组
  • 根据一个固定密钥(84位)生成6个整数数组(六个盒子),字符串转整数时都基于6个盒子进行转换
  • 生成一个初始的FSSBBIl1UgzbN7N443T,存入cookie中

定时任务阶段

  • 50秒重新生成一次FSSBBIl1UgzbN7N443T,新FSSBBIl1UgzbN7N443T的生成需要基于cookie中已有的FSSBBIl1UgzbN7N443T
  • 此过程也需要读取meta中的一个字符串常量
  • 也需要全局变量$_ts中数据参与
  • 还需要调用页面js代码中的函数
  • 新生成的FSSBBIl1UgzbN7N443T存入cookie中

ajax hook触发阶段

  • 检验请求的域名是都在白名单中
  • 检验请求的协议是否时http或者https
  • 基于cookie中的FSSBBIl1UgzbN7N443T生成一个新的FSSBBIl1UgzbN7N443T(新生成的不存入cookie中)
  • 加密生成一个64位字符串拼接到FSSBBIl1UgzbN7N443T之后,作为MmEwMD追加但请求的url之后
  • 发起ajax请求,得到json格式的职位列表信息

核心代码提取

以上主要逻辑梳理清晰后,就可以把不相干的代码干掉了,精简后不到1000行代码。

  • 进行简单的封装,提供一个对外函数,输入ajax请求的url,返回一个追加了MmEwMD后缀参数的url
  • 通过其他语言执行js,调用对外函数
  • 其他需要就可以爬去职位列表了
  • 当然某联限制第3页及以后的数据需要登录才能拿到,登录的cookie就小菜一碟了!

后记

  • 六个盒子的置换算法有点像置换密码本加密,又不是,不确定属于哪种加密算法,不过挺有趣!(随然折腾了我挺长时间!)
  • 关于鼠标键盘事件,暂时直接屏蔽了,不确定大规模采集是否回检验,不过追加这些数据难度不大,按规则伪造即可
  • requesid、pageid直接忽略了,但后续版本可梦会增加这些参数的检验
  • 只需要分析一套页面js、meta、动态js,然后将其中的一些变量数据都可以固化下来,然后就可以以不变应万变了生成MmEwMD了

页面reload机制

在2020年5月1日前 存在这种机制,目前没有了

  • 第一次访问页面会返回一个只包含百余行js代码的简单页面
  • 这段代码作用流式生成一个acw_sc__v2字样的cookie
  • 携带这个cookie自动重新夹在页面,就看到那个带meta的主页面了

第一次访问

响应的页面是一段含有JS代码的页面,并且
Set-Cookie: acw_tc=2760825115885621782278886e6ff96bc0a1ae185b1a44bad37a5e81b0450e;path=/;HttpOnly;Max-Age=2678401

JS代码负责生成cookie acw_sc__v2,并再次重新加载当前页面

第二次访问

携带两个cookie值

Cookie: acw_tc=2760825115885621782278886e6ff96bc0a1ae185b1a44bad37a5e81b0450e; acw_sc__v2=5eaf89021c00cc59ef77c712ae257ab673cb0a83

响应设置两个cookie值:


Set-Cookie: FSSBBIl1UgzbN7N443S=Ln0Z3igJCz1OlYV7LMd.SROLwsWoQ21ZB5uwPc7iL9A9AsK.dwTKxVy6cCRZuIVs; Path=/; expires=Thu, 02 May 2030 03:16:18 GMT; Secure; HttpOnly```

此次访问的响应页面,包含meta content 以及加密js引用等,负责每隔50秒生成一个cookie FSSBBIl1UgzbN7N443T
原创文章 16 获赞 10 访问量 1万+

猜你喜欢

转载自blog.csdn.net/jmfang/article/details/106117170