智能助手网
标签聚合 逆向

/tag/逆向

linux.do · 2026-04-17 13:24:55+08:00 · tech

有时候我们会遇到这种情况: 1、我们有幸拿到了某个版本的ntoskrnl.exe,但是巨硬不知道发什么疯把这个版本的pdb从msdl下架,我们只能下载到这个版本的上一个版本的pdb,那么如果我们想快速拿到这个版本的某个非导出函数/全局变量的地址,应该怎么办? 2、我们曾经逆向过某个win64程序,但是这个程序更新了,我们不想人力重新逆一遍,想依赖上一个版本的逆向结果快速拿到新版本的某个函数的逆向结果,应该怎么办? 在人力逆向时代,我们一般是开两个IDA窗口,目力观察两边明显一样的符号 比如 左边窗口: virtualaddress: '0x140821f20' disasm_code: |- ; Exported entry 2045. PsSetCreateProcessNotifyRoutine ; NTSTATUS __stdcall(PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, BOOLEAN Remove) PAGE:0000000140821F20 public PsSetCreateProcessNotifyRoutine PAGE:0000000140821F20 PsSetCreateProcessNotifyRoutine proc near PAGE:0000000140821F20 sub rsp, 28h PAGE:0000000140821F24 mov al, dl PAGE:0000000140821F26 xor edx, edx PAGE:0000000140821F28 test al, al PAGE:0000000140821F2A setnz dl PAGE:0000000140821F2D call PspSetCreateProcessNotifyRoutine PAGE:0000000140821F32 add rsp, 28h PAGE:0000000140821F36 retn PAGE:0000000140821F37 db 0CCh PAGE:0000000140821F37 PsSetCreateProcessNotifyRoutine endp procedure: |- NTSTATUS __stdcall PsSetCreateProcessNotifyRoutine(PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, BOOLEAN Remove) { return PspSetCreateProcessNotifyRoutine((__int64)NotifyRoutine, Remove != 0); } 右边窗口: virtualaddress: '0x140821f20' disasm_code: |- ; Exported entry 2045. PsSetCreateProcessNotifyRoutine ; NTSTATUS __stdcall(PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, BOOLEAN Remove) PAGE:0000000140821F20 public PsSetCreateProcessNotifyRoutine PAGE:0000000140821F20 PsSetCreateProcessNotifyRoutine proc near PAGE:0000000140821F20 sub rsp, 28h PAGE:0000000140821F24 mov al, dl PAGE:0000000140821F26 xor edx, edx PAGE:0000000140821F28 test al, al PAGE:0000000140821F2A setnz dl PAGE:0000000140821F2D call sub_140822108 PAGE:0000000140821F32 add rsp, 28h PAGE:0000000140821F36 retn PAGE:0000000140821F37 db 0CCh PAGE:0000000140821F37 PsSetCreateProcessNotifyRoutine endp procedure: |- NTSTATUS __stdcall PsSetCreateProcessNotifyRoutine(PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, BOOLEAN Remove) { return sub_140822108((__int64)NotifyRoutine, Remove != 0); } 哪怕完全不懂逆向的新手都可以虎哥抽锐刻,一眼丁真:sub_140822108 = PsSetLoadImageNotifyRoutineEx 对于这种流程非常固定,但是又需要那么一点点脑子的任务来说,最优解当然是交给LLM了 有聪明的佬肯定会想到,那我开一个cc/codex,接上MCP让他全自动一把梭不行吗? 理论上肯定可可以,只要你不在乎时间和token消耗的话 cc速度是够快了,还原1个中等大小的函数花个0.5¥+不是问题。codex的话,可能会便宜一点,只用花~0.2¥,但是起步两三分钟,要处理100~200个函数的话成本直接上天了。这下有点怀念以前那个可以反代kiro白嫖claude,什么都可以大力出奇迹的时代了。 既然彻底放权给agent成本太高,彻底回归古法逆向又是纯纯的浪费生命,那么有没有折中方案呢? 相信各位佬看到下面这段提示词应该知道我想表达什么了 I have disassembly outputs and procedure code of the same function. This is the function for reference: **Disassembly for Reference** ```c {disasm_for_reference} ``` **Procedure code for Reference** ```c {procedure_for_reference} ``` This is the function you need to reverse-engineering: **Disassembly to reverse-engineering** ```c {disasm_code} ``` **Procedure code to reverse-engineering** ```c {procedure} ``` What you need to do is to collect all references to “{symbol_name_list}” in the function you need to reverse-engineering and output those references as YAML. Example: ```yaml found_vcall: # This is for indirect call to virtual function or virtual function pointer fetching. insn_va: ‘0x180777700’ # Always be the instruction with displacement offset insn_disasm: call [rax+68h] # Always be the instruction with displacement offset vfunc_offset: ‘0x68’ func_name: ILoopMode_OnLoopActivate insn_va: ‘0x180777778’ # Always be the instruction with displacement offset insn_disasm: mov rax, [rax+80h] # Always be the instruction with displacement offset vfunc_offset: ‘0x80’ func_name: INetworkMessages_GetNetworkGroupCount found_call: # This is for direct call to non-virtual regular function. insn_va: ‘0x180888800’ insn_disasm: call sub_180999900 func_name: CLoopModeGame_RegisterEventMapInternal insn_va: ‘0x180888880’ insn_disasm: call sub_180555500 func_name: CLoopModeGame_SetGameSystemState found_funcptr: # This is for non-virtual regular function pointer. insn_va: ‘0x180666600’ # Must load/reference the function pointer target address insn_disasm: lea rdx, sub_15BC910 # Must load/reference the function pointer target address funcptr_name: CLoopModeGame_OnClientPollNetworking found_gv: # This is for reference to global variable. insn_va: ‘0x180444400’ insn_disasm: mov rcx, cs:qword_180666600 # Must load/reference the global variable gv_name: g_pNetworkMessages insn_va: ‘0x180333300’ insn_disasm: lea rax, unk_180222200 # Must load/reference the global variable gv_name: s_GameEventManager found_struct_offset: # This is for reference to struct offset. NOTE THAT virtual function pointer should not be here! virtual function pointer should ALWAYS be in found_vcall ! insn_va: ‘0x1801BA12A’ # Always be the instruction with displacement offset insn_disasm: mov rcx, [r14+58h] # Always be the instruction with displacement offset offset: ‘0x58’ size: 8 struct_name: CGameResourceService member_name: m_pEntitySystem ``` If nothing found, output an empty YAML. DO NOT output anything other than the desired YAML. DO NOT collect unrelated symbols. 上面的 Procedure code、Disassembly都是程序化填充的,返回结果也是程序化解析的,时间成本与token成本均为0 实测下来:量大管饱的d师傅逆200个函数只用大约1¥,碰到超大函数有爆context风险的,临时切gpt5.4也花不了几个钱,并且基本上10秒内都可以拿到结果。 2 个帖子 - 2 位参与者 阅读完整话题

