I think a special-purpose method (the approach taken by
TPersistent) might be the only solid option.
Sure, you could do a simple bitwise copy:
function TObject.Clone(): TObject;
begin
TObject(Result) := NewInstance();
Move(Pointer(Self)^, Pointer(Result)^, InstanceSize());
end;
But this will mess up managed types (strings, arrays etc. will cause use-after-free due to the reference count being too low) and, in the case of references (pointers, class instances) only copies the pointer value (no deep copy).
Even if you handled managed types correctly you'd still have to decide whether to deep-copy references, which
might still be
somewhat doable with classes (but requiring prior knowledge of deep vs. shallow types) but is completely unfeasible for opaque pointers.