The common way of getting involved in a project usually has nothing to do with its programming. Most contributions come from long-time users of the project so ideally you want to target something you use every day... To make things easier on yourself, something smaller and simpler is going to be a lot more accessible than something like Firefox.
The next step is getting involved with the bug tracking process at a "triage" level. Still no code involved. You want to make sure that bug reports contain a good amount of information and you should be testing them to make sure you can reproduce them.
Once you've got that far and you're familiar with the problems of the application, check out the dev source and build it. Make a few silly changes (like putting your name in its window title, etc) and build it again. Look at how the application works. Target a simple bug (I'd recommend a non-UI one*) and get hacking.
If you get stuck, now might be a good time to introduce yourself to the development mailing list. Lists are an archaic thing but as long as you remember to hit reply-all, they do work. Tell them which bug you're targeting and that you're doing this as an exercise and would appreciate some pointers. Most projects will be more than happy to help you.
Once you're done and you've tested your newly built code, create a diff patch and submit that under the bug you've targeted. Other devs may comment so it's important to follow the status of the bug.
Rinse and repeat. You're now a valued, code-hacking contributor.
You are right though. It's not the simplest of things to step into. I think the key to succeeding in an open source project is getting involved in its community. If you can show them you really want to give up your time, they'll help you as much as they're able to.
*UI bugs can be some of the hardest bugs to spot for a programmer who hasn't spent that long under the hood of an application. You need to find where the bug occurs and that can involve stepping through multiple UI frameworks and languages string files.
You also run quite a strong risk of introducing new bugs in other languages so testing things can become several times harder. I would stick to something well behind the scenes as you'll need confidence in the real source if you're going to ever get familiar with how it works.