Skip to content

Release v0.1.14

Latest

Choose a tag to compare

@KernelErr KernelErr released this 02 Aug 08:06
f47e3cd

v0.1.14

Rename metadata symbols over MCP

New tool rename_symbol_by_token — the 32nd — renames symbols in the loaded assembly's metadata. Until now the extension could read an obfuscated assembly (decompile, xref, string/constant search) and patch its behaviour (IL edits, force_return), but the names stayed unreadable. An AI can now write its understanding back into the assembly itself: work out that class a is the save manager, then rename it to SaveManager.

One tool covers every source-level symbol, addressed by metadata token:

target_kind Target
type, class, enum, interface, struct, delegate TypeDef (the specific kinds also assert the type really is one)
method, field, property, event Members
parameter, generic_parameter Param / GenericParam rows
enum_member, enum_members One enum constant, or a whole value-mapped batch
{ "assembly_name": "Assembly-CSharp", "target_kind": "class",
  "token": "0x02000123", "new_name": "SaveManager" }

Tokens come straight from get_type_info / list_types / search_types / list_methods / search_members — all of which now report the matching TypeDef, MethodDef, FieldDef, Param and GenericParam tokens — in decimal or 0x hex.

Bulk enum renaming by value. Obfuscators scramble member names but cannot change their constants, so enum_members maps names by numeric value rather than by order or current name:

{ "target_kind": "enum_members", "token": "0x02000456",
  "members": [ { "name": "EvaluationStandard", "value": 0 },
               { "name": "RegisteredPro",      "value": 1 } ] }

References are kept consistent. Renaming a symbol is not a string edit: a call into a closed generic type (Owner<int>.Echo) is encoded as a MemberRef, not as a direct definition operand, so a naive rename produces an assembly that saves cleanly and then fails at runtime. Matching TypeRef/MemberRef rows in the same module are rewritten alongside the definition, and the result reports how many were touched. Open decompiler tabs refresh so the new name is visible immediately.

Refused before anything is modified: a token whose table doesn't match target_kind, a name that collides with an existing sibling, constructors (.ctor / .cctor), the <Module> pseudo-type, an enum's value__ backing field, and an incomplete enum_members mapping. If a rename throws part-way, the original names are restored, so a failure never leaves a half-renamed module.

Two limits worth knowing (stated in the tool description and every result):

  • No revert. There is no counterpart to revert_method_il — undo by renaming back.
  • Same module only. Other loaded assemblies referencing the old name are not rewritten and will stop binding once the renamed module is saved. This is inherent to renaming; dnSpy's own editor behaves the same way.

Renames are in-memory — call save_assembly to persist, as with IL edits.

Testing

The end-to-end suite grew to 228 assertions (0 failures), covering all 14 target_kinds. Beyond checking that names changed, it saves the assembly and executes the renamed members out of the saved DLL — including calls that resolve through rewritten MemberRef rows — and asserts that every guard above refuses its case and leaves the target unchanged.

Thanks to @Chenj168 (#23).