AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Create Preprocessor Scripts

skill-hlnd2t-cs2-vibesignatures-create-preprocessor-scripts · by HLND2T

|

No reviews yet
0 installs
37 views
0.0% view→install

Install

$ agentstack add skill-hlnd2t-cs2-vibesignatures-create-preprocessor-scripts

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Dangerous shell/eval execution.

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution Used

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.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Create Preprocessor Scripts? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Create Preprocessor Scripts from Scratch

Create an ida_preprocessor_scripts/find-XXXX.py preprocessor script and add the corresponding config.yaml entries for a newly requested function, vtable, or struct member offset.

When to Use

  • A GitHub issue or user instruction requests adding support for finding a new function/symbol
  • No existing .claude/skills/find-XXXX/SKILL.md needs conversion (for that, use convert-finder-skill-to-preprocessor-scripts)

Inputs

The user or issue will provide some or all of:

| Field | Description | Example | |-------|-------------|---------| | Function name(s) | Target symbol(s) to find | CPlayer_MovementServices_PlayWaterStepSound | | Module | Which DLL/SO the function lives in | server, engine, networksystem, client | | Category | Symbol type | func, vfunc, structmember, patch, vtable | | xrefstrings | Debug strings for xref-based discovery | "CT_Water.StepLeft" | | xrefgvs | Global variable VA (e.g. vtable address) to find functions that reference it | vtable VA from SomeClass_vtable.{platform}.yaml | | xreffuncs | Known callee function name to find its callers | "CPlayerCommandQueue_ctor" | | Predecessor function | Function to decompile for LLMDECOMPILE patterns | CBaseEntity_TakeDamageOld | | VTable class | Class owning the vtable (for vfuncs) | CBasePlayerPawn | | Desired YAML fields | Which fields the output YAML needs | func_name, func_sig, func_va, func_rva, func_size | | Dependencies | Input YAMLs this skill depends on | CCSPlayer_MovementServices_vtable.{platform}.yaml | | Aliases | Alternative names for the symbol | CPlayer_MovementServices::PlayWaterStepSound |

Overview

Eleven preprocessor patterns exist. The discovery method and target type determine which to use:

| Pattern | Discovery Method | Has FUNCXREFS | Has LLMDECOMPILE | Has INHERITVFUNCS | Has FUNCVTABLERELATIONS | preprocessskill has llmconfig | |---------|-----------------|-----------------|---------------------|--------------------|---------------------------|-------------------------------| | A -- Regular function via xref strings | find_regex + xrefs_to on debug strings | Yes | No | No | No | No | | B -- Virtual function via xref strings | Same as A, but function is in a vtable | Yes | No | No | Yes | No | | C -- Virtual function via LLMDECOMPILE | Decompile a known predecessor function, identify vfunc call offsets | No | Yes | No | Yes | Yes | | D -- Regular function via LLMDECOMPILE | Decompile a known predecessor function, identify direct call targets | No | Yes | No | No | Yes | | E -- Struct member offset via LLMDECOMPILE | Decompile a known predecessor function, identify struct field access offsets | No | Yes | No | No | Yes | | F -- Virtual function via INHERITVFUNCS | Inherit vtable slot index from a known base-class vfunc, look up same slot in derived-class vtable (standard); or slot-only mode for abstract/interface vfuncs where only offset/index is needed | No | No | Yes | No | No | | G -- ConCommand handler function | Find the handler callback registered via RegisterConCommand by matching command name and help string | No (uses COMMANDNAME/HELPSTRING) | No | No | No | No | | H -- Secondary (ordinal) vtable | Locate a class's secondary vtable via mangled symbol (Windows) or offset-to-top (Linux) | No | No | No | No | No | | I -- Interface vfunc offset via thunk instruction walk | Walk a known concrete-class thunk via py_eval + idaapi.decode_insn, extract jmp [reg+disp] displacement as vfuncoffset | No | No | No | No | No | | J -- IGameSystem vfunc via dispatch scan | Scan IGameSystem_DispatchCall(idx, callback, ...) call sites in a known predecessor; map targets by scan/index order using _igamesystem_dispatch_common | No | No | No | No | No | | K -- IGameSystem vfunc via slot dispatch scan | Walk an IGameSystem_Loop*AllSystems dispatcher function body; extract [rax+offset] vtable call displacements via _igamesystem_slot_dispatch_common; output is slot-only (no func_sig) | No | No | No | No | No |

