Your intuition is right and you could write your own loader, of course. But the "standard" way we used to deal with this back in the day was to use a tool most often called a Packer.
It typically accepts a list of memory blocks from disk and often lets you override load addresses of these units as well. Then it combines them into one, does a simple ...
Maybe I'm confused by your question, but have you tried LOAD'ing the PRG file?
Loading memory is done with write operations. Write operations ignore ROM banking and always go to the underlying RAM location. Yes, your program initialization needs to bank-in the RAM it will be using, but the loading should work regardless of the initial banking setup.