Install
$ agentstack add skill-hlnd2t-cs2-vibesignatures-get-vtable-address ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Get VTable address and size
Find a class's virtual function table by class name. Get its address and size in a single step.
Prerequisites
- ClassName
Method
1. Get vtable address and size
Run this single Python script using mcp__ida-pro-mcp__py_eval, replacing ` with the actual class name (e.g., CGameRules, CCSPlayer_ItemServices`):
mcp__ida-pro-mcp__py_eval code="""
import ida_bytes, ida_name, idaapi, idautils, ida_segment
class_name = ""
ptr_size = 8 if idaapi.inf_is_64bit() else 4
vtable_start = None # address of first vfunc pointer
vtable_symbol = ""
is_linux = False
method = ""
# ── Direct symbol lookup ──────────────────────────────────────────────
# Windows: ??_7ClassName@@6B@
win_name = f"??_7{class_name}@@6B@"
addr = ida_name.get_name_ea(idaapi.BADADDR, win_name)
if addr != idaapi.BADADDR:
vtable_start = addr
vtable_symbol = win_name
is_linux = False
method = "direct"
# Linux: _ZTVClassName (e.g. _ZTV10CGameRules)
if vtable_start is None:
linux_name = f"_ZTV{len(class_name)}{class_name}"
addr = ida_name.get_name_ea(idaapi.BADADDR, linux_name)
if addr != idaapi.BADADDR:
vtable_start = addr + 0x10 # skip offset-to-top + typeinfo ptr
vtable_symbol = f"{linux_name} + 0x10"
is_linux = True
method = "direct"
# ── RTTI / TypeInfo fallback ──────────────────────────────────────────
# Windows: ??_R4ClassName@@6B@ (Complete Object Locator)
if vtable_start is None:
col_name = f"??_R4{class_name}@@6B@"
col_addr = ida_name.get_name_ea(idaapi.BADADDR, col_name)
if col_addr != idaapi.BADADDR:
is_linux = False
rdata_seg = ida_segment.get_segm_by_name(".rdata")
for ref in idautils.DataRefsTo(col_addr):
if rdata_seg and not (rdata_seg.start_ea ClassName (typeinfo)
if vtable_start is None:
ti_name = f"_ZTI{len(class_name)}{class_name}"
ti_addr = ida_name.get_name_ea(idaapi.BADADDR, ti_name)
if ti_addr != idaapi.BADADDR:
is_linux = True
for ref in idautils.DataRefsTo(ti_addr):
ott = ida_bytes.get_qword(ref - ptr_size) if ptr_size == 8 else ida_bytes.get_dword(ref - ptr_size)
if ott == 0:
vtable_start = ref + ptr_size
ztv_addr = ref - ptr_size
ztv_name = ida_name.get_name(ztv_addr) or f"_ZTV{len(class_name)}{class_name}"
vtable_symbol = f"{ztv_name} + 0x10"
method = "rtti_fallback"
break
assert vtable_start is not None, f"Cannot find vtable for {class_name}"
# ── Count virtual functions ───────────────────────────────────────────
count = 0
for i in range(1000):
ea = vtable_start + i * ptr_size
# Linux: stop at next vtable / typeinfo symbol boundary
if is_linux and i > 0:
name = ida_name.get_name(ea)
if name and (name.startswith("_ZTV") or name.startswith("_ZTI")):
break
ptr_value = ida_bytes.get_qword(ea) if ptr_size == 8 else ida_bytes.get_dword(ea)
if ptr_value == 0:
if is_linux:
count += 1 # NULL = pure virtual placeholder
continue
else:
break # Windows: NULL = vtable end
if ptr_value == 0xFFFFFFFFFFFFFFFF:
break
func = idaapi.get_func(ptr_value)
if func is not None:
count += 1
continue
flags = ida_bytes.get_full_flags(ptr_value)
if ida_bytes.is_code(flags):
count += 1
continue
break # not a valid function pointer
size_in_bytes = count * ptr_size
print(f"vtable_class: {class_name}")
print(f"vtable_symbol: {vtable_symbol}")
print(f"vtable_va: {hex(vtable_start)}")
print(f"vtable_size: {hex(size_in_bytes)}")
print(f"vtable_numvfuncs: {count}")
print(f"method: {method}")
"""
Lookup order:
- Direct symbol:
??_7ClassName@@6B@(Win) /_ZTVClassName(Linux) - RTTI fallback:
??_R4ClassName@@6B@→ DataRefsTo → vtable (Win) /_ZTIClassName→ DataRefsTo with offset-to-top==0 → vtable (Linux)
Platform-specific vfunc counting:
- Linux (
_ZTVprefix): NULL entries = pure virtual placeholders (keep counting); stops at next_ZTV/_ZTIsymbol - Windows (
??_7prefix): NULL = vtable end; stops immediately
2. Continue with Unfinished Tasks
If we are called by a task from a task list / parent SKILL, restore and continue with the unfinished tasks.
Output
The skill returns:
- vtable_class: The class name
- vtable_symbol: The IDA symbol. e.g.
??_7CGameRules@@6B@or_ZTV10CGameRules + 0x10 - vtable_va: The start address of the vtable (first vfunc pointer)
- vtable_size: Total size of the vtable in bytes
- vtable_numvfuncs: Count of virtual function entries in the vtable
- method: How the vtable was found (
directorrtti_fallback)
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: HLND2T
- Source: HLND2T/CS2_VibeSignatures
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.