Additionally, struct member offsets can be mixed into any pattern as a secondary target (see "Struct Member Mixin" section below).


Step 1: Determine the Pattern

From the user's input, determine:

  1. Is the target a function, vfunc, or struct member offset?
  • Has xref_strings + category func -> Pattern A
  • Has xref_strings + category vfunc -> Pattern B
  • Has xref_gvs (vtable VA from a vtable YAML) + category func -> Pattern A with dynamic FUNCXREFS (read vtable VA at runtime; see "Dynamic FUNCXREFS via xref_gvs" note)
  • Has xref_gvs (vtable VA from a vtable YAML) + category vfunc -> Pattern B with dynamic FUNC_XREFS
  • Has xref_funcs (known callee function name) + category func -> Pattern A (static FUNCXREFS; see "xreffuncs: finding callers of a known function" note)
  • Has xref_funcs (known callee function name) + category vfunc -> Pattern B (static FUNC_XREFS)
  • Has predecessor function + category vfunc -> Pattern C (vfunc_sig is ALWAYS required in GENERATE_YAML_DESIRED_FIELDS -- see "vfunc_sig is MANDATORY for Pattern C" note below)
  • Has predecessor function + category func -> Pattern D
  • Has predecessor function + category structmember -> Pattern E
  • Has base vfunc name + category vfunc (derived-class override of known base vfunc) -> Pattern F
  • If the target is an abstract/interface vfunc (no real function body, only vfunc_offset/vfunc_index needed) -> use Pattern F slot-only: generate_func_sig=False, desired fields = {func_name, vtable_name, vfunc_offset, vfunc_index}, NO vtable YAML required for the interface class
  • Has COMMAND_NAME + HELP_STRING (ConCommand handler callback) -> Pattern G
  • Has mangled vtable symbol / offset-to-top + category vtable (secondary vtable for a class) -> Pattern H
  • Target is an interface vfunc offset with no feasible func_sig/vfunc_sig, and the offset can be read from a concrete-class thunk's jmp [reg+disp] instruction -> Pattern I
  • Target is an IGameSystem vfunc visible as the callback argument to IGameSystem_DispatchCall(...) in a known predecessor's decompile -> Pattern J
  • Target is an IGameSystem abstract vfunc (slot-only output: func_name, vtable_name, vfunc_offset, vfunc_index; no func_sig) dispatched by a known IGameSystem_Loop*AllSystems function that iterates all game systems via vtable; the dispatcher's output YAML (func_va) is already available -> Pattern K
  1. Do xref strings differ between Windows and Linux? If yes, use platform-specific FUNC_XREFS_WINDOWS / FUNC_XREFS_LINUX variant.
  1. Are there multiple functions? If they share the same discovery method and starting point, put them in the same script with -AND- in the name. Otherwise, split into separate scripts.

CRITICAL -- LLMDECOMPILE dependency chains: When LLMDECOMPILE targets form a chain (FuncA -> FuncB -> FuncC, where each is the predecessor of the next), they MUST be in separate scripts -- one script per link in the chain. A single script CANNOT handle chained LLMDECOMPILE predecessors because the LLMDECOMPILE fallback resolves the predecessor's address from its output YAML (func_va field), and within a single script run the predecessor's output YAML doesn't exist yet. The IDA name-lookup fallback also fails because the predecessor wasn't renamed yet.


Step 2: Create the Preprocessor Script

Script location: ida_preprocessor_scripts/find-{skill_name}.py

The filename MUST match the name field in config.yaml skill entry.

