网站直接拿到的是高度混淆的9k-10k行随机的js代码.
关于ast的基础语法我就不多做介绍了,主要提供思路.借助ai工具相信你也可以达成相同的效果.
首先进行基础的StringLiteral,NumericLiteral的还原以及对BinaryExpression如果是表达式并且可以求值,那么直接获得最后值.
需要处理的ast节点有BinaryExpression,UnaryExpression,StringLiteral,NumericLiteral这些,ast代码大致长这样

得到的效果如下三图.下面三图的左边是解混淆前的,右边是解混淆后的效果.



然后是这种类型的代码

比如GZ = jGHK(rn.j3) + HK(rn.j4)
很显然是需要进行值替换的,rn.j3=1460,rn.j4=2301,rn.j5=1460都是可以向上找到赋值的.
ast逻辑是,我们寻找定义这种类型的数组或者对象,取出里面的属性值构建成我们自己的隐射表,然后对后面进行引用的部分进行替换.代码大致是下面这样


执行ast替换后得到的是如下面对比图效果.

下一步是处理HK这种类型的调用.

从代码编译器我们是可以看到HK实际上是指向H函数的.而H函数长这样

注意:H函数里大多是原生js,说明大概率H函数是可以独立调用的.
var A = G();
H = function (D, F) {
D = D - (-516 + vh);
var i = A[D]
往上看两眼就知道G()实际上是一个定值数组,长这样

那么这里只需要手动替换一下即可,然后H函数即是本地可运行的函数了.那么我们手动定义一个function H(),并计算诸如try {
GZ = jG[Hk(1549) + Hk(1366)][Hk(2138) + 'te'] && jG[Hk(1549) + Hk(1366)]Hk(2138) + 'te';
} 这类代码里面的比如Hk(1549)的值并进行ast替换.比如 Hk(1549)='span {fon',Hk(1366)='substring',Hk(2138)='#nocaptcha'
这里要提一下这个js的唯一一个坑点.D = D - (-516 + vh),观察这个vh的来源:
function vo() {
return vh = vP(PgnPjZ'toString', 'PgnPjZ', "4ad2269"), 'zbcJ0Uq';
}
而PgnPjZ是整个js,所以一旦对js文件进行任何改动,那么PgnPjZ['toString']与原本的预设值都不一样,vh的值也会不一样,会直接进入死循环导致网页卡死.解决方案是给vh手动设置值,至于值是多少,在浏览器跟一下js就拿到了当前js对应的正确值.时间有点久远了,没记错的话,大概vh会是D = D - (-516 + vh)的负数数字的正值,应该是516.
与此同时,另一个难点是,如何知晓HK函数是指向H函数的.

实际代码的逻辑无非是比如var kk=H,...,var su=kk,...,var Hp=su,...,var HK=hp这样下来的.我们要做的就是使用ast,在作用域内向上溯源,一直溯源到最顶点的H函数.
然后到最后一步,处理这种类型的函数调用.

观察到这些函数都是简单的对参数进行一个二元运算然后返回结果,那么思路就是,通过ast获得return的部分,然后直接对引用的地方进行结果替换.比如jj['aCDYX']整个替换成 x<y 或者jj.pRDRy(s,e)替换成 s-e
以上全部都完成后,删除掉已经失去价值的无引用的定义部分,如


后得到只剩三千多行的清晰可见的代码.然后在浏览器中进行替换跟栈后,会发现真正的核心加密代码仅仅只有100行.涉及浏览器环境的部分作用仅限于检查,不参与最后加密的运算.

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!