“今天来学习下怎么将简单的CallExpression 类型进行处理。”
昨天写了这篇文章 JavaScript 代码混淆实战(二):将 BinaryExpression 类型转换为 CallExpression 类型,今天来看看它的逆过程。
如何将下面的代码:
-
var Xor = function (p,q)
-
{
-
return p ^ q;
-
}
-
-
-
let a = Xor(111,222);
转变成下面的:
-
var Xor = function (p,q)
-
{
-
return p ^ q;
-
}
-
-
-
let a = 111 ^ 222;
01
—
分析及思路
分析:上面的转变其实就是将 Xor(111,222) 变成 111 ^ 222。
Xor 函数以 var 的方式定义,因此这里最好遍历 VariableDeclarator 类型,可以同时获取函数名和函数体。
这个函数体很简单,只有一个 return 语句。
功能只是对两个参数进行异或运算。
思路:
遍历 VariableDeclarator 路径,对参数、函数体之间的关系进行判断。
遍历 函数 所在的作用域,函数名相同替换即可。
02
—
实战
一.插件编写,遍历 VariableDeclarator, 判断其 init 节点:
二.功能编写:
-
function call2express(path)
-
{
-
}
函数名获取:
-
const {init,id} = path.node;
-
const name = id.name;
-
获取参数,并判断长度:
-
const params = init.params;
-
if (params.length !== 2) return;
-
let first_arg = params[0].name;
-
let second_arg = params[1].name;
-
判断函数体长度是否为1:
-
const body = init.body;
-
if (!body.body || body.body.length !== 1) return;
-
判断 ReturnStatement 及其 参数类型
-
const t = require("@babel/types");
-
let return_body = body.body[0];
-
let argument = return_body.argument;
-
if (!t.isReturnStatement(return_body) ||
-
!t.isBinaryExpression(argument))
-
{
-
return;
-
}
-
判断函数的参数与 return语句的参数是否一致:
-
let {left,right,operator} = argument;
-
if (!t.isIdentifier(left, {name:first_arg}) ||
-
!t.isIdentifier(right,{name:second_arg}))
-
{
-
return;
-
}
-
函数声明所在的作用域:
let scope = path.scope;
遍历作用域块节点,找出所有 CallExpression 判断成功后替换:
-
traverse(scope.block,{
-
CallExpression:function(_path) {
-
let _node = _path.node;
-
let args = _path.node.arguments;
-
if (args.length === 2 && t.isIdentifier(_node.callee,{name:name}))
-
{
-
_path.replaceWith(t.BinaryExpression(operator, args[0], args[1]))
-
}
-
},
-
})
-
完整代码:
本文旨在告诉小白如何去编写简单的插件,在分析的过程中可以对照在线解析网站,总之,熟能生巧吧。
文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/111771998