我们先来看一段代码
function TestCode(){
return parseInt(1),parseFloat(0.3)
}
console.log(TestCode.toString().split("\n"));
运行之后你会发现,打印了一个长度为3位的数组,我来解释一下这个代码的意思,这个就是先申明一个简单的函数,然后将这个函数转为源代码(这个源代码跟你一开始写的这个函数是一样的,你压缩了转换之后也是压缩的,不是压缩的转换之后也不是压缩的),并以换行符进行分割
[
'function TestCode(){\r',
' return parseInt(1),parseFloat(0.3)\r',
'}'
]
我们再来看看压缩的代码运行的结果
function TestCode(){return parseInt(1),parseFloat(0.3)};
console.log(TestCode.toString().split("\n"));
结果
[ 'function TestCode(){return parseInt(1),parseFloat(0.3)}' ]
返回的是一个长度为1的数组
举了两个例子,我们现在进入正题
从上面的两个例子中我们不难发现格式化的代码和不格式化的代码的区别就是多了换行符,而格式化检测的原理便是通过换行符作为分割看看分割之后这个数组的长度是多少进而判断是否为格式化的代码
以下是一个简单的demo用于检测是否格式化了代码
function TestCode(){return parseInt(1),parseFloat(0.3)};
function TestCode_format() {
return parseInt(1), parseFloat(0.3)
}
function isJsFormat(Code) {
return Code.toString().split("\n").length > 2;
}
console.log("NoFormat=====>",isJsFormat(TestCode))
console.log("Format=====>",isJsFormat(TestCode_format))
运行代码的结果
NoFormat=====> false
Format=====> true
既然我们以及知己知彼了(了解原理了),那我们就能想到对坑格式化检测的思路,也就是通过hook split方法
hook split代码
(function() {
// 保存原始的 split 方法
const originalSplit = String.prototype.split;
// 重写 split 方法
String.prototype.split = function(separator, limit) {
// 检查分隔符是否为 "\n"
if (separator === "\n") {
return [1]
}
// 调用原始 split 方法并返回结果
return originalSplit.apply(this, arguments);
};
})();
将此代码插入源代码的最前面
(function() {
// 保存原始的 split 方法
const originalSplit = String.prototype.split;
// 重写 split 方法
String.prototype.split = function(separator, limit) {
// 检查分隔符是否为 "\n"
if (separator === "\n") {
return [1]
}
// 调用原始 split 方法并返回结果
return originalSplit.apply(this, arguments);
};
})();
function TestCode(){return parseInt(1),parseFloat(0.3)};
function TestCode_format() {
return parseInt(1), parseFloat(0.3)
}
function isJsFormat(Code) {
return Code.toString().split("\n").length > 2;
}
console.log("NoFormat=====>",isJsFormat(TestCode))
console.log("Format=====>",isJsFormat(TestCode_format))
运行的结果
NoFormat=====> false
Format=====> false
都为false,成功绕过.