The extreme case is programs for which the entire platform has been abandoned - e.g. DOS (including TSRs), old Windows, old MacOS (including desk accessories). There's a whole "abandonware" community devoted to preserving games that have rotted this way, usually relying on emulation to keep them from being forgotten entirely. There are various file compression/encryption/annotation utilities that have become unusable because they relied on deprecated Windows APIs. Various sound/video hacks on Linux have died as those subsystems remain in constant flux. In my own work as a Gluster maintainer, several pieces such as Java/Python or monitoring APIs have rotted away as those APIs changed. It usually takes a long time for a large program to rot away completely, but individual pieces can become non-functional long before then.
I think the point OP is making is that there is plenty of bad software out there that (as a result of a combination of incompetence, scope creep, bad decisions, and short timelines) just isn't resilient, testable, and single use anymore. As long as the code is isolated enough, it's fairly easy from a technical standpoint to replace/refactor.
Ossified code is code that isn't isolated, but tightly bound to several other components. This means that you can't swap it out without making the exact same architectural mistakes. This means you basically need to start over from scratch, which is a much harder and broader problem.
there is an alternate path for your ossified code, but its really costly. idk if it has a cute name.
if there aren't system/integration tests - write system tests. you have to be pretty thorough.
have a long and involved discussion about what the new thing is going to be. go through all the frustrations with the current code base. convince yourself at the end that its going to be worth it, because the cost is going to be high. ideally the new version will open up new capabilities that just weren't possible before.
find a cut in the dependency graph. you're going to rewrite the code on one side and leave the other side untouched. ideally that cut will be small-ish and contain some particularly broken stuff that you'd like to get rid of as soon as possible. unfortunately there may not be a small cut that makes sense :-(
build a shim between the old model and the new model across the cut. this shim is only going to last as long as the old code on the other side. this shim might be involved and a total waste of effort. suck it up or look for a different cut.
replace the code on the new side and test against your suite. if its not really that exhaustive, expect a rash of bug reports. run through some kind of soft deployment. if its a request/response kind of thing consider forking your production traffic and comparing the results against the old code base.
repeat until golden brown.
this overall process also can fail. often because of poor test coverage, and more likely because you haven't adequately communicated the scope of the undertaking and its absolute necessity to the rest of the engineering organization and the business as a whole.
however, if you make it through, you've avoided the giant speed bump that comes at the end of the rewrite, and you've been able to fold in new feature and bugfix work along the way.