无法修改SWF文件时,如何让AS3通过ExternalInterface获取伪造的Electron环境User-Agent
我太懂你的处境了——远程拉取的SWF动不了,它靠ExternalInterface读UA判断Electron版本,低于1.5.3就强制弹更新,你改了navigator.userAgent却没生效,还可能没注意到SWF判断版本的核心逻辑细节。下面给你一步步解决的办法:
先理清两个核心问题
- 修改时机不对或浏览器限制:你之前的代码可能在SWF加载后才执行,或者浏览器对navigator的原生属性有防护,导致修改没生效;
- UA格式不符合SWF的判断逻辑:SWF根本不是靠
Electron/xxx识别版本,而是从UA里匹配GameVer(Dev|Stage)?/(\d+\.\d+\.\d+)这个规则,你的伪造UA里必须包含这个字符串,否则还是会触发更新。
具体解决步骤
1. 务必在SWF加载前执行修改代码
把UA伪造的JS代码放在页面最顶部的<script>标签里,或者在SWF的<object>/<embed>标签渲染之前执行——要是SWF已经加载完成再改,它早就读了真实UA,修改就白费了。
2. 用更彻底的方式劫持navigator.userAgent
有些浏览器(比如你用的Basilisk)对navigator的原生属性修改有防护,单纯用Object.defineProperty可能不够,试试用Proxy包装整个navigator对象,确保任何访问userAgent的操作都返回伪造值:
// 伪造符合要求的UA:包含Electron标识+GameVer版本(≥1.5.3) const fakeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Electron/9.0.0 GameVer/1.5.3"; // 用Proxy包装navigator,拦截所有属性访问 window.navigator = new Proxy(window.navigator, { get(target, prop) { if (prop === 'userAgent') { return fakeUA; } // 其他属性正常返回原生值,不影响其他功能 return target[prop]; } }); // 双重保险:再用Object.defineProperty重写userAgent的getter Object.defineProperty(window.navigator, 'userAgent', { get: () => fakeUA, configurable: true, enumerable: true }); // 额外防护:防止Flash直接调用window.navigator.userAgent.toString const originalToString = String.prototype.toString; Object.defineProperty(String.prototype, 'toString', { value: function() { if (this === window.navigator.userAgent) { return fakeUA; } return originalToString.call(this); }, configurable: true });
3. 验证修改是否生效
在代码后面加两行日志,确认UA已经被替换:
console.log(window.navigator.userAgent); // 应该输出伪造的UA console.log(window.navigator.userAgent.toString()); // 同样要输出伪造的UA
4. 匹配SWF的版本判断规则
一定要注意:SWF的getElectronVersion方法是从UA里提取GameVer后面的版本号,所以你的伪造UA里必须包含GameVer/1.5.3(或更高版本,比如GameVer/2.0.0),这样isElectronVersionIncompatible才会返回false,不会触发更新提示。
踩坑提醒
你之前尝试的window.getUserAgent方法没用,因为SWF里根本没调用这个自定义函数——它直接调用的是window.navigator.userAgent.toString,所以这个思路完全不对,不用再试了。
按照上面的步骤来,应该就能让远程SWF误以为它运行在符合要求的Electron环境里了。
备注:内容来源于stack exchange,提问作者ThatonehamYT

