STM32低功耗模式怎么选?一张图看懂STOP0/1/2区别,附CubeIDE配置实例(STM32L4系列)
2026/5/12 15:40:21
khbox 的项目已放gitee, https://gitee.com/sugarysp/khbox_pro ,欢迎各位大佬使用测试。
目前完成的有
待做:
浏览器中的 DOM 对象有着复杂的继承关系:
Document → Node → EventTarget → Object Navigator → Object Window → EventTarget → Object检测手段:
// 网站检测代码Object.getPrototypeOf(Document.prototype).constructor.name==='Node'// 必须为 true'addEventListener'inEventTarget.prototype// 必须为 true真实浏览器的原生方法调用toString()会返回[native code]:
// 真实浏览器navigator.javaEnabled.toString()// "function javaEnabled() { [native code] }"// 普通 JS 实现functionjavaEnabled(){returnfalse;}javaEnabled.toString()// "function javaEnabled() { return false; }" ❌ 暴露了浏览器原生方法强制检查this的合法性:
// 真实浏览器constuaGetter=Object.getOwnPropertyDescriptor(Navigator.prototype,'userAgent').get;uaGetter.call(window);// TypeError: Illegal invocation// 普通 JS 实现functionget_userAgent(){returnthis._ua;}get_userAgent.call(window);// 可以执行 ❌ 行为不一致KhBox 通过在 sandbox 中暴露构造函数,结合 JSDOM 的原型链实现正确的继承关系:
// main.js - 构建 sandboxconstsandbox={// 暴露实例(经过 KhBox Proxy 包装)document:proxyDocument,navigator:proxyNavigator,window:proxyWindow,// 暴露构造函数(直接引用 JSDOM 的)Document:dom.window.Document,Navigator:dom.window.Navigator,Window:dom.window.Window,Node:dom.window.Node,EventTarget:dom.window.EventTarget,// ...};// 测试原型链Document.prototype.constructor.name// "Document"Object.getPrototypeOf(Document.prototype).constructor.name// "Node"Object.getPrototypeOf(Node.prototype).constructor.name// "EventTarget"// 测试属性定义位置'cookie'inDocument.prototype// true'addEventListener'inEventTarget.prototype// true利用 V8 的Private Symbol机制,为函数对象存储自定义的 toString 返回值:
// native_protection.ccLocal<Function>CreateNativeWrapper(...){// 创建原生函数包装器Local<FunctionTemplate>tpl=FunctionTemplate::New(isolate,callback);Local<Function>nativeFunc=tpl->GetFunction(context).ToLocalChecked();// 生成 [native code] 字符串std::string native_code;if(strcmp(method_type,"get")==0){native_code="function get "+name+"() { [native code] }";}else{native_code="function "+name+"() { [native code] }";}// 🔥 关键:用 Private Symbol 存储nativeFunc->SetPrivate(context,GetNativeStringSymbol(isolate),String::NewFromUtf8(isolate,native_code.c_str()).ToLocalChecked());returnnativeFunc;}Object.keys()无法获取Function.prototype.toString会优先读取此 Symbolnavigator.javaEnabled.toString()// "function javaEnabled() { [native code] }" ✅String(navigator.javaEnabled)// "function javaEnabled() { [native code] }" ✅当调用浏览器原生方法时,如果this不是预期的对象类型,会抛出TypeError: Illegal invocation:
// 合法调用navigator.userAgent// ✅// 非法调用constuaGetter=Object.getOwnPropertyDescriptor(Navigator.prototype,'userAgent').get;uaGetter.call(window)// ❌ TypeError: Illegal invocationKhBox 通过三层检查机制实现 Illegal Invocation 保护:
// toolFuncs.jslazyLoader:function(receiver,target,prop,classNameFromC){// ...// 🔥 焊死到 Constructor.prototype 而不是实例上constwindow=khBox.memory.jsdom.window;constprotoTarget=window[protoOwner]?.prototype||receiver;return{impl:khBox.envFuncs[implKey],target:protoTarget,// Navigator.prototypeclassName:protoOwner,// "Navigator"// ...};}为什么要焊死到 Prototype?
// 如果焊死到实例上:navigator.userAgent// ✅ 可以访问Navigator.prototype.userAgent// ❌ 拿不到我们的 wrapper// 焊死到 Prototype 上:navigator.userAgent// ✅ 继承自 prototypeNavigator.prototype.userAgent// ✅ 直接获取到我们的 wrapperObject.getOwnPropertyDescriptor(Navigator.prototype,'userAgent').get// ✅ 受保护使用 JSON 配置中的类名而不是 JSDOM 的constructor.name,因为jsdom某些可能不够全,优先用自己脱下来的环境:
// watcher.cc - Watch 函数voidWatch(constv8::FunctionCallbackInfo<Value>&args){// 优先使用传入的 className(来自 JSON 配置)constchar*class_name=nullptr;if(args.Length()>=2&&args[1]->IsString()){String::Utf8Valuecn(isolate,args[1]);class_name_str=*cn;class_name=class_name_str.c_str();}// 存储到 Proxy 的 InternalFieldLocal<Object>proxy=CreateWatcherProxy(isolate,target,source_path,class_name);// ...}// main.js - 调用时明确指定类名constproxyNavigator=addon.watch(navigator,'Navigator');constproxyWindow=addon.watch(window,'Window');降级策略:
// toolFuncs.jsconstclassName=classNameFromC// 优先:JSON 配置||target[Symbol.toStringTag]// 降级 1||target.constructor?.name// 降级 2:JSDOM||"Unknown";完整的测试代码位于khbox_vm/pages/demo_proto/input.js:
// Part 1: 原型链测试console.log('Document.prototype.constructor.name:',Document.prototype.constructor.name);console.log('Document 的父类:',Object.getPrototypeOf(Document.prototype).constructor.name);// Part 2: toString 保护console.log(navigator.javaEnabled.toString());// "function javaEnabled() { [native code] }"// Part 3: Illegal InvocationconstuaGetter=Object.getOwnPropertyDescriptor(Navigator.prototype,'userAgent').get;// 正常调用console.log(navigator.userAgent);// ✅ 成功// 非法调用uaGetter.call(window);// ❌ TypeError: Illegal invocation$nodemain.js## Part 1: 原型链继承测试✅ Document.prototype.constructor.name: Document ✅ Document.prototype 的父类: Node ✅ Node.prototype 的父类: EventTarget## Part 2: toString 保护机制测试✅ navigator.javaEnabled.toString():functionjavaEnabled(){[native code]}## Part 3: Illegal Invocation 保护测试---3.1正常调用 --- ✅ navigator.userAgent: Mozilla/5.0(Windows NT10.0;Win64;x64)... ✅ navigator.javaEnabled():false---3.2非法调用 ---[Illegal Invocation Check]Expected:'Navigator', Actual:'Window'✅ 抛出 Illegal Invocation: Illegal invocationKhBox 框架通过以下机制实现了完整的浏览器行为模拟:
prototype链关系Function.prototype.toString返回[native code]Constructor.prototype而不是实例this的类型TypeError: Illegal invocation更多文章,敬请关注gzh:零基础爬虫第一天天