3

详解升讯威在线客服系统前端 JavaScript 脚本加密技术(1) - 曹旭升(sheng.c)

 1 year ago
source link: https://www.cnblogs.com/sheng_chao/p/16445609.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

详解升讯威在线客服系统前端 JavaScript 脚本加密技术(1)

我在业余时间开发维护了一款免费开源的升讯威在线客服系统,也收获了许多用户。对我来说,只要能获得用户的认可,就是我最大的动力。

这段时间有几个技术小伙伴问了我一个有意思的问题:“你的前端脚本是怎么加密的?”

我决定写帖子来分享这个问题的答案。

在线客服系统访客端:

在线客服系统客服端:


免费在线使用 & 免费私有化部署:https://kf.shengxunwei.com


视频实拍:演示升讯威在线客服系统在网络中断,直接禁用网卡,拔掉网线的情况下,也不丢消息,不出异常。
https://blog.shengxunwei.com/Home/Post/fe432a51-337c-4558-b9e8-347b58cbcd53


首先打开客服系统官方网站:https://kf.shengxunwei.com 然后查看嵌入的客服系统 JavaScript 文件,接着,用浏览器访问嵌入站点的 JavaScript 文件。可以看到,文件是加密和压缩过的:

然后我们通过格式化工具,格式化看看:

所有的变量名都经过了混淆:

所有的函数名都经过了混淆:

那么这是怎么做到的呢?我打算分成几篇不同的博文,循序渐进的解答这个问题,如何混淆前端 JavaScript 代码。

JavaScript 语法解析

JavaScript 是如何执行的

对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节码生成。

对于解释型语言(例如 JavaScript)来说,通过词法分析 -> 语法分析 -> 语法树,就可以开始解释执行了。

具体过程是这样的:

1.词法分析是将字符流(char stream)转换为记号流(token stream)

NAME "AST"  
EQUALS  
NAME "is Tree"  
SEMICOLON

2.语法分析成 AST (Abstract Syntax Tree)。

3.预编译,当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理!并且是先预声明变量,再预定义函数!

4.解释执行,在执行过程中,JavaScript 引擎是严格按着作用域机制(scope)来执行的,并且 JavaScript 的变量和函数作用域是在定义时决定的,而不是执行时决定的。JavaScript 中的变量作用域在函数体内有效,无块作用域;

function func(){
    for(var i = 0; i < array.length; i++){  
      //do something here.  
    }
    //此时 i 仍然有值,及 i == array.length  
    console.log(i); // 但在 java 语言中,则无效
}

JavaScript 引擎通过作用域链(scope chain)把多个嵌套的作用域串连在一起,并借助这个链条帮助 JavaScript 解释器检索变量的值。这个作用域链相当于一个索引表,并通过编号来存储它们的嵌套关系。当 JavaScript 解释器检索变量的值,会按着这个索引编号进行快速查找,直到找到全局对象(global object)为止,如果没有找到值,则传递一个特殊的 undefined 值。

var scope = "global";
scopeTest();
function scopeTest(){  
    console.log(scope);  
    var scope = "local";  
    console.log(scope); 
}
打印结果:undefined,local;

我们常说的 V8 是 Google 发布的开源 JavaScript 引擎,采用 C++ 编写。SpiderMonkey(Mozilla,基于 C)、Rhino(Mozilla,基于 Java),而 Nodejs 依赖于 V8 引擎开发,接下来的内容是 JavaScript 在 V8 引擎中的运行状态,而类似的 JavaScript 现代引擎对于这些实现大同小异。

在本文的开头提到了编译型语言,解释型语言。JavaScript 是解释型语言且弱类型,在生成 AST 之后,就开始一边解释,一边执行,但是有个弊端,当某段代码被多次执行时,它就有了可优化的空间(比如类型判断优化),而不用一次次的去重复之前的解释执行。 编译型语言如 JAVA,可以在执行前就进行优化编译,但是这会耗费大量的时间,显然不适用于 Web 交互。

于是就有了,JIT(Just-in-time),JIT 是两种模式的混合。

它是如何工作的呢:

1.在 JavaScript 引擎中增加一个监视器(也叫分析器)。监视器监控着代码的运行情况,记录代码一共运行了多少次、如何运行的等信息,如果同一行代码运行了几次,这个代码段就被标记成了 “warm”,如果运行了很多次,则被标记成 “hot”。

2.(基线编译器)如果一段代码变成了 “warm”,那么 JIT 就把它送到基线编译器去编译,并且把编译结果存储起来。比如,监视器监视到了,某行、某个变量执行同样的代码、使用了同样的变量类型,那么就会把编译后的版本,替换这一行代码的执行,并且存储。

3.(优化编译器)如果一个代码段变得 “hot”,监视器会把它发送到优化编译器中。生成一个更快速和高效的代码版本出来,并且存储。例如:循环加一个对象属性时,假设它是 INT 类型,优先做 INT 类型的判断

4.(去优化)可是对于 JavaScript 从来就没有确定这么一说,前 99 个对象属性保持着 INT 类型,可能第 100 个就没有这个属性了,那么这时候 JIT 会认为做了一个错误的假设,并且把优化代码丢掉,执行过程将会回到解释器或者基线编译器,这一过程叫做去优化。

明白了基本原理之后,接下来就是如何执行混淆的过程了,

未完待续。


免费在线使用 & 免费私有化部署:https://kf.shengxunwei.com


视频实拍:演示升讯威在线客服系统在网络中断,直接禁用网卡,拔掉网线的情况下,也不丢消息,不出异常。
https://blog.shengxunwei.com/Home/Post/fe432a51-337c-4558-b9e8-347b58cbcd53



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK