不可检测的JavaScript Error对象重写:绕过标准检测机制
不可检测的JavaScript Error对象重写:绕过标准检测机制
嘿,我最近一直在琢磨怎么在JavaScript里悄悄重写Error对象,还不能被常规的检测手段揪出来——说白了就是要修改它的原型或者构造函数,但得藏得足够深,不让普通的检查轻易识破。
我前前后后试了好几种思路:
- 用
Proxy包装原生Error:这应该是目前最靠谱的方向,Proxy能拦截对Error的各种访问操作,比如属性读取、构造调用这些。只要把拦截逻辑写得足够细致,让它在被检测的时候完全复刻原生Error的行为,只有在我们需要的特定场景下才执行自定义逻辑,就很难被发现。 - 尝试用箭头函数替代:但很快就踩坑了——箭头函数没有自己的
prototype属性,而原生Error构造函数的prototype是Error.prototype,这一对比立马就露馅了,所以这个路子基本走不通,除非额外做大量补全工作,性价比实在太低。 - 直接替换成普通函数(比如
Error = function() {}):这种方式太直白了,随便用instanceof或者检查prototype链就能发现异常。就算给这个函数做“伪装”——比如把它的prototype指向原生Error.prototype,同步name、length这些属性,甚至模拟原生Error的参数处理逻辑——还是可能被更深入的检测(比如Object.getOwnPropertyNames对比)发现破绽。
举个简单的Proxy示例,大概是这样的:
const originalError = Error; Error = new Proxy(originalError, { construct(target, args) { // 这里可以插入自定义逻辑,比如偷偷记录错误信息 const error = Reflect.construct(target, args); // 给错误加个不可枚举的自定义标记,避免被遍历发现 Object.defineProperty(error, '_customTrackTag', { value: 'marked', enumerable: false }); return error; }, get(target, prop) { // 确保所有属性读取都和原生表现一致,避免检测 const value = Reflect.get(target, prop); // 原型相关的访问直接返回原生引用,杜绝破绽 if (prop === 'prototype') { return target.prototype; } // 绑定函数上下文,避免调用时出现异常 return typeof value === 'function' ? value.bind(target) : value; } });
这种写法下,不管是用new Error()创建错误,还是检查Error.prototype、Error.name这些属性,表现都和原生几乎完全一致,只有我们插入的自定义逻辑在悄悄运行。
当然,也得提防一些极端检测场景——比如有人会用Function.prototype.toString.call(Error)对比原生函数的源码,这时候可能得额外拦截toString方法,返回原生Error的字符串表示才行。
内容来源于stack exchange
相关产品推荐
相关产品推荐