Read the reference for your chosen pattern:

  • [Pattern A -- Regular function via xref strings](references/pattern-A.md)
  • [Pattern B -- Virtual function via xref strings](references/pattern-B.md)
  • [Pattern C -- Virtual function via LLM_DECOMPILE](references/pattern-C.md)
  • [Pattern D -- Regular function via LLM_DECOMPILE](references/pattern-D.md)
  • [Pattern E -- Struct member offset via LLM_DECOMPILE](references/pattern-E.md)
  • [Pattern F -- Virtual function via INHERIT_VFUNCS](references/pattern-F.md) (standard + slot-only variant)
  • [Pattern G -- ConCommand handler function](references/pattern-G.md)
  • [Pattern H -- Secondary (ordinal) vtable](references/pattern-H.md)
  • [Pattern I -- Interface vfunc offset via thunk walk](references/pattern-I.md)
  • [Pattern J -- IGameSystem vfunc via dispatch scan](references/pattern-J.md)

Cross-Cutting Notes

FULLMATCH: Prefix for Xref Strings (Patterns A & B)

When the xref string is short or generic (e.g. "Precache", "userid", "team"), use the FULLMATCH: prefix to require exact string matching instead of substring matching. Without it, "Precache" would match "PrecacheModel", "PrecacheSound", etc.

FUNC_XREFS = [
    {
        "func_name": "CEntityInstance_Precache",
        "xref_strings": [
            "FULLMATCH:Precache",  # Only matches the exact string "Precache"
        ],
        "xref_gvs": [], "xref_signatures": [], "xref_funcs": [],
        "exclude_funcs": [], "exclude_strings": [], "exclude_gvs": [], "exclude_signatures": [],
    },
]
Dynamic FUNC_XREFS via xref_gvs (vtable VA)

