The code at the below link seems to do what I'm after:
http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User
I think the token duplication is the important part, but I'm not exactly sure why.
I did have a further issue doing this - any assemblies that needed to be loaded for the 'DoImport(...)' function couldn't be loaded after the impersonation, access was denied for some reason (sorry for the vagueness, I didn't have time to look into this). Ensuring they're loaded before doing the impersonation, either through some dummy function calls or code to force load (see e.g. Is there a way to force all referenced assemblies to be loaded into the app domain?) did the trick.