$npx -y skills add HLND2T/CS2_VibeSignatures --skill find-CNetworkMessages_dtorFind and identify the CNetworkMessages destructor virtual function in CS2 binary using IDA Pro MCP. Use this skill when reverse engineering CS2 networksystem.dll or libnetworksystem.so to locate the CNetworkMessages_dtor vfunc by scanning the last three entries of the CNetworkMes
| 1 | # Find CNetworkMessages_dtor |
| 2 | |
| 3 | Locate `CNetworkMessages_dtor` vfunc in CS2 `networksystem.dll` or `libnetworksystem.so` using IDA Pro MCP tools. |
| 4 | |
| 5 | ## Method |
| 6 | |
| 7 | ### 1. Load CNetworkMessages VTable from YAML |
| 8 | |
| 9 | **ALWAYS** Use SKILL `/get-vtable-from-yaml` with `class_name=CNetworkMessages`. |
| 10 | |
| 11 | If the skill returns an error, **STOP** and report to user. |
| 12 | |
| 13 | Otherwise, extract: |
| 14 | - `vtable_numvfunc` |
| 15 | - `vtable_entries` |
| 16 | |
| 17 | ### 2. Identify Destructor Candidates |
| 18 | |
| 19 | The destructor is located in the last three vtable entries. Check the entries at indices: |
| 20 | |
| 21 | - `vtable_numvfunc - 3` |
| 22 | - `vtable_numvfunc - 2` |
| 23 | - `vtable_numvfunc - 1` |
| 24 | |
| 25 | Read the function addresses from the vtable entries for these three slots. |
| 26 | |
| 27 | ### 3. Decompile and Identify the Destructor |
| 28 | |
| 29 | Decompile all three candidate functions: |
| 30 | |
| 31 | ```text |
| 32 | mcp__ida-pro-mcp__decompile addr="<candidate_1_addr>" |
| 33 | mcp__ida-pro-mcp__decompile addr="<candidate_2_addr>" |
| 34 | mcp__ida-pro-mcp__decompile addr="<candidate_3_addr>" |
| 35 | ``` |
| 36 | |
| 37 | #### Windows (`networksystem.dll`) |
| 38 | |
| 39 | The destructor has this characteristic two-argument pattern: |
| 40 | |
| 41 | ```c |
| 42 | __int64 __fastcall CNetworkMessages_dtor(__int64 a1, char a2) |
| 43 | { |
| 44 | CNetworkMessages_dtor2(a1); |
| 45 | if ( (a2 & 1) != 0 ) |
| 46 | (*(void (__fastcall **)(_QWORD, __int64))(*g_pMemAlloc + 24LL))(g_pMemAlloc, a1); |
| 47 | return a1; |
| 48 | } |
| 49 | ``` |
| 50 | |
| 51 | Key identification rules for Windows: |
| 52 | 1. Takes two parameters: `(__int64 a1, char a2)` (this + flags) |
| 53 | 2. Calls another large destructor function (`CNetworkMessages_dtor2`) with just `a1` |
| 54 | 3. Conditionally frees memory via `g_pMemAlloc` if `(a2 & 1) != 0` |
| 55 | 4. Returns `a1` |
| 56 | |
| 57 | The inner `CNetworkMessages_dtor2` function is a large function that: |
| 58 | - Writes `CNetworkMessages::vftable` back to `*this` as the first operation: `*(_QWORD *)a1 = &CNetworkMessages::vftable;` |
| 59 | - Contains a loop iterating 64 times destroying network message entries |
| 60 | - Calls multiple `CUtlSymbolTable::~CUtlSymbolTable` destructors |
| 61 | - Ends by setting `CConCommandMemberAccessor<CNetworkMessages>::vftable` on multiple member offsets |
| 62 | |
| 63 | #### Linux (`libnetworksystem.so`) |
| 64 | |
| 65 | The destructor has this characteristic single-argument pattern: |
| 66 | |
| 67 | ```c |
| 68 | __int64 __fastcall CNetworkMessages_dtor(__int64 a1) |
| 69 | { |
| 70 | ... |
| 71 | *(_QWORD *)a1 = CNetworkMessages_vtable; |
| 72 | ... |
| 73 | } |
| 74 | ``` |
| 75 | |
| 76 | Key identification rules for Linux: |
| 77 | 1. Takes one parameter: `(__int64 a1)` (this only) |
| 78 | 2. Writes `CNetworkMessages_vtable` (or `CNetworkMessages::vftable`) to `*(_QWORD *)a1` as the first substantive operation |
| 79 | 3. Is a very large function (hundreds of lines) that performs extensive cleanup |
| 80 | 4. Contains a loop destroying network message entries with `g_pMemAlloc` free calls |
| 81 | 5. Ends by writing `CConCommandMemberAccessor` vtable pointers and conditionally calling unregister functions |
| 82 | |
| 83 | ### 4. Confirm the Destructor |
| 84 | |
| 85 | The correct function among the three candidates is the one that matches the patterns above. Specifically: |
| 86 | |
| 87 | - **Windows**: Look for the small wrapper that calls a large inner destructor and conditionally frees `this` |
| 88 | - **Linux**: Look for the very large function that starts by writing the vtable pointer to `*this` |
| 89 | |
| 90 | If none of the three candidates match, **STOP** and report to user. |
| 91 | |
| 92 | ### 5. Generate Function Signature |
| 93 | |
| 94 | **ALWAYS** Use SKILL `/generate-signature-for-function` with `addr=<dtor_func_addr>` to generate a robust and unique `func_sig` for `CNetworkMessages_dtor`. |
| 95 | |
| 96 | Use the returned validated `func_sig` in the next step. |
| 97 | |
| 98 | ### 6. Write IDA Analysis Output as YAML |
| 99 | |
| 100 | **ALWAYS** Use SKILL `/write-vfunc-as-yaml` to write the analysis results. |
| 101 | |
| 102 | Required parameters: |
| 103 | - `func_name`: `CNetworkMessages_dtor` |
| 104 | - `func_addr`: `<dtor_func_addr>` |
| 105 | - `func_sig`: The validated signature from step 5 |
| 106 | - `vfunc_sig`: `None` |
| 107 | |
| 108 | VTable parameters: |
| 109 | - `vtable_name`: `CNetworkMessages` |
| 110 | - `vfunc_offset`: `<target_vfunc_offset>` in hex (computed as `vfunc_index * 8`) |
| 111 | - `vfunc_index`: `<target_vfunc_index>` |
| 112 | |
| 113 | ## Function Characteristics |
| 114 | |
| 115 | - **Purpose**: Destructor for the `CNetworkMessages` singleton; tears down all registered network messages, symbol tables, and member structures |
| 116 | - **Binary**: `networksystem.dll` / `libnetworksystem.so` |
| 117 | - **Parameters (Windows)**: `(this, char flags)` where `flags & 1` controls whether to free the object's memory |
| 118 | - **Parameters (Linux)**: `(this)` only |
| 119 | - **Return value**: `this` pointer (Windows) / varies (Linux) |
| 120 | |
| 121 | ## Discovery Strategy |
| 122 | |
| 123 | 1. Load the existing `CNetworkMessages_vtable` YAML to get the full vtable |
| 124 | 2. Scan the last three vtable entries (`numvfunc - 3` through `numvfunc - 1`) as destructor candidates |
| 125 | 3. Decompile each candidate and match against the destructor patterns: |
| 126 | - Windows: small wrapper calling inner dtor |