When the target function is the constructor (or any other function that references a class's vtable), use xref_gvs with the vtable's virtual address. Because the vtable VA is only known after IDA analysis, it cannot be hardcoded -- it must be read from the vtable's output YAML at runtime.

This requires a custom preprocess_skill that:

  1. Reads vtable_va from {VtableClass}_vtable.{platform}.yaml in new_binary_dir
  2. Builds func_xrefs dynamically with the VA in xref_gvs
  3. Passes the dynamic list to preprocess_common_skill
import os
try:
    import yaml
except ImportError:
    yaml = None

def _read_vtable_va(yaml_path):
    try:
        with open(yaml_path, "r", encoding="utf-8") as f:
            data = yaml.safe_load(f)
        if isinstance(data, dict):
            va = data.get("vtable_va")
            if va:
                return str(va)
    except Exception:
        pass
    return None

async def preprocess_skill(
    session, skill_name, expected_outputs, old_yaml_map,
    new_binary_dir, platform, image_base, debug=False,
):
    vtable_yaml_path = os.path.join(new_binary_dir, f"SomeClass_vtable.{platform}.yaml")
    vtable_va = _read_vtable_va(vtable_yaml_path)
    if not vtable_va:
        if debug:
            print("    Preprocess: SomeClass_vtable vtable_va not found, cannot resolve xref_gvs")
        return False

    func_xrefs = [
        {
            "func_name": "SomeClass_ctor",
            "xref_strings": [],
            "xref_gvs": [str(vtable_va)],
            "xref_signatures": [],
            "xref_funcs": [],
            "exclude_funcs": [],
            "exclude_strings": [],
            "exclude_gvs": [],
            "exclude_signatures": [],
        },
    ]
    return await preprocess_common_skill(
        session=session,
        expected_outputs=expected_outputs,
        old_yaml_map=old_yaml_map,
        new_binary_dir=new_binary_dir,
        platform=platform,
        image_base=image_base,
        func_names=TARGET_FUNCTION_NAMES,
        func_xrefs=func_xrefs,
        generate_yaml_desired_fields=GENERATE_YAML_DESIRED_FIELDS,
        debug=debug,
    )

config.yaml expected_input: must include the vtable YAML so it is guaranteed to be resolved before this script runs.

Multiple xrefs / exclude_signatures: If more than one function references the vtable (e.g. constructor + destructor), the intersection yields >1 result and the skill fails. Use exclude_signatures to exclude the unwanted function(s). If the ambiguity is platform-specific, make the exclusion conditional:

exclude_signatures = ["66 83 ?? FF"] if platform == "linux" else []

To find the right bytes to exclude: look up the two candidate addresses in IDA, read the first ~4 bytes of the function to exclude, and use those as the exclude_signatures pattern with ?? wildcards where needed.

xref_funcs: Finding Callers of a Known Function (Patterns A & B)

When the target function is discoverable as a caller of another already-known function, use xref_funcs with the callee's name. Unlike xref_gvs, the function name is available at script-write time, so FUNC_XREFS can be a static module-level constant -- no dynamic building required.

FUNC_XREFS = [
    {
        "func_name": "TargetFunc",
        "xref_strings": [],
        "xref_gvs": [],
        "xref_signatures": [],
        "xref_funcs": ["KnownCalleeFunc"],   # callee that the target calls
        "exclude_funcs": [],
        "exclude_strings": [],
        "exclude_gvs": [],
        "exclude_signatures": [],
    },
]

config.yaml expected_input: include the callee's output YAML to guarantee it is renamed in IDA before this script runs (the name lookup requires the rename to have happened):

        expected_input:
          - KnownCalleeFunc.{platform}.yaml        # ensures callee is renamed first
          - TargetClass_vtable.{platform}.yaml     # if target is a vfunc (Pattern B)
Struct Member Mixin (for any pattern)

Struct member offsets can also be mixed into a function-finding script when they are discovered from the same function via signature matching (not LLM_DECOMPILE). Add TARGET_STRUCT_MEMBER_NAMES alongside TARGET_FUNCTION_NAMES and pass struct_member_names= to preprocess_common_skill:

TARGET_FUNCTION_NAMES = [
    "SomeFunction",
]

TARGET_STRUCT_MEMBER_NAMES = [
    "SomeStruct_m_someField",
]

GENERATE_YAML_DESIRED_FIELDS = [
    ("SomeFunction", ["func_name", "func_sig", "func_va", "func_rva", "func_size"]),
    ("SomeStruct_m_someField", ["struct_name", "member_name", "offset", "size", "offset_sig", "offset_sig_disp"]),
]

# In preprocess_skill:
    return await preprocess_common_skill(
        ...
        func_names=TARGET_FUNCTION_NAMES,
        struct_member_names=TARGET_STRUCT_MEMBER_NAMES,
        ...
    )
CRITICAL -- FUNCVTABLERELATIONS and vfunc fields

FUNC_VTABLE_RELATIONS is required for ANY target whose GENERATE_YAML_DESIRED_FIELDS includes vtable_name or vfunc_sig -- not just Pattern B and C. Without it, the LLM_DECOMPILE slot-only fallback fails with "slot-only fallback missing vtable_name" and the entire skill fails.

This applies even when:

  • The target is a vfunc call-site offset (e.g. call [rax+128h]) rather than an actual function body in a vtable
  • No vtable YAML exists for that class in config.yaml (no expected_input for the vtable needed)
  • The script also finds non-vfunc targets (global variables, struct offsets) alongside the vfunc target

The vtable_name from FUNC_VTABLE_RELATIONS is used as metadata written to the output YAML -- it does NOT require an actual vtable lookup. For example, ("IGameTypes_CreateWorkshopMapGroup", "IGameTypes") provides the vtable class name IGameTypes even though no IGameTypes_vtable.{platform}.yaml exists.

Rule of thumb: If any field in GENERATE_YAML_DESIRED_FIELDS starts with vfunc_ or equals vtable_name, the target MUST have an entry in FUNC_VTABLE_RELATIONS.

CRITICAL -- vfunc_sig is MANDATORY for Pattern C (vfunc via LLM_DECOMPILE)

For ANY vfunc discovered via LLM_DECOMPILE (Pattern C), GENERATE_YAML_DESIRED_FIELDS MUST include vfunc_sig. This is non-negotiable -- the slot index alone is not stable across binary updates without a signature anchor on the actual vfunc body.

This rule applies to BOTH variants:

  • Standard Pattern C (also a downstream predecessor): `funcname, funcva, func_rva, f

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.