Skip to content

Latest commit

 

History

History
363 lines (226 loc) · 14.2 KB

File metadata and controls

363 lines (226 loc) · 14.2 KB

CS2 VibeSignatures

English README

这是一个主要用于为 CS2 生成 signatures/offsets,并通过 Agent SKILLS 与 MCP Calls 更新 HL2SDK_CS2 C++ 头文件的项目。

该项目的设计目标是在完全无需人工参与的情况下更新 signatures/offsets/cpp headers。

目前,本项目已可自动更新 CounterStrikeSharpCS2Fixes 的全部 signatures/offsets。

依赖要求

  1. 安装 uv

  2. depotdownloader

  3. uv sync

  4. claude / codex

  5. IDA Pro 9.0+

  6. ida-pro-mcp

  7. idalib(运行 ida_analyze_bin.py 的必需项)

  8. Clang-LLVM(运行 run_cpp_tests.py 的必需项)

整体工作流

1. 下载 CS2 二进制文件并复制dll/so到工作目录

uv run download_depot.py -tag 14156

uv run copy_depot_bin.py -gamever 14146 -platform all-platform
uv run copy_depot_bin.py -gamever 14146 -platform all-platform -checkonly

当只需要确认 bin/<gamever>/... 下的目标二进制是否已经齐全时,可在 CI 或预检查脚本中使用 -checkonly。该模式只检查目标路径,不要求 cs2_depot 已准备完成;当所有目标文件都已就绪时返回 0,缺少任一目标文件时返回 1,配置或参数错误时返回 2

2. 为 config.yaml 的符号生成对应的 signatures

