Chameleon时区伪装深度解析:完整替换Date API的逆向指南
2026/8/25 9:25:26 网站建设 项目流程

Chameleon时区伪装深度解析:完整替换Date API的逆向指南

【免费下载链接】chameleonWebExtension port of Random Agent Spoofer项目地址: https://gitcode.com/gh_mirrors/chamel/chameleon

Chameleon 是一款浏览器 WebExtension 插件,其核心能力之一是时区伪装——它通过完整替换Date对象及其全部原型方法,让网页代码"以为"用户身处任意时区。本文带你逆向这套机制,搞懂它是如何用不到 350 行代码把 20 多个 API 全部劫持的。

网站是怎么探测你真实时区的?

任何指纹检测库只需几行代码就能拿到你的时区:

new Date().getTimezoneOffset() // 返回 UTC 偏移分钟数 Intl.DateTimeFormat().resolvedOptions().timeZone // 返回时区 ID

这两个值来自浏览器底层,普通脚本无法修改。Chameleon 的思路不是"欺骗返回",而是直接把整个Date类替换成自己写的版本,让所有依赖 Date 的代码都走它的逻辑。

整体架构:三个模块协作

时区伪装涉及三个核心文件:

模块文件职责
时区伪装代码src/lib/spoof/timezone.ts生成注入页面的 Date 替换脚本
时区数据源src/lib/tz.ts提供 560+ 个 IANA 时区 ID
注入引擎src/lib/inject.ts组装最终注入脚本并执行

流程简述:用户在下拉框选择一个时区 → 引擎查询 IANA 时区信息 → 将伪装代码拼接为自执行脚本 → 注入当前页面及所有 iframe。

Date API 是如何被完整替换的?

构造函数劫持

替换的核心是一个自定义函数,它不再继承原生Date,而是内部调用原Date后重新包装:

  • 调用new ORIGINAL_DATE(...arguments)拿到真实时间
  • 通过Intl.DateTimeFormat把真实时间换算到目标时区
  • 把换算结果缓存到WeakMap中,后续 getter 都从缓存读取
  • new被省略(当函数调用),返回字符串而非对象

原型方法逐体重写

Date.prototype上的 20 个方法全部被替换,分为两组:

Getter 组getDategetDaygetFullYeargetHoursgetMinutesgetMonthgetTimezoneOffset):

每个方法内部先检查缓存,若无缓存则调用modifyDate(this)重新计算,然后从目标时区的 Date 对象上取值

Setter 组setDatesetFullYearsetHourssetMillisecondssetMonthsetSecondssetTime):

先执行原始 setter 修改时间戳,再重新触发modifyDate更新缓存,保证后续读取一致。

字符串方法组toDateStringtoStringtoTimeStringtoJSONtoLocaleStringtoLocaleDateStringtoLocaleTimeString):

这组最关键——指纹库最爱看字符串输出。处理方式:

  1. 用目标时区 Date 调用原方法生成字符串
  2. replaceName()函数把字符串中出现的真实时区缩写(长名/短名各 2 份)替换为目标时区缩写
  3. toStringtoTimeString额外拼接GMT+偏移量和时区全称

所有 setter 方法都做了 NaN 兜底,防止无效日期导致崩溃。

Intl.DateTimeFormat 与 window.open 的同步伪装

只替换Date还不够——Intl.DateTimeFormat能绕过 Date 直接读取系统时区。Chameleon 在 src/lib/inject.ts 中做了双重拦截:

  1. 替换Intl.DateTimeFormat构造函数:无论页面传什么参数,都在内部强制注入timeZone为目标时区 ID,再调用原始实现
  2. 拦截window.open:新窗口继承同一个伪装过的DateIntl.DateTimeFormat,防止跨窗口时区不一致

此外,所有 DOM 节点操作方法(appendChildinnerHTML等)被 patch,检测到<iframe>插入时自动向子 frame 注入同一套伪装代码。

反检测技巧:伪装成"原生代码"

指纹检测常通过以下方式识别 hook:

Date.toString() // 期望 "function Date() { [native code] }"

Chameleon 的对策:

  • 每个被替换函数都通过Object.defineProperty重写toString,返回"function 方法名() { [native code] }"
  • 重写name属性,让fn.name返回正确的方法名
  • 将原始Date引用重命名为随机标识符(随机字母+随机 base36 字符串),避免字符串搜索找到ORIGINAL_DATE
  • Date.length被锁定为7,与原生构造函数参数数量一致
  • Date.UTCDate.nowDate.parse保持指向原生实现,防止typeof检查异常

时区数据从哪来?

560 个时区 ID 硬编码在 src/lib/tz.ts 中,格式为 IANA 标准(Asia/ShanghaiAmerica/New_York等),同时携带 UTC 偏移字符串用于 UI 展示。实际偏移计算由moment-timezone库完成,它内置了完整的夏令时规则表,确保冬夏切换时偏移量自动正确。

配置时区伪装:默认值、IP 联动与白名单

在选项页 src/options/App.vue 中,时区下拉框提供三种模式:

  • default:使用系统真实时区
  • 具体时区 ID:伪装到指定时区
  • ip:根据当前出口 IP 自动推断时区(通过后台请求 IP 定位服务获取)

白名单规则可以按站点粒度独立配置时区,与主设置互不干扰。设置变更在 src/lib/chameleon.ts 中通过tempStore.ipInfo.tz缓存 IP 推断结果,避免每次切换页面都重新请求。

快速上手:启用时区伪装

  1. 打开扩展选项页,找到Timezone下拉框
  2. 选择目标时区(如Europe/LondonAsia/Tokyo)或ip自动匹配
  3. 保存后刷新已打开的标签页,伪装即生效
  4. 在控制台执行new Date().toString(),应看到目标时区的 GMT 偏移和时区名称

如果某些网站行为异常,可将该站点加入白名单并设为real(真实环境)或spoofed(使用伪装),避免全局规则影响登录验证等敏感场景。

总结

Chameleon 的时区伪装本质上是一套运行时 API 劫持框架:用Intl.DateTimeFormat做时区数学运算,用WeakMap缓存伪造结果,用Object.defineProperty抹平检测痕迹,最终实现Date全家桶 +Intl+ 跨窗口/跨 frame 三层一致的时区欺骗。理解这套机制后,你就能把它当作"浏览器 API 逆向工程"的教科书案例来参考。

【免费下载链接】chameleonWebExtension port of Random Agent Spoofer项目地址: https://gitcode.com/gh_mirrors/chamel/chameleon

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询