C ++:如何以编程方式在Windows Credential Manager中创build本地用户login凭据,以便“runas / savecred”可以使用它?

我试图设置一个可执行文件作为本地低特权用户(不同于当前login用户)运行默认情况下。 Windows命令“runas / savecred / user:username appname.exe”可以做到这一点,但它要求当前login用户在第一时间手动input不同用户的密码。 理想情况下,我希望程序的安装程序设置凭证,所以当前login的用户不需要交互。 (我不想将该程序作为Windows服务进行其他原因。)

当我运行“runas”命令时,我观察到Credential Manager中创build了一个新的“交互式login”Windows Credential,其中“Internet或networking地址”设置为“$ computer_name \ $ username(Interactive Logon)”,用户名“被设置为”$计算机名\ $用户名“,”密码“被显示为”********“,并且”持久性“被设置为”企业“。

基于这一观察,我发现了一个Win32 API CredWrite,但是我却遇到了麻烦,无法使它工作。 当调用CredWrite时,出现错误代码87(ERROR_INVALID_PARAMETER – 参数不正确)。

#include <windows.h> #include <wincred.h> #include <tchar.h> void main () { char* password = "randompassword"; DWORD blobsize= 1 + strlen(password); CREDENTIAL cred = {0}; cred.Flags = CRED_FLAGS_USERNAME_TARGET; cred.Type = CRED_TYPE_DOMAIN_PASSWORD; cred.TargetName = L"computername\\username"; cred.CredentialBlobSize = blobsize; cred.CredentialBlob = (LPBYTE) password; cred.Persist = CRED_PERSIST_LOCAL_MACHINE; cred.UserName = L"computername\\username"; if (!CredWrite(&cred, 0)) { std::cerr << GetLastError() << std::endl; } } 

我一直在看的参考资料列在底部。 我能够创build一个CRED_TYPE_GENERICtypes的凭证,但它不被RUNAS识别。 我真的很困惑如何设置像TargetName和types的字段,以编程方式创build一个交互式login凭据作为RUNAS。 官方MSDN文档不清楚,没有例子。

CredWrite: https ://msdn.microsoft.com/en-us/library/windows/desktop/aa375187( v= vs.85).aspx证书: https ://msdn.microsoft.com/en-us/library/ windows / desktop / aa374788(v = vs.85).aspx创buildCRED_TYPE_GENERICtypes凭证的示例代码: 如何从Windows Vault凭证pipe理器存储和检索凭证?

您传递给CredWrite的CREDENTIAL结构有一个未公开的标志。

如果你调用API = 8196的API,你会得到你想要的结果

 char* password1 = "randompassword"; DWORD blobsize = strlen(password1); // Do NOT add 1 here. CREDENTIAL cred = { 0 }; cred.Flags = 8196; cred.Type = 2; cred.TargetName = L"computername\\username"; cred.CredentialBlobSize = blobsize; cred.CredentialBlob = (LPBYTE)password1; cred.Persist = 3; cred.UserName = L"computername\\username"; if (!CredWrite(&cred, 0)) { std::cerr << GetLastError() << std::endl; } 

ERROR_INVALID_PARAMETER错误(错误代码87)是由CredentialBlobSize的错误值引起的。 “如果类型成员是CRED_TYPE_DOMAIN_PASSWORD,则此成员包含UserName的明文Unicode密码,CredentialBlob和CredentialBlobSize成员不包含结尾的零字符。 (CREDENTIAL: https ://msdn.microsoft.com/en-us/library/windows/desktop/aa374788( v= vs.85).aspx)

使用此修复程序可以创建Windows凭据(不是通用的或基于证书的凭据),而不会出错。

 #include <windows.h> #include <wincred.h> #include <tchar.h> void main () { char* password = "randompassword"; DWORD blobsize= strlen(password); // Do NOT add 1 here. CREDENTIAL cred = {0}; cred.Flags = CRED_FLAGS_USERNAME_TARGET; cred.Type = CRED_TYPE_DOMAIN_PASSWORD; cred.TargetName = L"computername\\username"; cred.CredentialBlobSize = blobsize; cred.CredentialBlob = (LPBYTE) password; cred.Persist = CRED_PERSIST_LOCAL_MACHINE; cred.UserName = L"computername\\username"; if (!CredWrite(&cred, 0)) { std::cerr << GetLastError() << std::endl; } } 

但是,还是有一个微妙的差别。 我创建的“Internet或网络地址”是RUNAS无法识别的“$ computer_name \ $ username( Windows Identity )”。 由RUNAS创建的是“$ computer_name \ $ username( 交互式登录 )”。 这一点如何设置?

我可以使用CredRead来读取我创建的凭证,但是无法为由RUNAS创建的凭证这样做。

 CREDENTIAL cred = { 0 }; PCREDENTIAL pcred = &cred; // Works for Windows Identity. TargetName is case-insensitive. CredRead(L"$computer_name\$username", CRED_TYPE_DOMAIN_PASSWORD, 0, &pcred); // Fails for Interactive Logon with error code 87 or 1168. I tried all possible CRED_TYPE_*. CredRead(L"$computer_name\$username", CRED_TYPE_*, 0, &pcred); 

类似的线程:1. Runas命令,绕过证书( https://community.spiceworks.com/topic/485852-runas-command-bypass-credentials)2.runas / savecred …不接受cmdkey / add(凭证)( runas / savecred …不接受cmdkey / add(凭证) )3.使用/ savecred开关的runas不接受cmdkey命令存储的凭证( https://social.technet.microsoft.com/Forums/ windowsserver / en-US / c0e398cc-224f-4390-bc69-0ee544f9b5cb / runas-with-the-savecred-switch-does-not-accept-a-credential-by-the-cmdkey-command?forum = winserversecurity )

CMDKEY命令允许我创建一个最接近由RUNAS创建的证书。 两者在由“cmdkey / list”返回的结果中看起来相同。 但是,由CMDKEY创建的那个不被RUNAS所尊敬。

 cmdkey /add:Domain:interactive=$computer_name\$username1 /user:$computer_name\$username1 /pass:$password cmdkey /list # created by CMDKEY Target: Domain:interactive=$computer_name\$username1 Type: Domain Password User: $computer_name\$username1 # created by RUNAS Target: Domain:interactive=$computer_name\$username2 Type: Domain Password User: $computer_name\$username2