Automated tests are the best tool to fight legacy code.
By having automated tests such as unit tests or behavioral tests, you are able to refactor legacy code effectively with confidence that little can be broken.
Badly written systems often consist of tightly coupled functions. One change to a function in one class may well break a function in a completely different class, leading to a domino effect of more classes being broken until the entire application is broken.
In order to decouple classes and follow practices such as the Single Responsibility Principle, refactoring must be carried out. Any refactoring effort must be sure not to break code elsewhere in an application.
This brings us onto the topic of test coverage: is it a truly meaningful figure?
Alberto Savoia answered this question best in an amusing anecdote he placed online on artima.com; let's take a read:
Early one morning, a programmer asked the great master: "I am ready to write some unit tests. What code coverage...