问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
How to fuck JSFuck
先叠个甲,这类的混淆我在网站见过很多次,这次单独研究这个混淆主要是HVV时候没空写,这次先解决给下次未雨绸缪。  给我的新工具写的小文章。请点star,我会好好更新的。 <https://github.com/AugustineFulgur/ClarityJS> 0 What is JSFuck ---------------- 请点击: <https://jsfuck.com/> 这是混淆前: `alert(1);console.log(1);` 这是混淆后: `[][(![] + [])[+!+[]] + (!![] + [])[+[]]][([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][ [] ] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][ [] ] + [])[+[]] + (!![] + [])[+!+[]] + ([][ [] ] + [])[+!+[]] + (+[![]] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (+(!+[] + !+[] + !+[] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][ [] ] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][ [] ] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][ [] ] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [!+[] + !+[]]) + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]])()((![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[+!+[] + [+!+[]]] + [+!+[]] + ([] + [] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [!+[] + !+[]]] + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]](+[![]] + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]()[+!+[] + [!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (+(+!+[] + [+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]]) + [])[+!+[]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [+[]] + ([] + [])[([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][ [] ] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]])[!+[] + !+[] + [+[]]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[+!+[] + [+!+[]]] + [+!+[]] + ([] + [] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [!+[] + !+[]]] + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]](+[![]] + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][ [] ] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]()[+!+[] + [!+[] + !+[]]])[!+[] + !+[] + [+!+[]]])` 1 正向分析 ------ 这种混淆我不是第一次见啊,说白了就是由于:  好吧,其实是因为: 1.JS里的隐式类型转换实在是太多了-> 2.加上他居然会把func+str变成print(func)+str-> 3.再加上你还可以用\[\]调用对象-> 4.你可以用一把括号构造函数-> 5.函数+一些乱七八糟的东西会变成类似'function anonymous() {}'的字符串-> 6.取个索引就变成了单个字符。 **JS说“let me CONVERT**\*\* it for you”,于是有了JSFuck^ ^~\*\* ### 1.1 分析代码组成元素 观察一下混淆后的代码,可以看出这段混淆代码主要由\[\]、!、()、+四个元素构成。 其中对\[\]使用了大量变形,如!\[\]、!!\[\]、+!+\[\]、!+\[\]等。还有一些括号,其中部分属于函数调用。 小Tips,可以用`<sub><font style="color:#8A8F8D;">)(</font></sub>`快速查找这样的函数调用。 从函数调用处分开,可以发现它被分为了三个部分: `[][(![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((!![]+[])[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+[![]]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][[]]+[])[+!+[]]+(![]+[])[+!+[]]+((+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]) () ((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[+!+[]]]+[+!+[]]+([]+[]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[!+[]+!+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]](+[![]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]])[!+[]+!+[]+[+!+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[+[]]+([]+[])[([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[+!+[]+[+!+[]]]+[+!+[]]+([]+[]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[!+[]+!+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]](+[![]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+!+[]]+(!![]+[])[+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+!+[]]+(!![]+[])[+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]])[!+[]+!+[]+[+!+[]]])` 有些运算可能正常人看不太懂,这时候可以用AST浏览器查看节点,比如!+\[\]:  ### 1.2 隐式类型转换-构造字符串  最简单的例子是'1'+'1'和'1'+1,在JavaScript中它的运算结果是一样的:  这就是一个最基础关于隐式转换的例子。 然后我们扩展一下,用上文中最常出现的\[\]也就是空数组来替代第一个'1':  在这些运算里,\[\]会被当成空字符串。 有时候,我们还可以将数字转换成十六进制,进而转换成字符串。比如:  211的31进制为6p。 ### 1.3 隐式类型转换-构造数字  在另一些时候我们可以通过隐式类型转换将字符串转换为数字,比如:  不过其中最有名的还是一元运算符+。在JavaScript中,这个运算符专门将object转为数字。 当对象是\[\]时,它会被先转换成空字符串,再被转换成数字,也就是\[\]->""->0:  而在JavaScript中,!0=true,+true=1:  那么我们实际上能够用+-!\[\]表示所有数字。 ### 1.4 \[\]型调用  在JavaScript中,索引(ElementAccess)也可以被当成对象(PropertyAccess)调用。 比如以下两个式子是等价的:  所以,一个超长的调用链可以用一个超长的索引代替,如:  2 分析构造法 ------- 理论充足——现在我们开始分析混淆代码的部分。先直接运行第一部分,可以看到返回的是一个返回值为函数eval的函数:  哇塞,是不是有一点1+1到哥德巴赫猜想的感觉了^ ^?不过没事,我们可以慢慢看。取出第一个小片段(第一个\[\]\[\]):  可以看到返回值是一个函数at。不难想到,由于左侧是一个空数组,这个函数应该是Array.at。这里是由索引构成的对象调用表达式:  再次拆分,可以发现它是由false拆下一个a+true拆下一个t构成的。这里比较长我画个图明晰一点:  可以看到,通过上文中两种构造,我们构建出\["at"\]成功调用了一个函数。 这时候可能有人有疑问:true+false不算重复也才9个字母,怎么能作为混淆用呢? 比如这里一段构造出的constructor:  结合at函数的string和原来的true+false,我们又能构造出所有仅包含"a, c, d, e, f, i, l, n, o, r, s, t, u, v"的函数,比如constructor。 那么,再多呢?由于我们文章的主题不是探讨怎么混淆,而是怎么反混淆——其他字母的具体构造法可以看jsfuck网站自己使用的混淆脚本,关于26个字母的来源都很清楚:  <https://jsfuck.com/jsfuck.js>  有了construtor和26个字母,我们就能构造出一个关键的函数,Function。  它的作用则是动态执行函数,也就是执行传入的code中的内容(它还有一些重载不在我们讨论范围内),这里我们用来获取当前的上下文,也就是window:this。  这里再加上一个调用就能获取this,当然内部换成window也可以。  获取window有什么用呢?自然是进一步获取到window下面的——eval啦。对window调用\['eval'\]即可取得eval:  这下执行任意代码的eval也拿到了,执行任意代码用的26个字母也拿到了,RCE自然也是囊中之物。 3 使用AST逆向还原代码 ------------- 讲了两千多字终于讲到正题- -。不过正所谓知其然而知其所以然,要讲就要一次讲明白。 当然,AST的原理这里略过,有想了解的读者可以自行搜索一下。 ### 3.1 先上效果图 闲言少叙,先上效果图:  这里使用我的工具ClarityJS可以一键还原: <https://github.com/AugustineFulgur/ClarityJS> ### 3.2 还原思路 在上面我们已经分析了JSFuck的混淆手法——利用索引调用函数,利用函数构造eval;利用函数的隐式类型转换构造字母和特殊字符,进而构造语句。 而反混淆的最简单方式就是将所有\[常量节点\]运算出来,比如说将!!\[\]置为True,将!\[\]置为false,然后进一步处理所有相加、索引。 然后,处理一些常见的property函数比如toString。 然后将索引型调用简化为直接调用。 通俗来说,就是这样: `function func(p){ if(recursive is_constant(p.node)){ //递归判断这个节点下方的所有节点是不是常量 p.node.value=evaluation(p.node); //对节点求值 } }` 所以我们需要写两个函数,一个用于递归判断当前节点是否是一个常量表达式的节点,一个用于将常量表达式求值的节点。 ### 3.3 判断常量 1-消去一元、二元、属性表达式 现在我们来写判断节点是否是常量的函数。 首先,AST不是那么“通情达理”的表达式,不会自动处理这些纷杂的\[\]和!,我们需要详细判断所有可能用到的节点,所以,我们要先梳理一下混淆代码中用到了哪些节点: - • +/!:一元表达式,也就是UnaryExpression - • +:二元表达式,这里主要用到的就是+ - • \*\[\]:属性(?),MemberExpression,在前方是数组时求值,在前方是object时简化为PropertyExpression(这个这篇文章不讨论) 同时,为避免递归函数无限循环,我们需要给函数设置一个最大递归深度。 最后,我们需要对判断单个值是否为常量。 初步来看是这些,那么码代码: `function is_constant(n,dept=0){ //二元 if(dept>=maxdept) return false; if(tps.isBinaryExpression(n)){ return is_constant(n.left,dept+1) && is_constant(n.right,dept+1); } //一元 else if(tps.isUnaryExpression(n)){ return is_constant(n.argument,dept+1); } //数组 else if(tps.isMemberExpression(n) && n.computed){ return is_constant(n.object,dept+1) && is_constant(n.property,dept+1); } //数组:常量数组、空数组处理 else if((tps.isArrayExpression(n))){ return n.elements.every(e=>is_constant(e,dept+1)); } //纯值判断 else if(tps.isNumericLiteral(n) || tps.isStringLiteral(n) || tps.isBooleanLiteral(n)){ return !dept==0; //跳过本来就是纯值的部分,省去不必要的执行 } else{ return false; } }` ### 3.4 求值 1-简单粗暴Eval一下 很遗憾的是,AST也并未给我们一个完整安全的求值方法,还是需要自己判断。当然,如果我们使用万能的eval大法也是可以的: `if(is_constant(p.node)) eval(generator.default(p.node).code);` 而如果要安全行事,就得采用和上文中is\_constant一样的if-else大分支,太长了这里先不写- -(这个模块在ClarityJS里叫【unsafe】constclear,后续会完善出安全的版本)。 ### 3.5 判断常量 2-消去CallExpression和NaN 验证一下可行性,进行第一次求值: `[].at.constructor("return e" + 31["to" + "".constructor["na" + (0 .constructor + [])["11"] + "e"]]("32") + "a" + "l")()("alert(1)" + "".fontcolor(NaN + "".fontcolor()["12"])["21"] + "c" + "o" + "n" + "s" + "o" + "l" + "e" + "." + "l" + "o" + ("false0" + "".constructor)["20"] + "(" + [1] + ")" + "".fontcolor(NaN + "".fontcolor()["12"])["21"]);` 可以看到已经简化了不少,但还有很明显的一部分未处理,比如说0.constructor这类属性(成员)函数。所以下一步我们需要简化形参为常数的成员函数。 还有一个我们之前没有注意到的NaN,它不属于Boolean、String或Number,而是Identifier(**怎么会有语言同时拥有undefined、null和NaN?哇塞**)。 按照上文思路,继续添加两个分支: `//对常见常量函数的处理 else if(tps.isCallExpression(n) && tps.isMemberExpression(n.callee)){ return is_constant(n.callee.object,dept+1) && tps.isIdentifier(n.callee.property) && n.arguments.every(e=>is_constant(e,dept+1)); } else if(tps.isIdentifier(n)){ return n.name==='NaN'; }` ### 3.6 判断常量 3-消去常量属性 再次执行,可以看见NaN和有参函数fontcolor已经被消去,但还存在一个\*.constructor: `[].at.constructor("return e" + 31["to" + "".constructor["na" + (0 .constructor + [])["11"] + "e"]]("32") + "a" + "l")()("alert(1);console.lo" + ("false0" + "".constructor)["20"] + "(" + [1] + ")" + ";");` 这是因为\*.prop属于属性(和\*\[index\]同样属于MemberExpression),而\*.func()属于函数^ ^。下图中可以直观看到,左值被判定成CallExpression右值则是PropertyAccessExpression(我这里用的是ts的解释器,在es6里就是MemberExpression):  这两个处理是不一样的。所以我们需要扩充上文中isMemberExpression分支,增加computed==false也就是点型调用的处理。 `else if(tps.isMemberExpression(n)){ return is_constant(n.object,dept+1) && (n.computed ? is_constant(n.property,dept+1) : tps.isIdentifier(n.property)); }` 最后再执行一次,完美:  4 最后 ---- AST是个很好的技术,不仅仅应用于反混淆领域,也在SAST和漏洞挖掘领域大放光彩。 看在我写了快四千个字  的份上——先给我的工具点个STAR(还不快点^ ^),后续我会写更多关于这项技术的内容。
发表于 2025-09-19 09:00:00
阅读 ( 459 )
分类:
其他
2 推荐
收藏
0 条评论
请先
登录
后评论
阿斯特
公众号:重生之成为赛博女保安
11 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!