// 离线 instrument 沙箱 v2: 全容错 Proxy 桩, 让 kwpsec(kws)+kwf 的 Jimbei VM 跑到底。 // 记录它读了哪些指纹 / 监听了哪些事件 / 采了什么触摸保真 / 有没有自动化检测。 // 决定性: 真手指相对 adb 是否存在不可伪造信号。 // 有 force/pressure/radius/coalesced/精确时序 → 行为墙 → 人工路径 // 只可合成轨迹 + 真机已真指纹 → 真手指无优势 → 号码信誉墙 → 换号 const fs = require("fs"), vm = require("vm"), path = require("path"); const ROOT = path.join(__dirname, ".."); const H5 = path.join(ROOT, "out", "h5_security_js"); const KWS = fs.readFileSync(path.join(H5, "kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js"), "utf-8"); const KWF = fs.readFileSync(path.join(H5, "kwf-0.0.2.2cee19b4b7dec496.js"), "utf-8"); const ctx = vm.createContext({ console, setTimeout, clearTimeout, setImmediate, setInterval, clearInterval, queueMicrotask, // 注意: 不注入 Buffer/process (Node 全局) —— kwpsec 会探测它们判定 Node 环境 (自动化), 真浏览器没有。 btoa: (s) => Buffer.from(s, "binary").toString("base64"), atob: (s) => Buffer.from(s, "base64").toString("binary"), }); vm.runInContext(` globalThis.__reads = {}; globalThis.__events = []; globalThis.__canvas = []; globalThis.__audio = []; globalThis.__errs = []; var __win; // window 自指 // 全容错日志 Proxy: 任何属性都不返回 undefined (缺的返回可调用代理), 永不崩。 // 自动化/Node 环境标记黑名单: 真浏览器/WebView 里全是 undefined。强制返回 undefined (否则代理返回 truthy → 被误判自动化)。 var MARKERS = new Set(["_phantom","callPhantom","__nightmare","phantom","_selenium","callSelenium","_Selenium_IDE_Recorder","selenium","domAutomation","domAutomationController","Buffer","process","fbejkbakrbadskfe","kwscb","webdriver","__webdriver_evaluate","__webdriver_script_function","__webdriver_script_func","__webdriver_script_fn","__webdriver_unwrapped","__selenium_evaluate","__selenium_unwrapped","__fxdriver_evaluate","__fxdriver_unwrapped","__driver_evaluate","__driver_unwrapped","spawn","_WEBDRIVER_ELEM_CACHE","ChromeDriverw","require","module","__core-js_shared__","awesomplete","callPhantom"]); // 全容错日志 Proxy。callable=true 时代理本身是函数 (target=noop), 这样未知方法 .apply/.call/() 不崩。 // 容器(navigator/document/window)用 callable=false (typeof object, 准确)。 function mkTotal(name, real, strict, callable){ real = real || {}; var target = callable ? function(){} : {}; function sub(n){ return mkTotal(n, {}, false, true); } // 未知子值一律=可调用代理 (永远不崩) return new Proxy(target, { get: function(t,k){ if (typeof k === "symbol") return undefined; if (k === "then" || k === "toJSON") return undefined; var key = String(k); if (__win && (key==="window"||key==="self"||key==="globalThis"||key==="top"||key==="parent"||key==="frames")) return __win; var lk = name+"."+key; __reads[lk]=(__reads[lk]||0)+1; if (key in real && real[key] !== undefined){ var v = real[key]; if (typeof v === "function") return v.bind(real); if (typeof v === "object" && v !== null) return v; return v; } // 内置全局 (Array/Object/Function/encodeURIComponent...) 真返回 if (key!=="window"&&key!=="self"&&key!=="globalThis"&&typeof globalThis[key]!=="undefined"){ return globalThis[key]; } // 自动化/Node 标记: 真浏览器里 undefined, 强制返回 undefined (否则 truthy 代理被误判自动化) if (MARKERS.has(key)){ return undefined; } if (strict){ return undefined; } // window 精确模式保留 return sub(lk); }, apply: callable ? function(t,thisArg,args){ var k=name+"()"; __reads[k]=(__reads[k]||0)+1; return sub(k); } : undefined, construct: callable ? function(){ return {}; } : undefined, has: function(){ return true; }, set: function(){ return true; }, getOwnPropertyDescriptor: function(t,k){ if(k in real) return Object.getOwnPropertyDescriptor(real,k); return {configurable:true,enumerable:false,value:undefined}; }, ownKeys: function(){ return Object.keys(real); } }); } // ---- 真实 canvas/webgl 实现 (关键信号要真跑) ---- function mkCanvasReal(){ return { width:300, height:150, style:{}, getContext: function(type){ __canvas.push("getContext:"+(type||"?")); var ctx2d = { fillRect:function(){}, clearRect:function(){}, strokeRect:function(){}, fillText:function(t){ __canvas.push("2d.fillText:"+(t||"").slice(0,8)); }, strokeText:function(){ __canvas.push("2d.strokeText"); }, measureText:function(s){ __canvas.push("2d.measureText"); return { width:(s?String(s).length:0)*7, actualBoundingBoxAscent:8, actualBoundingBoxDescent:2 }; }, getImageData:function(x,y,w,h){ __canvas.push("2d.getImageData"); return { width:w, height:h, data: new Uint8ClampedArray((w||1)*(h||1)*4) }; }, createImageData:function(w,h){ return { width:w, height:h, data: new Uint8ClampedArray((w||1)*(h||1)*4) }; }, putImageData:function(){}, beginPath:function(){}, closePath:function(){}, moveTo:function(){}, lineTo:function(){}, arc:function(){}, rect:function(){}, fill:function(){}, stroke:function(){}, save:function(){}, restore:function(){}, translate:function(){}, rotate:function(){}, scale:function(){}, setTransform:function(){}, transform:function(){}, drawImage:function(){}, clip:function(){}, arcTo:function(){}, quadraticCurveTo:function(){}, bezierCurveTo:function(){}, isPointInPath:function(){return false;}, createLinearGradient:function(){return {addColorStop:function(){}};}, createRadialGradient:function(){return {addColorStop:function(){}};}, fillStyle:"#000", strokeStyle:"#000", font:"16px Arial", textBaseline:"alphabetic", textAlign:"start", globalAlpha:1, lineWidth:1, lineCap:"butt", lineJoin:"miter", shadowBlur:0, shadowColor:"rgba(0,0,0,0)", shadowOffsetX:0, shadowOffsetY:0, }; var webgl = { getParameter:function(p){ __canvas.push("webgl.getParameter:"+p); return {"37445":"Qualcomm","37446":"Adreno (TM) 740","7936":"WebKit WebGL","7937":"WebKit WebGL","34921":16384,"33902":16384,"33901":16384,"35724":"WebGL GLSL ES 1.00 (OpenGL ES)"}[p] || "WebKit WebGL"; }, getExtension:function(n){ __canvas.push("webgl.getExtension:"+n); return n==="WEBGL_debug_renderer_info"?{UNMASKED_VENDOR_WEBGL:37445,UNMASKED_RENDERER_WEBGL:37446}:{}; }, getSupportedExtensions:function(){ return ["EXT_blend_minmax","ANGLE_instanced_arrays","WEBGL_debug_renderer_info","OES_texture_float"]; }, getShaderPrecisionFormat:function(){ return {rangeMin:127,rangeMax:127,precision:23}; }, createBuffer:function(){return{};},bindBuffer:function(){},bufferData:function(){},createShader:function(){return{};},shaderSource:function(){},compileShader:function(){},createProgram:function(){return{};},attachShader:function(){},linkProgram:function(){},useProgram:function(){},enableVertexAttribArray:function(){},vertexAttribPointer:function(){},drawArrays:function(){}, drawingBufferWidth:300, drawingBufferHeight:150, UNMASKED_VENDOR_WEBGL:37445, UNMASKED_RENDERER_WEBGL:37446, }; return mkTotal("canvas.ctx("+(type||"")+")", type==="webgl"||type==="experimental-webgl" ? webgl : ctx2d); }, toDataURL: function(type){ __canvas.push("toDataURL:"+(type||"png")); return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg=="; }, toBlob: function(cb){ __canvas.push("toBlob"); if(cb) setTimeout(function(){cb({size:100});},0); }, addEventListener: function(t){ __events.push("canvas:"+t); }, getBoundingClientRect: function(){ return {left:0,top:0,right:300,bottom:150,width:300,height:150,x:0,y:0}; }, captureStream: function(){ return { getTracks:function(){return [];} }; }, }; } // ---- 真实 audio 实现 ---- function mkAudioReal(label){ var dest={connect:function(){return null;},disconnect:function(){}}; function node(){ return { connect:function(){return dest;}, disconnect:function(){}, frequency:{value:440}, type:"sine", value:1, start:function(){}, stop:function(){}, gain:{value:1}, threshold:-24, knee:30, ratio:12, attack:0.003, release:0.25, reduction:0 }; } return { sampleRate:44100, currentTime:0, destination:dest, state:"running", listener:{}, createOscillator:function(){ __audio.push(label+":createOscillator"); return node(); }, createAnalyser:function(){ __audio.push(label+":createAnalyser"); return node(); }, createDynamicsCompressor:function(){ __audio.push(label+":createDynamicsCompressor"); return node(); }, createGain:function(){ __audio.push(label+":createGain"); return node(); }, createBiquadFilter:function(){ return node(); }, createScriptProcessor:function(){ return node(); }, createBuffer:function(ch,len,sr){ return { getChannelData:function(){ return new Float32Array(len); }, length:len, numberOfChannels:ch, sampleRate:sr }; }, createBufferSource:function(){ var n=node(); n.buffer=null; return n; }, decodeAudioData:function(b,ok){ if(ok) ok({getChannelData:function(){return new Float32Array(100);}}); }, startRendering:function(){ __audio.push(label+":startRendering"); return Promise.resolve({ getChannelData:function(){ return new Float32Array(100); }, length:100 }); }, close:function(){ return Promise.resolve(); }, resume:function(){ return Promise.resolve(); } }; } // ---- navigator / screen / document / window ---- var nav = mkTotal("navigator", { userAgent:"Mozilla/5.0 (Linux; Android 13; PJZ110) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/114.0.0.0 Mobile Safari/537.36", appVersion:"5.0 (Linux; Android 13; PJZ110)", appName:"Netscape", appCodeName:"Mozilla", platform:"Linux armv8l", oscpu:"Linux armv8l", product:"Gecko", productSub:"20030107", vendor:"Google Inc.", vendorSub:"", language:"zh-CN", languages:["zh-CN","en-US"], cookieEnabled:true, doNotTrack:null, onLine:true, webdriver:false, hardwareConcurrency:8, deviceMemory:8, maxTouchPoints:5, plugins:{length:0}, mimeTypes:{length:0}, javaEnabled:function(){return false;}, connection:{effectiveType:"4g",rtt:50,downlink:10,saveData:false}, permissions:{query:function(){return Promise.resolve({state:"prompt"});}}, mediaDevices:{enumerateDevices:function(){return Promise.resolve([]);}}, userAgentData:{mobile:true,brands:[{brand:"Chromium",version:"114"}]}, geolocation:{getCurrentPosition:function(){},watchPosition:function(){}}, storage:{estimate:function(){return Promise.resolve({quota:1e9,usage:1e6});}}, sendBeacon:function(){return true;} }); globalThis.navigator = nav; globalThis.screen = mkTotal("screen", { width:1080, height:2376, availWidth:1080, availHeight:2256, availLeft:0, availTop:0, colorDepth:24, pixelDepth:24, orientation:{type:"portrait-primary",angle:0} }); var docEl={style:{},clientWidth:1080,clientHeight:2256,getBoundingClientRect:function(){return {left:0,top:0,width:1080,height:2256};},addEventListener:function(t){__events.push("docEl:"+t);}}; var bodyEl={style:{},clientWidth:1080,clientHeight:2256,appendChild:function(){},addEventListener:function(t){__events.push("body:"+t);}}; var headEl={appendChild:function(){},getElementsByTagName:function(){return [];}}; var doc = mkTotal("document", { nodeType:9, documentElement:docEl, body:bodyEl, head:headEl, cookie:"", referrer:"https://app.m.kuaishou.com/", URL:"https://app.m.kuaishou.com/verify/captcha.html", domain:"app.m.kuaishou.com", title:"安全验证", readyState:"complete", visibilityState:"visible", hidden:false, hasFocus:function(){return true;}, createElement:function(tag){ if(String(tag).toLowerCase()==="canvas") return mkTotal("canvas", mkCanvasReal()); return mkTotal("el("+tag+")", { tagName:String(tag).toUpperCase(), style:{}, setAttribute:function(){}, getAttribute:function(){return null;}, appendChild:function(c){return c;}, addEventListener:function(t){__events.push("el("+tag+"):"+t);}, getBoundingClientRect:function(){return {left:0,top:0,width:100,height:20};}, width:0, height:0, innerHTML:"", textContent:"" }); }, createElementNS:function(ns,tag){ return this.createElement(tag); }, createTextNode:function(t){return {nodeValue:t};}, getElementsByTagName:function(t){ return t==="html"?[docEl]:t==="body"?[bodyEl]:t==="head"?[headEl]:[]; }, getElementById:function(){return null;}, querySelector:function(){return null;}, querySelectorAll:function(){return [];}, addEventListener:function(type,fn){ __events.push("document:"+type); if(type==="DOMContentLoaded"||type==="load"||type==="readystatechange"){ try{fn&&fn();}catch(e){__errs.push("docEvh:"+e.message);} } }, removeEventListener:function(){}, dispatchEvent:function(){return true;}, fonts:{ready:Promise.resolve(),check:function(){return true;},load:function(){return Promise.resolve([]);}}, createEvent:function(){return {initEvent:function(){}};}, queryCommandSupported:function(){return false;}, adoptNode:function(n){return n;}, importNode:function(n){return n;} }); globalThis.document = doc; globalThis.AudioContext=function(){ return mkTotal("AudioContext", mkAudioReal("AC")); }; globalThis.webkitAudioContext=globalThis.AudioContext; globalThis.OfflineAudioContext=function(){ return mkTotal("OfflineAudioContext", mkAudioReal("OAC")); }; globalThis.webkitOfflineAudioContext=globalThis.OfflineAudioContext; globalThis.MessageChannel=function(){ this.port1={postMessage:function(){},onmessage:null,close:function(){}}; this.port2=this.port1; }; globalThis.Worker=function(){ this.postMessage=function(){}; this.terminate=function(){}; }; globalThis.Blob=function(a,o){ this.type=(o&&o.type)||""; this.size=10; this.arrayBuffer=function(){return Promise.resolve(new ArrayBuffer(10));}; }; globalThis.URL=createURL(); function createURL(){ return {createObjectURL:function(){return "blob:x";},revokeObjectURL:function(){}}; } // window 级属性: 用 mkTotal 包一个真 backing, 再绑定到 globalThis var winBacking = { devicePixelRatio:3, innerWidth:1080, innerHeight:2256, outerWidth:1080, outerHeight:2376, screenX:0, screenY:0, scrollX:0, scrollY:0, pageXOffset:0, pageYOffset:0, localStorage:{getItem:function(){return null;},setItem:function(){},removeItem:function(){}}, sessionStorage:{getItem:function(){return null;},setItem:function(){}}, indexedDB:{}, name:"", status:"", closed:false, ontouchstart:null, ondevicemotion:null, ondeviceorientation:null, DeviceMotionEvent:function(){}, DeviceOrientationEvent:function(){}, addEventListener:function(type,fn){ __events.push("window:"+type); if(type==="load"||type==="DOMContentLoaded"){ try{fn&&fn();}catch(e){__errs.push("winEvh:"+e.message);} } }, removeEventListener:function(){}, postMessage:function(){}, WebSocket:function(){ this.send=function(){}; this.close=function(){}; }, XMLHttpRequest:function(){ this.open=function(){}; this.send=function(){}; this.setRequestHeader=function(){}; }, fetch:function(){ return Promise.resolve({json:function(){return Promise.resolve({});},text:function(){return Promise.resolve("");},arrayBuffer:function(){return Promise.resolve(new ArrayBuffer(8));}}); }, requestAnimationFrame:function(cb){ return 1; }, cancelAnimationFrame:function(){}, history:{length:1,pushState:function(){},replaceState:function(){}}, location:{href:"https://app.m.kuaishou.com/verify/captcha.html?key=-123&type=7",protocol:"https:",host:"app.m.kuaishou.com",hostname:"app.m.kuaishou.com",pathname:"/verify/captcha.html",search:"?key=-123&type=7",hash:"",origin:"https://app.m.kuaishou.com"}, crypto:{getRandomValues:function(b){for(var i=0;i { const reads = ctx.__reads, events = ctx.__events, canvas = ctx.__canvas, audio = ctx.__audio; const FIDELITY = ["force","pressure","radiusX","radiusY","webkitForce","mozPressure","tiltX","tiltY","coalesced","getCoalescedEvents","predicted","twist","tangentialPressure","width","height"]; const fidHit = []; for (const f of FIDELITY) for (const k in reads) if (k.toLowerCase().endsWith("."+f.toLowerCase()) || k.toLowerCase().includes("."+f.toLowerCase())) fidHit.push(k+"="+reads[k]); const AUTO = ["webdriver","phantom","nightmare","selenium","domAutomation","callPhantom","_phantom","__nightmare","cdc_","driver","headless","puppeteter","spawn","Buffer","process"]; const autoHit = []; for (const a of AUTO) for (const k in reads) if (k.toLowerCase().includes(a.toLowerCase())) autoHit.push(k+"="+reads[k]); const behUniq = [...new Set(events.filter(e=>/mouse|touch|pointer|click|scroll|wheel|key|focus|blur|visibility|devicemotion|orientation|resize|input|drag|transition|copy|paste/i.test(e)))].sort(); console.log("\n================ kwpsec 信号采集面报告 ================"); console.log("\n[A] 行为事件监听 ("+behUniq.length+"): " + (behUniq.join(", ") || "(无)")); console.log("\n[B] 触摸保真字段 (有命中=真手指不可伪造→人工路径): " + (fidHit.join(", ") || "(无)")); console.log("\n[C] 自动化检测读取: " + (autoHit.join(", ") || "(无明文命中)")); console.log("\n[D] Canvas/WebGL 探针 ("+canvas.length+"): " + ([...new Set(canvas)].slice(0,40).join(", ") || "(无)")); console.log("\n[E] Audio 探针 ("+audio.length+"): " + ([...new Set(audio)].slice(0,20).join(", ") || "(无)")); console.log("\n[F] 全部属性探针 (top 60 by 次数):"); console.log(Object.entries(reads).sort((a,b)=>b[1]-a[1]).slice(0,60).map(([k,v])=>" "+k+" ×"+v).join("\n")); console.log("\n[G] 全部事件 (unique): " + ([...new Set(events)].sort().join(", ") || "(无)")); console.log("\n[H] 运行期错误 ("+ctx.__errs.length+"): " + (ctx.__errs.slice(0,12).join(" | ") || "(无)")); fs.writeFileSync(path.join(ROOT,"out","kws_signal_report.json"), JSON.stringify({reads,events:[...new Set(events)],canvas:[...new Set(canvas)],audio:[...new Set(audio)],errs:ctx.__errs},null,2)); console.log("\n[saved] out/kws_signal_report.json"); }, 800);