JavaScript(简称JS or js)是一种脚本,一门编程语言,它是标准 Web 技术蛋糕的第三层,第一二层分别为HTML、css 。
01
JavaScript概述
1.1
JavaScript特性
不知道你有没有看过那张「感谢发明JavaScript」的图片:
JavaScript语言的特性导致它容易被人诟病,我们可以在浏览器中按F12,然后点击Console
,尝试输入:
数值 9
与字符串 "1"
相加,得到字符串 "91"
;但数值 9
与字符串 "1"
相减,得到数值 8
数组 [1, 2]
与数组 [3]
相加,得到字符串 "1,23"
这些都是JavaScript的特性,但并不了解JavaScript的人可能会因此产生类型转换等的困惑
1.2
JavaScript混淆
混淆并不是对代码的加密,它旨在替换掉代码中有意义的信息,将原本清晰的代码变得复杂;原因是JavaScript代码是公开的,为了让其能正常运行,不能采用加密的方式加密代码;但为了不被轻易获取、破解,我们可以增加阅读代码的成本
例如,代码:
alert("Aurora")
的执行会使得出现文本信息为 Aurora
的弹框,我们可以将其改写成:
(new Function("alert('Aurora')"))()
或者
[]["filter"]["constructor"]("alert('Aurora')")()
修改后的代码的功能与原先都是一样的,都是产生一个文本信息为 Aurora
的弹框
上面的还只是最初级的混淆,现在的混淆方式都是很强悍的,例如接下来要介绍的aaencode
02
aaencode混淆
2.1
aaencode实例
(゚Д゚)(゚o゚)(゚Θ゚)
之类的颜文字alert('Aurora')
经过aaencode将混淆成:alert('Aurora')
一样,但极大地增加了阅读代码的成本在线网站:https://utf-8.jp/public/aaencode.html
2.2
aaencode解析
我们可以尝试解析它:
o=(˙_˙) =_=3;
是上面aaencode得到的代码的第二句(每句以分号 ;
为分隔符),表面上看这里只有两个颜文字:o=(˙_˙)
和 =_=3
,但其实这里用JS语法定义了三个变量
将颜文字以 =
为分隔符,拆分开,得到 o = (˙_˙) = _ = 3;
其实就是
_ = 3;
(˙_˙) = _;
o = (˙_˙);
三个赋值语句的连写形式
赋值语句连写在弱类型语言中都可以实现,比如Python
人眼由于对颜文字的敏感,下意识将 o=(˙_˙) =_=3;
拆分解读为 o=(˙_˙)
和 =_=3;
;而对浏览器而言,它会尝试以JS的语法去分析它,这时它就以 =
为分隔符,将 o=(˙_˙) =_=3;
分析成一条三赋值的JS语句
语句 o=(˙_˙) =_=3;
让变量 o
、 (˙_˙)
和 _
同时赋值为3;随后就能够在后续代码中用这三个变量替代 3
混淆JS代码是有代价的,代价之一是冗余,像上式的 (˙_˙)
,其实就是一个用()
包起来的 ˙_˙
变量,这对括号()
事实上是没什么意义的,只是为了构成颜文字额外添加的
第三句是 c=(゚Θ゚) =(゚ー゚)-(゚ー゚);
,这里暗藏着一个减运算:由于上一句中变量 (゚ー゚)
已经赋值为 3
,所以这里的减运算得到 0
,然后也是一个连续赋值,令变量 c
和 (゚Θ゚)
同时初始化为 0
第四句是 (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);
其中的 (o^_^o)
其实是变量 o
与变量 _
进行异或运算,然后再与变量 o
进行异或运算;根据前面的赋值,就有 (3^3^3)
得到 3
;然后 (o^_^o)/ (o^_^o)
进行除运算,令前面的 (゚Д゚)
和 (゚Θ゚)
赋值为 1
最后再解析一下第五句:(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] };
将其排版一下,得到:
(゚Д゚) = {
゚Θ゚ : '_' ,
゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,
゚ー゚ノ : (゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,
゚Д゚ノ : ((゚ー゚==3) +'_')[゚ー゚]
};
(゚Д゚)
被定义成一个键值对(Map)゚Θ゚
直接被赋值为字符 _
゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚]
,这里的 (゚ω゚ノ==3)
比较变量 ゚ω゚ノ
与数值 3
,使得其结果为布尔值 false
,然后基于JavaScript的语法,false + '_' = "false_"
,布尔值 false
与字符串相加,本身会先变成字符串 "false"
;前面已经知道 ゚Θ゚ = 1
,所以最后就相当于 "false_"[1]
,取得下标为1的字符 a
゚ω゚ノ
就被赋值为字符 a
将 alert("Aurora")
改写成 []["filter"]["constructor"]("alert('Aurora')")()
,使其从语句变成字符串
每个字符串中的字符都混淆掉
例如字符 a
,就可以用前面定义的键值对 (゚Д゚).゚ω゚ノ
来替代;其它字符也相似
将每个字符混淆掉后,虽然看起来发生了改变,但功能不变,并且能直接执行
03
decode
3.1
.toString()
[]['filter']['constructor'][你的代码
]()
注意到最后面的 ()
,它表示调用函数,那么将它替换为 .toString()
,就能阻止前面函数的执行、并且把函数转换成字符串输出出来
在aaencode中,末尾始终是 (˙_˙)
,它表示传递了一个 _
字符的函数调用,将它改写为 .toString()
能够看到原函数内容:
3.2
hook function constructor
Function.prototype.__defineGetter__('constructor', function() {
return function(...args) {
console.log('code:', ...args);
return Function(...args);
};
});
这个方法直接修改了深层的JS功能,需要对JS有较深入的了解
原本函数调用只是单纯地调用该函数,但是修改后的JS能够在执行该函数的同时,把函数的执行语句通过 console.log()
输出出来
使用方法就是复制上面的代码,在浏览器的Console中执行,随后就可以执行一些JS混淆代码
当浏览器的Console执行上面的代码后,再执行经aaencode混淆后的 alert("Aurora")
代码,除了弹出消息框显示"Aurora"外,还会在Console中出现语句:code: alert("Aurora");
3.3
手工计算
手工将JS混淆还原的确是可行的,权当在练习JavaScript的类型转换
网络上还有人承接此类工作呢:
下一节将介绍JSF*ck混淆
未完待续......
作者:examine2
编辑:une
深大信息安全协会
Aurora
长按二维码关注