linux.do · 2026-04-15 18:11:08+08:00 · tech

[mw_shl_code=javascript,false]{ “a1”: “1.2”, # 加密版本 “a2”: new Date().valueOf() - serverTimeDiff, # 加密过程中用到的时间戳. 这次服主变坏了, 时间戳需要减去一个 serverTimeDiff(见a3) ! “a3”: “这是把xxx信息加密后提交给服务器, 服主校验成功后返回的一个dfpId”, # dfpId. 服务器返回的dfpId数据包里, 有一个serverTimestamp字段. serverTimeDiff = serverTimestamp - Date.now() “a4”: “一个长48位的加密结果”, # a5, a2以及一小段jsvmp运行后, 输出a4 “a5”: “一个长320位的加密结果”, # a2, a6, 以及下面的Ln, 计算后输出a5 “a6”: “w1.2xxxxx这一段长512xxxxxxx”, # w1.2 + 客户端环境的加密结果 “a7”: wx "getAccountInfoSync" .miniProgram.appId, # 小程序id “x0”: 3, # 源代码写死 “d1”: md5ToHex(j) # a1, a2, a3, a4, a7以及上面加密过程中出现的一些数组, 经过运算后, 输出d1 } Ln = { “b1”: {appId: “小程序id”, envVersion: “release”, version: “微信版本号”}, “b2”: “一个url”, “b6”: “微信的openId”, # 这个玩意儿可以考虑置空 “b7”: Math.floor(Date.now() / 1e3), “b8”: “17” # 不重要, 1-20给个随机值就行 }[/mw_shl_code] PS: 基于某评微信小程序的guard.js文件, 且文件经过简单的ast脱混淆. 1. 收集的环境[mw_shl_code=javascript,false]Ne = { DFP: [“app”, “dfpid”, “filetime”, “fpv”, “localid”, “system”, “timestamp”, “ext”, “sessionId”], system: [“accelerometer”, “albumAuthorized”, “BatteryInfo”, “batteryLevel”, “Beacons”, “benchmarkLevel”, “bluetoothEnabled”, “brand”, “brightness”, “cameraAuthorized”, “compass”, “deviceOrientation”, “devicePixelRatio”, “enableDebug”, “errMsg”, “fontSizeSetting”, “language”, “LaunchOptionsSync”, “locationAuthorized”, “locationEnabled”, “locationReducedAccuracy”, “microphoneAuthorized”, “model”, “networkType”, “notificationAlertAuthorized”, “notificationAuthorized”, “notificationBadgeAuthorized”, “notificationSoundAuthorized”, “pixelRatio”, “platform”, “safeArea”, “screenHeight”, “screenTop”, “screenWidth”, “SDKVersion”, “statusBarHeight”, “system”, “version”, “wifiEnabled”, “WifiInfo”, “windowHeight”, “windowWidth”], BatteryInfo: [“errMsg”, “isCharging”, “level”], safeArea: [“left”, “right”, “top”, “bottom”, “width”, “height”], WifiInfo: [“SSID”, “BSSID”, “autoJoined”, “signalStrength”, “justJoined”, “secure”, “frequency”] }[/mw_shl_code] 1.1 环境加密逻辑(a6). 主要是找到收集了哪些环境, 以及环境对应的值. 加密函数中只有常见的加密运算符, 没有检测环境的异常分支或其他坑. 所以逆向中遇到的加密函数直接 复制粘贴到自己的代码里就好. 譬如: [mw_shl_code=javascript,false]vn = { gzipSync: R, compressSync: R, strToU8: function (e, n) { var a = e.length; if (!n && “undefined” != typeof TextEncoder) return new TextEncoder().encode(e); for (var t = new Je(e.length + (e.length >>> 1)), c = 0, r = function (e) { t[c++] = e; }, f = 0; f < a; ++f) { if (c + 5 > t.length) { var o = new Je(c + 8 + (a - f << 1)); o.set(t), t = o; } 128 > (o = e.charCodeAt(f)) || n ? r(o) : 2048 > o ? (r(192 | o >>> 6), r(128 | 63 & o)) : 55295 < o && 57344 > o ? (r(240 | (o = 65536 + (1047552 & o) | 1023 & e.charCodeAt(++f)) >>> 18), r(128 | o >>> 12 & 63), r(128 | o >>> 6 & 63), r(128 | 63 & o)) : (r(224 | o >>> 12), r(128 | o >>> 6 & 63), r(128 | 63 & o)); } return nn(t, 0, c); } }; function R(e, n) { void 0 === n && (n = {}); var a = pn(), t = e.length; a.p(e); var c = (e = ln(e, n, 10 + (n.filename && n.filename.length + 1 || 0), 8)).length, r = n; if (n = r.filename, e[0] = 31, e[1] = 139, e[2] = 8, e[8] = 2 > r.level ? 4 : 9 == r.level ? 2 : 0, e[9] = 3, 0 != r.mtime && gn(e, 4, Math.floor(new Date(r.mtime || Date.now()) / 1e3)), n) for (e[3] = 8, r = 0; r <= n.length; ++r) e[r + 10] = n.charCodeAt(r); return gn(e, c - 8, a.d()), gn(e, c - 4, t), e; } gn = function (e, n, a) { for (; a; ++n) e[n] = a, a >>>= 8; }, function J(e) { function n() { for (var e, n = [“xxxxxxxxxxxxxxxxxxxxxxxxxx”, “xxxxxxxxxxxxxxxxxxxxxxxxxx”], a = , c = 0; c < n[“length”]; c++) { e = “”; for (var r = n[c], f = r["length"], o = parseInt("0x" + r["substr"](0, 2)), d = 2; d < f; d += 2) { var i = parseInt("0x" + r["charAt"](d) + r["charAt"](d + 1)); e += String["fromCharCode"](i ^ o); } a["push"](e); } return a; } var a = ke["codec"]["utf8String"]["toBits"](n()[0]), c = ke["codec"]["utf8String"]["toBits"](n()[1]); return a = new ke["cipher"]["aes"](a), e = ke["mode"]["cbc"]["encrypt"](a, e, c), ke["codec"]["base64"]["fromBits"](e); }[/mw_shl_code] a2-a8加密前的准备工作. 2.1 a5, a4的加密逻辑(包含两段简单的jsvmp代码, 相对于mtgsig1.1的jsvmp代码, 服主很可能还在练手). 代码中调用的函数也都是简单的运算操作. 例: [mw_shl_code=javascript,true]Qn = function () { for (var n, a, c = 256, r = ; c–; r[c] = n >>> 0) for (a = 8, n = c; a– n = 1 & n ? n >>> 1 ^ 3988292384 : n >>> 1; return function (n) { if ("string" == e(n)) { for (var a = 0, c = -1; a < n["length"]; ++a) c = r[255 & c ^ n["charCodeAt"](a)] ^ c >>> 8; return 306674911 ^ c; } for (a = 0, c = -1; a < n["length"]; ++a) c = r[255 & c ^ n[a]] ^ c >>> 8; return 306674911 ^ c; }; }(); function Z(e) { var n = ; return n[0] = e >>> 24 & 255, n[1] = e >>> 16 & 255, n[2] = e >>> 8 & 255, n[3] = 255 & e, n; } function X(e) { for (var n = , a = 0; a < e[“length”]; a += 2) { var c = e "charAt" + e[“charAt”](a + 1); c = parseInt(c, 16), n "push" ; } return n; } function W(e) { e = encodeURIComponent(e); for (var n = [], a = 0; a < e["length"]; a++) { var c = e["charAt"](a); "%" === c ? (c = e["charAt"](a + 1) + e["charAt"](a + 2), c = parseInt(c, 16), n["push"](c), a += 2) : n["push"](c["charCodeAt"](0)); } return n; } function ae(e, n) { var a = e[“length”]; n ^= a; for (var c = 0; 4 <= a;) { var r = 1540483477 * (65535 & (r = 255 & e[c] | (255 & e[++c]) << 8 | (255 & e[++c]) << 16 | (255 & e[++c]) << 24)) + ((1540483477 * (r >>> 16) & 65535) << 16); n = 1540483477 * (65535 & n) + ((1540483477 * (n >>> 16) & 65535) << 16) ^ (r = 1540483477 * (65535 & (r ^= r >>> 24)) + ((1540483477 * (r >>> 16) & 65535) << 16)), a -= 4, ++c; } switch (a) { case 3: n ^= (255 & e[c + 2]) << 16; case 2: n ^= (255 & e[c + 1]) << 8; case 1: n = 1540483477 * (65535 & (n ^= 255 & e[c])) + ((1540483477 * (n >>> 16) & 65535) << 16); } return ((n = 1540483477 * (65535 & (n ^= n >>> 13)) + ((1540483477 * (n >>> 16) & 65535) << 16)) ^ n >>> 15) >>> 0 ^ 1540483477; }[/mw_shl_code] 2.2 d1, 以及最终mtgsig赋值 1 个帖子 - 1 位参与者 阅读完整话题

linux.do · 2026-04-15 18:08:16+08:00 · tech

拿到验证码的url, 解析出request_code 通过request_code, 请求ext_api/page_data接口, 拿到验证码基础信息. 主要包含 session 和 sign 两个长字符串 2.1 sign 是一段加密过的 包含 环境检测 / 控制流 的/很 长 /很 大 的 一串js代码. 解密sign要用到session , 目前检测的环境不多 , sign解密成js代码并且执行成功后可以拿到一个关键的变量 _f 的值. 通过request_code, 请求ext_api/spiderindefence/info接口, 拿到验证码的两张图片信息, 以及一个很重要的 hint 值(乱码字符串, 解密九宫格图片的顺序时要用到) 识别第一张图片文本, 拿到要 连接哪个颜色 ; 识别第二张图片, 拿到 哪个坐标(位置)是哪个颜色 4.1 文本图片 可以考虑使用 ddddocr , 可以勉强识别, 成功率较低 4.2 九宫格图片 识别 4.2.1 服务器下发的九宫格 原图 , 顺序/大小都是混淆过的 . 页面最终显示的验证码 是在客户端 先用js解密出九宫格图片的排序顺序, 然后用canvas重新画出的一张图片. 4.2.2 需要扣一下 解密九宫格图片排序的js代码; canvas画图的代码用python的PIL库复现一下就行(一点儿也不难:curse:) 4.2.3 重组后的九宫格图片, 还要注意调整分辨率 (不然会导致下面4.2.4中坐标读取错误) 4.2.4 每个位置的球的颜色识别, 本质就是用PIL库读取固定点的RGB值就可以了, 判断RGB在哪个颜色范围, 就属于哪个颜色. (9个球的位置都是固定的) 4.2.5 参考 原图: 重新排序以及重置分辨率后: 5. 生成滑动轨迹. 手动收集, 每个位置的球都手动连一次, 要注意收集到的轨迹数组的长度, 太长不行, 太短也不行. (不然就得重新收集, 一点儿也不麻烦{:1_909:}) 6. 加密各个参数, 提交验证(这部分有很多要注意的点, 先写还记得的) 6.1 behavior和_token, 使用的同一个加密算法, 加密两轮, 但是传入的参数有区别 , 注意区分就好了. 加密结果要用到上面解出来的**_f** 值 6.2 _token主要包含 两个重要的时间戳 , 几段 不完整的 鼠标移动轨迹 数组和一个点击事件生成的小数组, 以及一些简单的基础环境信息 6.3 behavior主要包含 九宫格图片 与各个元素的相对位置坐标, 点击次数, 以及滑动轨迹(有长度限制) 6.3 时间戳部分, 在正确的位置生成正确的时间戳! 注意每个有关联的时间戳之间的差值. 多刷新几次浏览器, 拿到一个大概的差值, 在代码里随机生成一下 6.4 轨迹部分, 注意每个轨迹数组是怎么来的. 不同的轨迹数组, 但是可以相互印证, 对不上就鸡鸡! 有意思的: 通过判断是否存在 “v_” 开头的函数名, 检测v_jstools插件. 图片顺序的解密, js代码的解密, 轨迹的加密代码 都不难. 扣完代码, 再加上补环境的代码, 也就400+行! 更多的是 每个节点生成的时间戳 和 各个轨迹数组的验证! 1 个帖子 - 1 位参与者 阅读完整话题

linux.do · 2026-04-15 15:24:46+08:00 · tech

今天突发奇想研究一下炉石记牌器是怎么做的,拉下来HDT的代码给gpt5.4研究,发现它其中读取游戏内存的部分是编译好的包,没源码,所以现在下载了下来,怎么让模型来逆向这个包?包里有.h头文件,应该是c++或者c写的。之前没这方面经验,还望佬们不吝赐教! 文件试了几次上传不上来,下载地址: https://libs.hearthsim.net/hstracker/68562eeef78c18860bfd86113bd4c80ebe5023be/HearthMirror.framework.zip 1 个帖子 - 1 位参与者 阅读完整话题

linux.do · 2026-04-12 16:19:16+08:00 · tech

大家看看有些观点确实颠覆认知。 by: GitHub - ultraworkers/claw-code: The repo is finally unlocked. enjoy the party! The fastest repo in history to surpass 100K stars ⭐. Join Discord: https://discord.gg/5TUQKqFWd Built in Rust using oh-my-codex. · GitHub [04.01 更新]: 关闭遥测开关请谨慎使用!这个动作本身就有极大可能在后续被纳入风控特征中。 最新的防护建议更新 在此部分 ,关闭遥测开关的风险探索 在此部分 。 基于 Claude Code 泄露源码的全面逆向分析,本文档梳理了 Claude Code 向 Anthropic 服务端上报的所有数据,识别出可能触发封号的关键数据点,并给出防护建议。 一、数据上报架构总览 暂时无法在飞书文档外展示此内容 二、三大数据上报通道 通道 端点 用途 Datadog https://http-intake.logs.us5.datadoghq.com/api/v2/logs 实时事件监控,80+ 事件类型 1P BigQuery https://api.anthropic.com/api/event_logging/batch 完整遥测日志,带 OAuth 认证 GrowthBook https://api.anthropic.com/ 特性开关和 A/B 实验,上报用户属性 即使关闭遥测( DISABLE_TELEMETRY=1 ),API 请求自身携带的 Attribution Header 和 Attestation 仍然会发送。遥测开关只能关闭 Datadog 和 BigQuery 通道。 三、API 请求中携带的身份信息 3.1 HTTP Headers 每个 API 请求都会发送以下 HTTP 头: x-app: cli User-Agent: claude-cli/{版本} ({USER_TYPE}, {入口点}, agent-sdk/..., client-app/...) X-Claude-Code-Session-Id: {sessionId} x-client-request-id: {随机UUID} x-claude-remote-container-id: ... (容器环境) x-claude-remote-session-id: ... (远程会话) User-Agent 中包含了 USER_TYPE(ant/external)、入口点(cli/vscode/jetbrains)、Agent SDK 版本等关键信息,服务端可以精确判断你的使用方式。 3.2 Attribution Header(关键反作弊机制) 每个 API 请求的 system prompt 中嵌入一行特殊的 billing header: x-anthropic-billing-header: cc_version={版本}.{fingerprint}; cc_entrypoint={入口}; cch=00000; 暂时无法在飞书文档外展示此内容 三个关键字段: cc_version : 版本号 + 3字符指纹。指纹基于首条用户消息的第4、7、20个字符 + 版本号的 SHA256 前3位 cc_entrypoint : 启动入口(cli/vscode/jetbrains 等) cch : Native Client Attestation(原生客户端证明)。由 Bun 底层 Zig 代码在 HTTP 发送时替换占位符为计算出的 hash。服务端通过验证此 token 来确认请求来自未修改的官方 Claude Code 二进制 cch Attestation 是最核心的反作弊机制。修改过的客户端或 API 代理无法生成正确的 attestation token,服务端可以立即判断请求来自非官方客户端。 3.3 Fingerprint 算法 源码位于 src/utils/fingerprint.ts : const FINGERPRINT_SALT = '59cf53e54c78' // 硬编码盐值,必须与后端匹配 // SHA256(SALT + msg[4] + msg[7] + msg[20] + version)[:3] 服务端会验证这个指纹。如果你用修改过的客户端或代理转发,指纹不匹配就会被检测到。 四、持久化设备身份追踪 4.1 Device ID 源码位于 src/utils/config.ts : // 首次运行生成 64 字符随机十六进制字符串 randomBytes(32).toString('hex') // 永久存储在 ~/.claude.json 这是一个跨会话、跨账号的永久设备指纹。即使你换账号,设备 ID 不变。如果一个设备 ID 关联了多个被封账号,新账号也可能被关联封禁。 4.2 GrowthBook 上报的完整用户画像 源码位于 src/services/analytics/growthbook.ts : { id, // 用户 ID sessionId, // 会话 ID deviceID, // 持久设备 ID organizationUUID, // 组织 ID accountUUID, // 账号 UUID email, // 邮箱地址 subscriptionType, // 订阅类型 (pro/max/team/enterprise) rateLimitTier, // 速率限制层级 appVersion, // 版本号 apiBaseUrlHost, // 自定义 API 端点(如用代理会暴露) platform, // 操作系统 firstTokenTime, // 首次使用时间 githubActionsMetadata // GitHub Actions 信息 } 4.3 邮箱地址收集 邮箱收集来源优先级( src/utils/user.ts ): OAuth 账户邮箱 内部员工邮箱( COO_CREATOR → @anthropic.com ) git config user.email — 即使你没用 OAuth 登录,也会通过 git 获取你的邮箱 即使换了账号, git config user.email 会暴露你的真实身份。这是一个容易被忽略的信息泄露点。 五、环境探测 — 系统指纹 5.1 操作系统和硬件信息 每个遥测事件都附带以下环境信息: 字段 来源 示例值 platform process.platform darwin/linux/win32 arch process.arch x64/arm64 nodeVersion 运行时检测 v20.11.1 bunVersion 运行时检测 1.1.24 terminalType 环境变量检测 vscode/cursor/tmux/ssh-session linuxDistroId /etc/os-release ubuntu/debian/fedora wslVersion /proc/version WSL1/WSL2/WSL3 installedPkgMgrs 可用性检测 npm,yarn,pnpm 字段 来源 示例值 availableRuntimes 可用性检测 bun,deno,node 5.2 运行环境检测 Claude Code 会主动探测你是否在以下环境运行: 暂时无法在飞书文档外展示此内容 5.3 AI Gateway/代理检测 源码位于 src/services/api/logging.ts ,Claude Code 主动检测你是否使用了 AI 代理网关: const GATEWAY_FINGERPRINTS = { litellm: { prefixes: ['x-litellm-'] }, helicone: { prefixes: ['helicone-'] }, portkey: { prefixes: ['x-portkey-'] }, cloudflare: { prefixes: ['cf-aig-'] }, kong: { prefixes: ['x-kong-'] }, braintrust: { prefixes: ['x-bt-'] }, databricks: [域名后缀检测] } 客户端会扫描 API 响应头来判断你是否通过代理/网关转发请求,并将检测到的 gateway 类型上报到 Datadog 和 BigQuery。 5.4 GitHub Actions 元数据自动泄露 在 CI 环境自动采集( src/utils/user.ts ): 环境变量 内容 GITHUB_ACTOR GitHub 用户名 GITHUB_ACTOR_ID GitHub 用户 ID GITHUB_REPOSITORY 仓库全名 GITHUB_REPOSITORY_ID 仓库 ID GITHUB_REPOSITORY_OWNER 仓库拥有者 GITHUB_REPOSITORY_OWNER_ID 拥有者 ID 六、速率限制和配额监控 6.1 三层限额系统 源码位于 src/services/claudeAiLimits.ts : 限额类型 窗口 说明 five_hour 5小时滑动窗口 会话级限制 seven_day 7天 周限额 seven_day_opus 7天 Opus 模型专属限额 seven_day_sonnet 7天 Sonnet 模型专属限额 overage 超额 额外用量限制 6.2 提前预警机制 基于 HTTP 响应头: anthropic-ratelimit-unified-{claim}-surpassed-threshold 基于使用速度:如果消耗速度超过可持续速率(例如在 72% 的时间窗口消耗了 90% 配额),触发警告 getRawUtilization() 暴露使用率给状态栏脚本 七、远程控制机制 7.1 GrowthBook 远程杀开关 // 特性名故意混淆:tengu_frond_boric { datadog?: boolean, firstParty?: boolean } 可以远程禁用特定分析管道。 7.2 Policy Limits 远程策略 服务端可以远程推送策略限制,每小时轮询一次。支持组织级别的功能限制。 7.3 Remote Managed Settings 企业版可远程推送配置,包括对"危险设置"的安全审查: 危险 Shell 设置: apiKeyHelper , awsAuthRefresh , statusLine 等 危险环境变量: ANTHROPIC_BASE_URL , HTTP_PROXY , NODE_TLS_REJECT_UNAUTHORIZED 等 八、封号风险评估矩阵 暂时无法在飞书文档外展示此内容 九、防护建议 以下建议仅供安全研究参考,请在合规范围内使用 Claude Code。 9.1 降低风险的实操建议 核心原则:「融入」而非「消失」。让自己看起来像一个正常的合规地区用户。 措施 说明 重要程度 不要关闭遥测 保持默认设置,不要设置 DISABLE_TELEMETRY 或 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 。如果已经设置了,请尽快清除 极高 不要使用手机客户端 (仅在订阅支付时使用,刚需场景无法规避)|手机端会采集 GPS、SIM 卡 MCC/MNC、基站定位等硬件级地理信号,几乎不可能伪装|极高| |封号后彻底清理环境|清除 ~/.claude.json 中的 deviceId 、 ~/.claude/ 下的持久化数据。deviceId 是跨账号的设备指纹,不清理会关联新账号。 建议:可以单独对 ~/.claude/skills/ 、 ~/.claude/settings.json 、 ~/.claude/CLAUDE.md 、 ~/.claude/rules/ 等文件进行备份后,再将 ~/.claude/ 、 ~/.claude.json 完全删除。|高| |网络保持稳定一致|使用住宅 IP,固定出口,全程保持代理连接。避免 IP 地理位置突然跳变|高| |环境信号对齐| TZ 、 LANG 、 LC_ALL 与 IP 归属地一致。IP 在纽约但时区是 Asia/Shanghai 是最常见的穿帮|高| |避免中国特有 Linux 发行版|deepin、UOS、openKylin、openEuler 等发行版名称本身就是强地理信号。建议用 Ubuntu/Debian/macOS|高| |避免国内镜像源|不要用 npmmirror、tuna 等国内镜像。 npm config set registry https://registry.npmjs.org/ |中| |修改 git config user.email |避免通过 git 邮箱泄露真实身份|中| |正常使用,不搞自动化|有间隔、有停顿、合理频率。不要 24 小时无间断调用|中| |避免使用已知 AI Gateway|LiteLLM、Helicone、Portkey 等代理的响应头指纹会被检测并上报。不要使用所谓的反封号反追踪工具。|中| 9.2 无法规避的硬性检测 cch Attestation : 由 Bun 底层 Zig 代码生成,无法通过修改 JS/TS 层绕过 Fingerprint 校验 : 盐值和算法与服务端强耦合 API 请求头 : 每个请求都携带 session ID、User-Agent、version 等信息 HTTP 连接层 : IP 地址、TLS 指纹等网络层信息始终可见 9.3 关闭遥测本身可能是更大的风险 注意,关闭遥测这个动作本身可能比你想隐藏的东西更危险。 第一,关闭遥测自带地域标签。 「关闭遥测」的教程几乎只在中文社区传播。风控系统不需要知道你是谁,只需要知道:在所有关闭遥测的用户中,不合规地区用户的比例显著偏高。合规地区的用户没有强动机去做这件事——不关也没有后果。这是一个经典的贝叶斯推理: P(不合规地区 | 关闭遥测) 远高于基准概率。 第二,你关不掉的远多于你关掉的。 关闭遥测只屏蔽了 Datadog 和 BigQuery 两条上报通道。但服务端每次 API 请求必然可见的信号——IP 及地理归属、TLS 指纹(JA3/JA4)、OAuth Token、API 调用频率和时间分布、客户端版本号——一个都没少。你唯一多做的事,是给自己贴了一个「我有东西要藏」的标签。 第三,关闭遥测会同时关闭付费功能。 源码证实了一条致命的调用链: DISABLE_TELEMETRY=1 → isAnalyticsDisabled()=true → is1PEventLoggingEnabled()=false → isGrowthBookEnabled()=false 。GrowthBook 控制着几乎所有付费功能的 Feature Flag,关闭后 Opus 4.6 1M 模型会静默消失、Fast Mode 不可用、Remote Control 失效——你花了钱,但功能悄悄降级了,连报错都没有。 9.4 核心结论 **建议不要关闭遥测!关闭遥测不会让你更安全,反而会让你成为风控系统中最显眼的那个人。**即使关闭所有遥测开关,每个 API 请求自身就携带了丰富的身份和环境信息(Attribution Header + Attestation + Session ID + User-Agent)。Anthropic 服务端完全有能力基于这些数据进行异常检测和账号关联。最安全的做法是合规使用,不要触碰反作弊红线。 **被封号后必须彻底清理环境:**换账号不等于换设备。 ~/.claude.json 中的 deviceId 是一个跨账号的永久设备指纹,不清理它,风控系统一关联就能发现这台设备上有封号历史,新账号的风险分会直接拉满。除了 deviceId,还需要清理 ~/.claude/ 下的所有持久化数据(session、缓存、遥测队列等),才算真正「换了一台新设备」。 风控对抗的核心逻辑是「融入」而非「消失」。 需要的是让自己看起来和千千万万的正常用户没有区别,而不是变成没有数据的幽灵——那反而是最显眼的。 附录:关键源码文件索引 文件路径 内容 src/utils/fingerprint.ts 指纹计算算法 src/constants/system.ts Attribution Header 和 cch Attestation src/services/api/client.ts HTTP Headers 构建 src/services/analytics/datadog.ts Datadog 事件上报 src/services/analytics/growthbook.ts GrowthBook 用户画像上报 src/services/analytics/firstPartyEventLoggingExporter.ts BigQuery 遥测导出 src/services/analytics/metadata.ts 事件元数据采集 src/utils/user.ts 用户身份信息收集 文件路径 内容 src/utils/env.ts 环境和运行时探测 src/utils/platform.ts 系统平台信息采集 src/services/api/logging.ts API 请求日志和 Gateway 检测 src/services/claudeAiLimits.ts 速率限制和配额管理 src/services/policyLimits/index.ts 远程策略限制 src/services/remoteManagedSettings/index.ts 远程托管设置 src/utils/config.ts Device ID 生成和持久化 1 个帖子 - 1 位参与者 阅读完整话题