There's a good book on this subject by Michael Feathers, but the single best trick I've ever read for getting control of a legacy code base comes from Jim Weirich's blog:
...dealing with legacy code means that the code is already written and the test-first approach won’t work. That’s ok, I have a little trick that I use. Just comment out the bodies of all the methods in the class you are about to test. Then write the tests that force you to uncomment the code. Just uncomment only enought to get the tests to pass, don’t uncomment anything you don’t have to. You have enough tests when all the code has been uncommented. The technique is almost as good as doing real test-first.
Obviously this technique can also have the side effect of uncovering code which does nothing, which, in my experience, is a very common problem with legacy code. There's frequently code in there which simply does nothing at all. If you comment everything out, and only uncomment as you write tests, and find yourself back to full functionality with everything under test, and there are still lines of code that no test ever forced you to uncomment, you can very safely throw that extra code away like the garbage it is.
This is an essential technique for legacy code.