JavaScript逆向时一些奇奇怪怪的检测
之前和同事讨论过一些检测,同事说可以记录下来,能帮到新人,于是有了这篇文章。
document.all
这是在浏览器里被特殊处理的一个特性,也就是typeof document.all是undefined, 但却document.all却能取到值。要在Node中实现这个特性,现在有两种方案,一种是Node C++插件,另一种是V8内置函数。一般场景用V8内置函数即可,移植性更高。Node C++插件和系统有关,也和Node版本绑定,移植性差。
要实现这个特性,GPT给出如下答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const v8 = require("v8"); const vm = require("vm");
v8.setFlagsFromString('--allow-natives-syntax');
let undetectable = vm.runInThisContext('%GetUndetectable()');
v8.setFlagsFromString('--no-allow-natives-syntax');
undetectable.aaa = 'bbb'; console.log('typeof undetectable:', typeof undetectable); console.log('undetectable.aaa:', undetectable.aaa); console.log('undetectable instanceof Object:', undetectable instanceof Object);
|
修修改改,即可实现document.all
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const v8 = require("v8"); const vm = require("vm");
v8.setFlagsFromString('--allow-natives-syntax');
let undetectable = vm.runInThisContext('%GetUndetectable()');
v8.setFlagsFromString('--no-allow-natives-syntax');
function HTMLAllCollection() { return undetectable }; Object.defineProperties(HTMLAllCollection.prototype, { [Symbol.toStringTag]: { value: 'HTMLAllCollection', configurable: true } }); undetectable.__proto__ = HTMLAllCollection.prototype; document = {} document.all = new HTMLAllCollection()
length = 3; for (let i = 0; i < length; i++) { document.all[i] = '1'; } debugger; document.all.length = length; console.log(typeof document.all) console.log(document.all) console.log(document.all.length)
|
eval(‘!new function(){eval(“console.log(this);this.a=2”)}().a’)
这个主要用来检测vm2环境,在浏览器和Node里都是false, 在vm2里是true, 测试代码如下
1 2 3 4 5 6 7 8 9 10 11
| const { VM } = require("vm2"); const vm = new VM();
vm.run(` const obj = new function() { eval("console.log(this);this.a=2"); }(); console.log(obj); console.log(obj.a); console.log(!obj.a); `);
|
window[“Object”][“getOwnPropertyNames”](Function.prototype.toString)
这个主要考察严格模式和非严格模式, 正常用以下方法重定义
1 2
| Function.prototype.toString = function toString() {}; console.log(Object.getOwnPropertyNames(Function.prototype.toString));
|
会返回[‘length’, ‘name’, ‘arguments’, ‘caller’, ‘prototype’]
用以下方法重定义
1 2
| Function.prototype.toString = }.toString console.log(Object.getOwnPropertyNames(Function.prototype.toString));
|
则返回 [‘length’, ‘name’]
1 2 3 4 5 6 7 8 9 10 11 12
| let form = document.createElement('form'); form.action = 'https: let input = document.createElement('input'); input.name = 'action'; form.appendChild(input) input = document.createElement('input'); input.name = 'textContent'; input.id = 'password'; form.appendChild(input) console.log(form.action) console.log(form.textContent) console.log(form.password)
|
正常form.action是一个url链接,但这里变成了HTMLInputElement。
参考资料
零点的 JavaScript toString 检测对抗