Q:

Why does Win32 API function CredEnumerate() return ERROR_NOT_FOUND if I'm impersonated?

I've written some sample code which when I call from the windows command prompt under the context of a normal user account, dump's all the user's saved credentials using CredEnumerate().  However, I really want to be able to do this from SYSTEM user context so I've tested my program from a SYSTEM cmd prompt. 
When I running my program as SYSTEM, I run LogonUser like so:
bLoggedOn = LogonUser(userName.c_str(), domain.c_str(), password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &userToken_);

Then I run ImpersonateLoggedOnUser() on the token to give me the security context of the local user.  After this I do:
bOk = CredEnumerate(NULL, 0, &count, &pCredentials);

And I'd expect this to return the credentials in the same way as if I'd not gone in from system and impersonated.  Can anyone spot anything that I've missed to truly put myself in the user's context?

A:

I guess I aught to answer this question myself since I've now spent ages working out how to do this and I'm not sure it's widely known.  CredEnumerate/CredRead will never provide password information for domain passwords no matter what process context you're in or what token you have despite what it seems to hint at on MSDN.  The only way to get access to the saved credential information is to do so using the undocumented function LSAICryptUnprotectData() which is in lsasrv.dll.  This can decrypt the files you find in %APPDATA%\Microsoft\Credentials and can provide an identical data structure to CredEnumerate except with the password filled in.  The only catch is that this must be done in the process context of lsass.exe (The windows security subsystem), no setting of privilledges etc is enough to give a normal process the rights to do this.  If you're a hacker you can do this by performing a CreateRemoteThread() to inject a thread into lsass.exe or if you're trying to do this in a legitimate way, i.e you're extending the Windows operating system in some way for a third party application, like I was, you can do this by creating a Windows authentication package which lsass will load.  This AP can then use a named pipe or some such method to allow interaction with the rest of your code.

