$npx -y skills add HLND2T/CS2_VibeSignatures --skill find-CCSPlayer_MovementServices_FullWalkMove_SpeedClampFind and identify the velocity clamping branch inside CCSPlayer_MovementServices_FullWalkMove in CS2 binary using IDA Pro MCP, then generate a patch signature to disable it. Use this skill when reverse engineering CS2 server.dll or libserver.so to locate and patch the speed-clamp
| 1 | # CCSPlayer_MovementServices_FullWalkMove_SpeedClamp Patch Workflow |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Locate the velocity clamping branch inside `CCSPlayer_MovementServices_FullWalkMove` and generate a patch that converts the conditional jump into an unconditional jump, making the speed-clamp code a dead path. |
| 6 | |
| 7 | The target code pattern in pseudocode: |
| 8 | ```c |
| 9 | v20 = (float)((float)(v16 * v16) + (float)(v19 * v19)) + (float)(v17 * v17); |
| 10 | if ( v20 > (float)(v18 * v18) ) // <-- patch target: disable this branch |
| 11 | { |
| 12 | // velocity clamping logic: scale velocity down to maxspeed |
| 13 | v21 = fsqrt(v20); |
| 14 | v22 = v18 / v21; |
| 15 | *(float *)(a2 + 56) = ... * v22; |
| 16 | *(float *)(a2 + 60) = ... * v22; |
| 17 | *(float *)(a2 + 64) = ... * v22; |
| 18 | ... |
| 19 | } |
| 20 | ``` |
| 21 | |
| 22 | In assembly, this is a `comiss` + `jbe` (or `jbe short`) pair. The `jbe` skips the clamping block when velocity <= maxspeed^2. Patching `jbe` to `jmp` makes it always skip, disabling the clamp entirely. |
| 23 | |
| 24 | ## Prerequisites |
| 25 | |
| 26 | - `CCSPlayer_MovementServices_FullWalkMove` must already be identified. Use SKILL `/get-func-from-yaml` with `func_name=CCSPlayer_MovementServices_FullWalkMove` to load its address. If YAML does not exist, run SKILL `/find-CCSPlayer_MovementServices_FullWalkMove-AND-CCSPlayer_MovementServices_CheckVelocity-AND-CCSPlayer_MovementServices_WaterMove` first. |
| 27 | |
| 28 | ## Location Steps |
| 29 | |
| 30 | ### 1. Get FullWalkMove Function Address |
| 31 | |
| 32 | **ALWAYS** Use SKILL `/get-func-from-yaml` with `func_name=CCSPlayer_MovementServices_FullWalkMove`. |
| 33 | |
| 34 | If the skill returns an error, stop and report to user. |
| 35 | |
| 36 | ### 2. Decompile and Locate the Speed Clamp Pattern |
| 37 | |
| 38 | Decompile the function: |
| 39 | |
| 40 | ``` |
| 41 | mcp__ida-pro-mcp__decompile(addr="<func_va>") |
| 42 | ``` |
| 43 | |
| 44 | In the decompiled output, search for the velocity clamping pattern. The key indicators are: |
| 45 | - A sum-of-squares computation: `(x*x) + (y*y) + (z*z)` stored in a variable (e.g., `v20`) |
| 46 | - Compared against another float squared: `v20 > (float)(v18 * v18)` |
| 47 | - Inside the if-block: `fsqrt`, division, and writes to `a2+56`, `a2+60`, `a2+64` (velocity vector) |
| 48 | |
| 49 | Note the address annotation on the comparison line (e.g., `/*0x180a00e28*/` or similar). |
| 50 | |
| 51 | ### 3. Disassemble Around the Comparison |
| 52 | |
| 53 | Disassemble the function starting from slightly before the annotated address to find the exact `comiss` + `jbe`/`jbe short` instruction pair: |
| 54 | |
| 55 | ``` |
| 56 | mcp__ida-pro-mcp__disasm(addr="<func_va>", offset=<estimated_offset>, max_instructions=30) |
| 57 | ``` |
| 58 | |
| 59 | Look for this assembly pattern: |
| 60 | ```asm |
| 61 | addss xmm2, xmm1 ; v20 = sum of squares |
| 62 | comiss xmm2, xmm0 ; compare v20 vs v18*v18 |
| 63 | jbe loc_XXXXXXXX ; skip clamp block if v20 <= v18*v18 |
| 64 | ``` |
| 65 | |
| 66 | Record: |
| 67 | - **patch_va**: Address of the `jbe` instruction |
| 68 | - **jump_target**: The target address of the `jbe` (the `loc_XXXXXXXX` label) |
| 69 | |
| 70 | ### 4. Determine Patch Bytes |
| 71 | |
| 72 | Read the original bytes of the `jbe` instruction: |
| 73 | |
| 74 | ``` |
| 75 | mcp__ida-pro-mcp__get_bytes(regions={"addr": "<patch_va>", "size": 6}) |
| 76 | ``` |
| 77 | |
| 78 | Determine the patch based on the instruction encoding: |
| 79 | |
| 80 | **Case A: Near `jbe` (`0F 86 rel32` — 6 bytes)** |
| 81 | - `patch_bytes` = `E9 <new_rel32_le> 90` |
| 82 | - Compute: `new_rel32 = jump_target - (patch_va + 5)` |
| 83 | |
| 84 | **Case B: Short `jbe` (`76 rel8` — 2 bytes)** |
| 85 | - `patch_bytes` = `EB <rel8>` |
| 86 | - The `rel8` stays the same (same target, `jmp short` uses same displacement encoding as `jbe short`) |
| 87 | |
| 88 | ### 5. Generate Patch Signature |
| 89 | |
| 90 | **ALWAYS** Use SKILL `/generate-signature-for-patch` to generate and validate the signature. |
| 91 | |
| 92 | Required context for the skill: |
| 93 | - `func_name`: `CCSPlayer_MovementServices_FullWalkMove` |
| 94 | - `func_va`: From step 1 |
| 95 | - `patch_va`: Address of the `jbe` instruction from step 3 |
| 96 | - `original_instruction`: e.g., `jbe loc_180A00EE4` |
| 97 | - `patched_instruction`: e.g., `jmp loc_180A00EE4` |
| 98 | - `description`: `Disable velocity clamping in FullWalkMove - patch conditional jbe to unconditional jmp to skip the speed clamping if-branch` |
| 99 | |
| 100 | ### 6. Write YAML Output |
| 101 | |
| 102 | **ALWAYS** Use SKILL `/write-patch-as-yaml` to persist the results. |
| 103 | |
| 104 | Required parameters: |
| 105 | - `patch_name`: `CCSPlayer_MovementServices_FullWalkMove_SpeedClamp` |
| 106 | - `patch_sig`: The validated signature from step 5 |
| 107 | - `patch_bytes`: The computed patch bytes from step 4 |
| 108 | - `patch_sig_disp`: From step 5 result (omit if 0) |
| 109 | |
| 110 | ## Output YAML Files |
| 111 | |
| 112 | - `CCSPlayer_MovementServices_FullWalkMove_SpeedClamp.windows.yaml` |
| 113 | - `CCSPlayer_MovementServices_FullWalkMove_SpeedClamp.linux.yaml` |