这是一个主要用于为 CS2 生成 signatures/offsets,并通过 Agent SKILLS 与 MCP Calls 更新 HL2SDK_CS2 C++ 头文件的项目。
该项目的设计目标是在完全无需人工参与的情况下更新 signatures/offsets/cpp headers。
目前,本项目已可自动更新 CounterStrikeSharp 和 CS2Fixes 的全部 signatures/offsets。
-
安装 uv
-
uv sync -
claude / codex
-
IDA Pro 9.0+
-
idalib(运行
ida_analyze_bin.py的必需项) -
Clang-LLVM(运行
run_cpp_tests.py的必需项)
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。
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_APIKEY、CS2VIBE_LLM_BASEURL、CS2VIBE_LLM_MODEL、CS2VIBE_LLM_TEMPERATURE、CS2VIBE_LLM_EFFORT、CS2VIBE_LLM_FAKE_AS - LLM 流程不会读取
OPENAI_API_KEY、OPENAI_API_BASE、OPENAI_API_MODEL
-
推荐实务中优先使用:纯程序化的预处理脚本 > 基于 LLM_DECOMPILE 的自动化反编译 >
SKILL.md
-
-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_va、insn_disasm、vfunc_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.yamlvcall_finder/14141/g_pNetworkMessages.txt
reference YAML 存放路径:
ida_preprocessor_scripts/references/<module>/<func_name>.<platform>.yaml
准备步骤:
- 确认目标函数已有当前版本 YAML 且包含
func_va,或可通过config.yaml的 symbol name/alias 在 IDA 中定位。 - 运行独立 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"- 检查生成文件:
func_va可信disasm_code非空,且与目标函数语义匹配procedure在可用时应与预期语义一致(Hex-Rays 不可用时允许为空字符串)func_name仅用于确认输出文件对应你请求的规范名,不能单独证明地址解析正确
- 在目标
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
- 生成文件在仓库中的路径:
uv run update_gamedata.py -gamever 14141 [-debug]uv run run_cpp_tests.py -gamever 14141 [-debug] [-fixheader] [-agent=claude/codex/"claude.cmd"/"codex.cmd"] - 使用
-fixheader时,会启动一个 agent 来修复 cpp headers 中的不匹配项(会消耗少量token)
dist/CounterStrikeSharp/config/addons/counterstrikesharp/gamedata/gamedata.json
GameEventManager:在CSS中已废弃。CEntityResourceManifest_AddResource:游戏更新时基本不会改动。
dist/CS2Fixes/gamedata/cs2fixes.games.txt
CCSPlayerPawn_GetMaxSpeed,因为它并不存在于server.dll中。
dist/swiftlys2/plugin_files/gamedata/cs2/core/offsets.jsonc
dist/swiftlys2/plugin_files/gamedata/cs2/core/signatures.jsonc
dist/plugify-plugin-s2sdk/assets/gamedata.jsonc
dist/cs2kz-metamod/gamedata/cs2kz-core.games.txt
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 个符号。
dist/cs2surf/gamedata/cs2surf-core.games.jsonc
- 已跳过 26 个符号。
以 CCSPlayerPawn 为例。
Claude Code:
/create-preprocessor-scripts Create "find-CCSPlayerPawn_vtable" in server.
- 在 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
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".
-
在 IDA 中搜索字符串
"IGameSystem::InitAllSystems",查找该字符串的 xrefs。引用该字符串的函数就是IGameSystem_InitAllSystems。 -
如果还没改名,请将其重命名为
IGameSystem_InitAllSystems。 -
查看
IGameSystem_InitAllSystems开头附近的模式:( i = qword_XXXXXX; i; i = *(_QWORD *)(i + 8) ) -
如果还没改名,将前一步发现的
qword_XXXXXX重命名为IGameSystem_InitAllSystems_pFirst。
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".
以 CGameResourceService_m_pEntitySystem 为例。
-
在 IDA 中搜索字符串
"CGameResourceService::BuildResourceManifest(start)",并查找其 xrefs。 -
xref 应指向一个函数——这就是
CGameResourceService_BuildResourceManifest。如果尚未改名,请将其重命名。
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 会在一个已知函数里定位特定指令,并生成替换字节来修改其运行时行为(例如强制/跳过某分支、NOP 掉某次调用)。目标函数通常应已有对应的 find-SKILL 输出(一般通过
expected_input提供)。 -
务必确保 ida-pro-mcp server 正在运行。
-
对于人类贡献者:当你查找新符号时,应编写新的初始提示词,不要从 README 直接复制粘贴!
以 CCSPlayer_MovementServices_FullWalkMove_SpeedClamp 为例 —— 在 CCSPlayer_MovementServices_FullWalkMove 内把速度限制逻辑对应的 jbe 补丁为无条件 jmp。
- 反编译
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`)
按照 .claude/skills/create-preprocessor-scripts/SKILL.md 中的步骤创建预处理脚本并更新 config.yaml。
处理方式:在 C:\Program Files\IDA Professional 9.0\idalib\python 目录下,以管理员权限运行 python py-activate-idalib.py。
处理方式:尝试 set IDADIR=C:\Program Files\IDA Professional 9.0,或将 IDADIR=C:\Program Files\IDA Professional 9.0 添加到系统环境变量。
@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"