Skip to content

8qwe24657913/Analyze_baidu_BSK

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

分析百度BSK脚本

0. 引子

  • 众所周知,Javascript作为一门脚本语言,其加密是不可能的,而解密却十分简单,因为 js 要执行就需要解密,一般使用DevTools就可以直接看到解密后的代码
  • 然而,百度一个叫做BSK(basilisk)的脚本却让我改变了这个看法

一天,我在百度贴吧偶然发现了发帖参数中有个叫_BSK的东西

这又臭又长的内容让人心生怀疑,怕不是百度又在追踪用户?

1. BSK亮相

抱着这样的想法,我用DevTools找生成的脚本,然而令人意外的是,并没有找到_(:з」∠)_ 难道DevTools也会失手?

退而求其次,找到了引入BSK的地方:https://tb1.bdstatic.com/tb/_/poster/bsk_service_c6680a4.js

注:百度服务器用了文件合并,而我在本文中写的是单独的js地址,且本文提到的js均已上传到github,后文中不再赘述

可以看到,这个bsk_service_c6680a4.js引入了另一个脚本: https://fex.bdstatic.com/bsk/??dknsaZmLdyKfEeIVbKxn_dcc70f7.js,omzVouOACqkNljzDbdOB_af501e9.js

而后者又可以拆成dknsaZmLdyKfEeIVbKxn_dcc70f7.jsomzVouOACqkNljzDbdOB_af501e9.js两部分,为了简洁,我们姑且称它们为1.js2.js

如果你打开2.js,你会发现这个js只干了一件事,传出一个巨大的n维数组,很明显是提供数据的,所以我们把它改个名字,data.js

而打开1.js,情况就复杂得多了,它调用Function,构造了一个巨大的IIFE,而IIFE中虽然骚操作很多,却没有eval或是Function这种代码生成,需要进一步分析

(Time Flip)

3. 分析结果

好的,现在我们跳过了无趣的代码分析过程,直接给出结果(否则就太冗长了……)

经过分析,和上面说的一样,1.js根本没有去构造什么代码,而是写!了!一!个!JS!虚!拟!机!

js-in-js虚拟机什么概念?这可是失传已久的操作啊,上一个做这种操作的 Continuum 连Github都404了啊(虽然Continuum实现难度比这个不知高到哪里去了,也不代表只学过几年前端的人能写出这个脚本来,港真,目测多数人连读都读不懂……)

既然我们知道了这是个虚拟机,那就把它改名叫vm.js吧,哦,等等,还要反混淆,vm_deobf.js

为了方便各位阅读代码,我还搞了一份简化版:vm_deobf_simplified.js,把原vm_deobf.js中压栈弹栈压栈弹栈的弯弯绕改为简单的return以突出逻辑(顺便还优化了性能,修了BUG……)

好吧,我知道你们懒得读代码(读也不一定能懂……),我来说一说这个虚拟机大体的实现方式

  • 预先将要执行的JS转为AST并以某种方式编码在data.js里
  • 对AST的每个节点,根据type字段选择对应的函数,由函数来负责解析执行
  • 自己搞了一个函数及其作用域的实现,顶级作用域是window
  • 虚拟机内代码可以访问window的属性,调用虚拟机内外的函数(伪函数)
  • 输入一个object,虚拟机内的代码将最终执行结果写到这个object

然而,这还不是它的完全体……

4. 加/解密原理

事实上,data.js传入的巨大n维数组在转成AST的过程中,需要经过一次xor解密

数学知识复习:

  • a ^ b == b ^ a
  • (a ^ b) ^ c == a ^ (b ^ c)
  • a ^ 0 == a
  • a ^ a == 0

而xor加/解密,便是在加密时把数据与key异或,解密时再做一次,便还原了数据

这也不是很强嘛……老师,还能再给力点吗?

当然!事实上,这个虚拟机内运行的代码可以改变自己加密的key

只要调用虚拟机提供的函数_A(key),整个函数的key都会被临时改变,难以进行静态分析

如果更进一步,将_A(key)if else结合起来,我们还可以让一份代码表现出二义性,如果这么做,实际执行的代码就几乎无法分析了

好在,百度程序员并没有做到这个地步,也让我们得以一窥实际执行代码的真容

5. 拨云见日

_A(key)并没有与if else联合使用,让我们有了解码的能力

修改vm.js,让它输出AST,再借助escodegen生成代码,便得到了raw.js

让我们把raw.js人工反混淆并简化逻辑,得到deobf.js,这回终于是TM人能读的代码了……让我们赶快来读一读

**注:**实际运行的代码是有bug的,我在deobf.js中一一标出了 <-- 然而百度的人说并没有bug,怕不是我写的decoder有问题?

到了虚拟机里脚本跑了这几百毫秒也没有什么别的,大概三件事:

  • 一个,随机了自己的执行顺序;
  • 第二个,把机器发帖的特征写入了返回值;
  • 第三个,就是我们知道的“收集浏览器特征”。

值得注意的是,这脚本中有一个用canvas生成用户指纹的函数,实际上并没有被执行,不知是程序员忘了写还是有意为之 <-- 百度的人说是为了性能考虑……然而我认为VM损失的性能比这个多得多……

6. 结

在这篇文章中,我有意省略了分析代码的过程,一来不让文章读起来太过枯燥,二来没有js知识的人也能看懂

有兴趣的人可以读一读本repo中的脚本(可能有错误,欢迎指正),至少我是涨了些AST相关的经验值

如果有什么问题,欢迎pull request

最后,百度你有这工夫怎么不去修BUG?反馈吧一年四季就只有清缓存刷新一句话,卖大力丸也得换换台词吧(摔

About

记录分析百度"BSK"脚本的过程

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published