uv run ida_analyze_bin.py -gamever=14146 [-oldgamever=14145] [-configyaml=path/to/config.yaml] [-modules=server] [-platform=windows] [-agent=claude/codex/"claude.cmd"/"codex.cmd"] [-maxretry=3] [-vcall_finder=g_pNetworkMessages|*] [-llm_model=gpt-4o] [-llm_apikey=your-key] [-llm_baseurl=https://api.example.com/v1] [-llm_temperature=0.2] [-llm_effort=medium] [-llm_fake_as=codex] [-debug]
  • 在真正运行 Agent SKILL(s) 前,会先通过 mcp call 直接使用 bin/{previous_gamever}/{module}/{symbol}.{platform}.yaml 中的旧 signature 查找当前版本游戏二进制中的符号。不会消耗 token。

  • -agent="claude.cmd" 用于Windows上使用npm安装的claude cli

  • 共享 LLM CLI 参数:

    • -llm_apikey:启用基于 LLM 的流程时必需,包括 vcall_finder 聚合与 LLM_DECOMPILE
    • -llm_baseurl:可选,自定义兼容 base URL;启用 -llm_fake_as=codex 时必填
    • -llm_model:可选,默认 gpt-4o
    • -llm_temperature:可选,仅在显式设置时发送
    • -llm_effort:可选,默认 medium,支持 none|minimal|low|medium|high|xhigh
    • -llm_fake_as:可选,设为 codex 时改走直连 /v1/responses 的 SSE 传输
    • 环境变量 fallback:CS2VIBE_LLM_APIKEYCS2VIBE_LLM_BASEURLCS2VIBE_LLM_MODELCS2VIBE_LLM_TEMPERATURECS2VIBE_LLM_EFFORTCS2VIBE_LLM_FAKE_AS
    • LLM 流程不会读取 OPENAI_API_KEYOPENAI_API_BASEOPENAI_API_MODEL
  • 推荐实务中优先使用:纯程序化的预处理脚本 > 基于 LLM_DECOMPILE 的自动化反编译 > SKILL.md

vcall_finder 相关

  • -vcall_finder=g_pNetworkMessages 会在模块级 vcall_finder 配置中筛选同名对象;-vcall_finder=* 会处理 config.yaml 中已声明的全部对象。

  • 当启用 -vcall_finder 时,脚本会在每个模块/平台完成 IDA 任务后导出对象引用函数的完整反汇编与伪代码到 vcall_finder/{gamever}/{object_name}/{module}/{platform}/,并在全部模块/平台结束后执行 LLM 聚合;若某个 detail YAML 已存在顶层 found_vcall,则会跳过该次 LLM 调用,直接复用缓存结果。

  • LLM 成功返回后,会立刻将 found_vcall: [...]found_vcall: [] 回写到对应的 detail YAML,后续重跑可直接跳过该函数的 LLM 调用。

  • vcall_finder/{gamever}/{object_name}.txt 现在是按 YAML document stream 追加的扁平记录;每条记录直接包含 insn_vainsn_disasmvfunc_offset,不再嵌套 found_vcall:

uv run ida_analyze_bin.py -gamever=14141 -modules=networksystem -platform=windows -vcall_finder=g_pNetworkMessages -llm_model=gpt-5.4 -llm_apikey=sk -llm_effort=high -llm_fake_as=codex -llm_baseurl=http://127.0.0.1:8080/v1

输出示例:

  • vcall_finder/14141/g_pNetworkMessages/networksystem/windows/sub_140123450.yaml
  • vcall_finder/14141/g_pNetworkMessages.txt

LLM_DECOMPILE reference YAML 相关

reference YAML 存放路径:

  • ida_preprocessor_scripts/references/<module>/<func_name>.<platform>.yaml

准备步骤:

  1. 确认目标函数已有当前版本 YAML 且包含 func_va,或可通过 config.yaml 的 symbol name/alias 在 IDA 中定位。
  2. 运行独立 CLI:
uv run generate_reference_yaml.py -gamever 14141 CNetworkGameClient_RecordEntityBandwidth -mcp_host 127.0.0.1 -mcp_port 13337

自动启动 idalib-mcp 示例:

uv run generate_reference_yaml.py -gamever 14141 -module engine -platform windows -func_name CNetworkGameClient_RecordEntityBandwidth -auto_start_mcp -binary "bin/14141/engine/engine2.dll"
  1. 检查生成文件:
    • func_va 可信
    • disasm_code 非空,且与目标函数语义匹配
    • procedure 在可用时应与预期语义一致(Hex-Rays 不可用时允许为空字符串)
    • func_name 仅用于确认输出文件对应你请求的规范名,不能单独证明地址解析正确
  2. 在目标 find-*.py 脚本里接入 LLM_DECOMPILE
    • 生成文件在仓库中的路径:
      • ida_preprocessor_scripts/references/<module>/<func_name>.<platform>.yaml
    • LLM_DECOMPILE 使用相对路径,应写成:
      • references/<module>/<func_name>.<platform>.yaml
    • tuple 示例:
      • ("CNetworkMessages_FindNetworkGroup", "prompt/call_llm_decompile.md", "references/engine/CNetworkGameClient_RecordEntityBandwidth.windows.yaml")
    • LLM_DECOMPILE 复用 ida_analyze_bin.py 的共享 -llm_* 参数:-llm_model-llm_apikey-llm_baseurl-llm_temperature-llm_effort-llm_fake_as

3. 将 yaml(s) 转换为 gamedata json / txt

uv run update_gamedata.py -gamever 14141 [-debug]

4. 运行 C++ 测试并检查 cpp headers 是否与 yaml(s) 匹配

uv run run_cpp_tests.py -gamever 14141 [-debug] [-fixheader] [-agent=claude/codex/"claude.cmd"/"codex.cmd"] 
  • 使用 -fixheader 时,会启动一个 agent 来修复 cpp headers 中的不匹配项(会消耗少量token)

当前支持的 gamedata

CounterStrikeSharp

dist/CounterStrikeSharp/config/addons/counterstrikesharp/gamedata/gamedata.json

  • GameEventManager:在CSS中已废弃。
  • CEntityResourceManifest_AddResource:游戏更新时基本不会改动。

CS2Fixes

dist/CS2Fixes/gamedata/cs2fixes.games.txt

  • CCSPlayerPawn_GetMaxSpeed,因为它并不存在于 server.dll 中。

swiftlys2

dist/swiftlys2/plugin_files/gamedata/cs2/core/offsets.jsonc

dist/swiftlys2/plugin_files/gamedata/cs2/core/signatures.jsonc

plugify

dist/plugify-plugin-s2sdk/assets/gamedata.jsonc

cs2kz-metamod

dist/cs2kz-metamod/gamedata/cs2kz-core.games.txt

modsharp

dist/modsharp-public/.asset/gamedata/core.games.jsonc

dist/modsharp-public/.asset/gamedata/engine.games.jsonc

dist/modsharp-public/.asset/gamedata/EntityEnhancement.games.jsonc

dist/modsharp-public/.asset/gamedata/log.games.jsonc

dist/modsharp-public/.asset/gamedata/server.games.jsonc

dist/modsharp-public/.asset/gamedata/tier0.games.jsonc

  • 已跳过 230 个符号。

CS2Surf/Timer

dist/cs2surf/gamedata/cs2surf-core.games.jsonc

  • 已跳过 26 个符号。

如何为 vtable 创建 SKILL

CCSPlayerPawn 为例。

Claude Code:

/create-preprocessor-scripts Create "find-CCSPlayerPawn_vtable" in server.

如何为函数创建 SKILL

CItemDefuser_SpawnCBaseModelEntity_SetModel 为例

1. 在 IDA 中查找目标符号

  • 在 IDA 中搜索字符串 "weapons/models/defuser/defuser.vmdl",在其 xrefs 里找如下模式的代码片段:
    v2 = a2;
    v3 = (__int64)a1;
    sub_180XXXXXX(a1, (__int64)"weapons/models/defuser/defuser.vmdl"); //This is CBaseModelEntity_SetModel, rename it to CBaseModelEntity_SetModel
    sub_180YYYYYY(v3, v2);
    v4 = (_DWORD *)sub_180ZZZZZZ(&unk_181AAAAAA, 0xFFFFFFFFi64);
    if ( !v4 )
      v4 = *(_DWORD **)(qword_181BBBBBB + 8);
    if ( *v4 == 1 )
    {
      v5 = (__int64 *)(*(__int64 (__fastcall **)(__int64, const char *, _QWORD, _QWORD))(*(_QWORD *)qword_181CCCCCC + 48i64))(
                        qword_181CCCCCC,
                        "defuser_dropped",
                        0i64,
                        0i64);

包含该代码片段的函数为: CItemDefuser_Spawn

2. 创建预处理脚本并更新 config.yaml

Claude Code:

/create-preprocessor-scripts Create "find-CItemDefuser_Spawn" in server by xref_strings "weapons/models/defuser/defuser.vmdl", where CItemDefuser_Spawn is a vfunc of CItemDefuser_vtable.

Claude Code:

/create-preprocessor-scripts Create "find-CBaseModelEntity_SetModel" in server by LLM_DECOMPILE with "CItemDefuser_Spawn", where CBaseModelEntity_SetModel is a regular function being called in "CItemDefuser_Spawn".

如何为全局变量创建 SKILL

IGameSystem_InitAllSystems_pFirst 为例

1. 在 IDA 中查找目标符号

  • 在 IDA 中搜索字符串 "IGameSystem::InitAllSystems",查找该字符串的 xrefs。引用该字符串的函数就是 IGameSystem_InitAllSystems

  • 如果还没改名,请将其重命名为 IGameSystem_InitAllSystems

  • 查看 IGameSystem_InitAllSystems 开头附近的模式:( i = qword_XXXXXX; i; i = *(_QWORD *)(i + 8) )

  • 如果还没改名,将前一步发现的 qword_XXXXXX 重命名为 IGameSystem_InitAllSystems_pFirst

2. 创建预处理脚本并更新 config.yaml

Claude Code:

/create-preprocessor-scripts Create "find-IGameSystem_InitAllSystems" in server by xref_strings "IGameSystem::InitAllSystems", where IGameSystem_InitAllSystems is a regular func.

Claude Code:

/create-preprocessor-scripts Create "find-IGameSystem_InitAllSystems_pFirst" in server by LLM_DECOMPILE with "IGameSystem_InitAllSystems", where IGameSystem_InitAllSystems_pFirst is a global variable being used in "IGameSystem_InitAllSystems".

如何为结构体偏移创建 SKILL

CGameResourceService_m_pEntitySystem 为例。

1. 在 IDA 中查找目标符号

  • 在 IDA 中搜索字符串 "CGameResourceService::BuildResourceManifest(start)",并查找其 xrefs。

  • xref 应指向一个函数——这就是 CGameResourceService_BuildResourceManifest。如果尚未改名,请将其重命名。

2. 创建预处理脚本并更新 config.yaml

Claude Code:

/create-preprocessor-scripts Create "find-CGameResourceService_BuildResourceManifest" in engine by xref_strings "CGameResourceService::BuildResourceManifest(start)" , where CGameResourceService_BuildResourceManifest is a vfunc of CGameResourceService_vtable.
/create-preprocessor-scripts Create "find-CGameResourceService_m_pEntitySystem" in engine by LLM_DECOMPILE with "CGameResourceService_BuildResourceManifest", where CGameResourceService_m_pEntitySystem is a struct offset.

如何为补丁创建 SKILL

  • 补丁 SKILL 会在一个已知函数里定位特定指令,并生成替换字节来修改其运行时行为(例如强制/跳过某分支、NOP 掉某次调用)。目标函数通常应已有对应的 find-SKILL 输出(一般通过 expected_input 提供)。

  • 务必确保 ida-pro-mcp server 正在运行。

  • 对于人类贡献者:当你查找新符号时,应编写新的初始提示词,不要从 README 直接复制粘贴!

CCSPlayer_MovementServices_FullWalkMove_SpeedClamp 为例 —— 在 CCSPlayer_MovementServices_FullWalkMove 内把速度限制逻辑对应的 jbe 补丁为无条件 jmp

1. 在 IDA 中查找目标符号

  • 反编译 CCSPlayer_MovementServices_FullWalkMove,查找类似“某 float > 某 float 平方”的代码模式:
  v20 = (float)((float)(v16 * v16) + (float)(v19 * v19)) + (float)(v17 * v17);
  if ( v20 > (float)(v18 * v18) )
  {
    ...velocity clamping logic...
  }
  • 在比较附近反汇编,找到确切的条件跳转指令。

  • 在比较地址附近反汇编,定位 comiss + jbe 指令对。

  期望的汇编模式:
    addss   xmm2, xmm1          ; v20 = sum of squares
    comiss  xmm2, xmm0          ; compare v20 vs v18*v18
    jbe     loc_XXXXXXXX         ; skip clamp block if v20 <= v18*v18
  • 根据指令编码确定补丁字节。
  * Near `jbe` (`0F 86 rel32`,6 字节) → `E9 <new_rel32> 90`(无条件 `jmp` + `nop`)
  * Short `jbe` (`76 rel8`,2 字节) → `EB rel8`(无条件 `jmp short`)

2. 创建预处理脚本并更新 config.yaml

按照 .claude/skills/create-preprocessor-scripts/SKILL.md 中的步骤创建预处理脚本并更新 config.yaml

故障排查

error: could not create 'ida.egg-info': access denied

处理方式:在 C:\Program Files\IDA Professional 9.0\idalib\python 目录下,以管理员权限运行 python py-activate-idalib.py

Could not find idalib64.dll in .........

处理方式:尝试 set IDADIR=C:\Program Files\IDA Professional 9.0,或将 IDADIR=C:\Program Files\IDA Professional 9.0 添加到系统环境变量。

Jenkins 工作流参考

@echo Download latest game binaries

uv run download_bin.py -gamever %CS2_GAMEVER%
@echo Analyze game binaries

uv run ida_analyze_bin.py -gamever %CS2_GAMEVER% -agent="claude.cmd" -platform %CS2_PLATFORM% -debug
@echo Update gamedata with generated yamls

uv run update_gamedata.py -gamever %CS2_GAMEVER% -debug
@echo Find mismatches in CS2SDK headers and fix them

uv run run_cpp_tests.py -gamever %CS2_GAMEVER% -debug -fixheader -agent="claude.cmd"