Reflect.getPrototypeOf是探测混淆原型链的基础工具,需结合递归遍历、特征识别与上下文分析;它比直接访问__proto__更安全可靠,可避免getter触发、兼容冻结对象,并对非对象输入返回undefined。

Reflect.getPrototypeOf 本身不能“自动化检测”高度混淆的原型链,但它是一个关键基础工具——配合递归遍历、特征识别和上下文分析,才能实现对异常原型链结构的有效探测。
理解混淆原型链的常见手法
高度混淆的代码常通过以下方式破坏原型链可读性:
- 动态重写
__proto__或prototype属性,插入伪造对象或代理(Proxy) - 用
Object.setPrototypeOf()在运行时反复篡改实例原型 - 返回非标准对象(如
Object.create(null))切断默认继承 - 在原型上定义 getter/setter 隐藏真实原型引用,或抛出错误干扰探测
用 Reflect.getPrototypeOf 构建安全的原型遍历器
相比直接访问 obj.__proto__,Reflect.getPrototypeOf(obj) 更可靠:它不触发 getter,对冻结/不可扩展对象行为一致,且对非对象输入返回 undefined 而非报错。
一个健壮的遍历函数示例:
function tracePrototypeChain(obj, maxDepth = 20) {
const chain = [];
let current = obj;
let depth = 0;
while (current !== null && depth < maxDepth) {
const proto = Reflect.getPrototypeOf(current);
if (proto === undefined || proto === null) break;
chain.push(proto);
current = proto;
depth++;
}
return chain;
}
该函数能稳定捕获原型路径,避免因 getter 侧信道或属性劫持导致的误跳转或崩溃。
识别异常模式的关键检查点
仅获取原型链不够,需结合以下逻辑判断是否被混淆:
- 重复原型对象:同一构造函数原型多次出现在链中(可能被循环注入)
-
缺失内置原型:链中未出现
Object.prototype或Function.prototype(如从Object.create(null)开始) -
非函数构造器:某个原型对象没有
constructor属性,或其值不是函数 -
原型对象自身被篡改:检查
proto.toString === Object.prototype.toString是否成立,防伪造 toString
结合其他 API 提升检测鲁棒性
单靠 Reflect.getPrototypeOf 有局限,建议组合使用:
- 用
Object.getOwnPropertyNames(proto)检查原型上是否存在可疑属性(如_obfuscated,$$hook) - 用
Object.isExtensible(proto)和Object.isFrozen(proto)判断是否被刻意锁定 - 对疑似 Proxy 对象,尝试
Proxy.revocable检测或检查typeof proto === 'object' && !proto.constructor - 对比
obj.constructor.prototype与Reflect.getPrototypeOf(obj)是否一致,不一致即存在显式篡改
不复杂但容易忽略:混淆者常只改实例原型,不碰构造器,因此跨维度比对才是发现异常的核心。

















