C#使用CredWrite访问C $

我正在尝试使用对该服务器没有权限的域帐户访问服务器的C $。 我需要以该服务器的本地登录的forms保存凭据,以使程序正常工作。

如何使用CredWrite保存这些凭据

我发现的Credential Manager类:(编辑:以下是正常运行的代码。)

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace Test_Manager { public class Win32CredMan { [DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool CredRead(string target, CRED_TYPE type, int reservedFlag, out IntPtr CredentialPtr); [DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool CredWrite([In] ref NativeCredential userCredential, [In] UInt32 flags); [DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)] static extern bool CredFree([In] IntPtr cred); public enum CRED_TYPE : uint { GENERIC = 1, DOMAIN_PASSWORD = 2, DOMAIN_CERTIFICATE = 3, DOMAIN_VISIBLE_PASSWORD = 4, GENERIC_CERTIFICATE = 5, DOMAIN_EXTENDED = 6, MAXIMUM = 7, // Maximum supported cred type MAXIMUM_EX = (MAXIMUM + 1000), // Allow new applications to run on old OSes } public enum CRED_PERSIST : uint { SESSION = 1, LOCAL_MACHINE = 2, ENTERPRISE = 3, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct NativeCredential { public UInt32 Flags; public CRED_TYPE Type; public IntPtr TargetName; public IntPtr Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public UInt32 CredentialBlobSize; public IntPtr CredentialBlob; public UInt32 Persist; public UInt32 AttributeCount; public IntPtr Attributes; public IntPtr TargetAlias; public IntPtr UserName; ///  /// This method derives a NativeCredential instance from a given Credential instance. ///  /// The managed Credential counterpart containing data to be stored. /// A NativeCredential instance that is derived from the given Credential /// instance. internal static NativeCredential GetNativeCredential(Credential cred) { NativeCredential ncred = new NativeCredential(); ncred.AttributeCount = 0; ncred.Attributes = IntPtr.Zero; ncred.Comment = IntPtr.Zero; ncred.TargetAlias = IntPtr.Zero; ncred.Type = (CRED_TYPE)cred.Type; ncred.Persist = (UInt32)cred.Persist; ncred.CredentialBlobSize = (UInt32)cred.CredentialBlobSize; ncred.TargetName = Marshal.StringToCoTaskMemUni(cred.TargetName); ncred.CredentialBlob = Marshal.StringToCoTaskMemUni(cred.CredentialBlob); ncred.UserName = Marshal.StringToCoTaskMemUni(cred.UserName); return ncred; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct Credential { public UInt32 Flags; public CRED_TYPE Type; public string TargetName; public string Comment; public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten; public UInt32 CredentialBlobSize; public string CredentialBlob; public CRED_PERSIST Persist; public UInt32 AttributeCount; public IntPtr Attributes; public string TargetAlias; public string UserName; } #region Critical Handle Type definition sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid { // Set the handle. internal CriticalCredentialHandle(IntPtr preexistingHandle) { SetHandle(preexistingHandle); } internal Credential GetCredential() { if (!IsInvalid) { // Get the Credential from the mem location NativeCredential ncred = (NativeCredential)Marshal.PtrToStructure(handle, typeof(NativeCredential)); // Create a managed Credential type and fill it with data from the native counterpart. Credential cred = new Credential(); cred.CredentialBlobSize = ncred.CredentialBlobSize; cred.CredentialBlob = Marshal.PtrToStringUni(ncred.CredentialBlob, (int)ncred.CredentialBlobSize / 2); cred.UserName = Marshal.PtrToStringUni(ncred.UserName); cred.TargetName = Marshal.PtrToStringUni(ncred.TargetName); cred.TargetAlias = Marshal.PtrToStringUni(ncred.TargetAlias); cred.Type = ncred.Type; cred.Flags = ncred.Flags; cred.Persist = (CRED_PERSIST)ncred.Persist; return cred; } else { throw new InvalidOperationException("Invalid CriticalHandle!"); } } // Perform any specific actions to release the handle in the ReleaseHandle method. // Often, you need to use Pinvoke to make a call into the Win32 API to release the // handle. In this case, however, we can use the Marshal class to release the unmanaged memory. override protected bool ReleaseHandle() { // If the handle was set, free it. Return success. if (!IsInvalid) { // NOTE: We should also ZERO out the memory allocated to the handle, before free'ing it // so there are no traces of the sensitive data left in memory. CredFree(handle); // Mark the handle as invalid for future users. SetHandleAsInvalid(); return true; } // Return false. return false; } } #endregion public int WriteCred(string key, string user, string secret) { // Validations. byte[] byteArray = Encoding.Unicode.GetBytes(secret); if (byteArray.Length > 512) throw new ArgumentOutOfRangeException("The secret message has exceeded 512 bytes."); // Go ahead with what we have are stuff it into the CredMan structures. Credential cred = new Credential(); cred.TargetName = key; cred.UserName = user; cred.CredentialBlob = secret; cred.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(secret).Length; cred.AttributeCount = 0; cred.Attributes = IntPtr.Zero; cred.Comment = null; cred.TargetAlias = null; cred.Type = CRED_TYPE.DOMAIN_PASSWORD; cred.Persist = CRED_PERSIST.ENTERPRISE; NativeCredential ncred = NativeCredential.GetNativeCredential(cred); // Write the info into the CredMan storage. bool written = CredWrite(ref ncred, 0); int lastError = Marshal.GetLastWin32Error(); if (written) { return 0; } else { string message = string.Format("CredWrite failed with the error code {0}.", lastError); throw new Exception(message); } } public static string ReadCred(string key) { // Validations. IntPtr nCredPtr; string readPasswordText = null; // Make the API call using the P/Invoke signature bool read = CredRead(key, CRED_TYPE.GENERIC, 0, out nCredPtr); int lastError = Marshal.GetLastWin32Error(); // If the API was successful then... if (read) { using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr)) { Credential cred = critCred.GetCredential(); readPasswordText = cred.CredentialBlob; } } else { readPasswordText = string.Empty; //1168 is "element not found" -- ignore that one and return empty string: if (lastError != 1168) { string message = string.Format("ReadCred failed with the error code {0}.", lastError); throw new Exception(message); } } return readPasswordText; } } } 

长话短说这是我正在尝试使用的上述代码中的方法:

 public int WriteCred(string key, string user, string secret) { // Validations. byte[] byteArray = Encoding.Unicode.GetBytes(secret); if (byteArray.Length > 512) throw new ArgumentOutOfRangeException("The secret message has exceeded 512 bytes."); // Go ahead with what we have are stuff it into the CredMan structures. Credential cred = new Credential(); cred.TargetName = key; cred.UserName = user; cred.CredentialBlob = secret; cred.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(secret).Length; cred.AttributeCount = 0; cred.Attributes = IntPtr.Zero; cred.Comment = null; cred.TargetAlias = null; cred.Type = CRED_TYPE.DOMAIN_PASSWORD; cred.Persist = CRED_PERSIST.ENTERPRISE; NativeCredential ncred = NativeCredential.GetNativeCredential(cred); // Write the info into the CredMan storage. bool written = CredWrite(ref ncred, 0); int lastError = Marshal.GetLastWin32Error(); if (written) { return 0; } else { string message = string.Format("CredWrite failed with the error code {0}.", lastError); throw new Exception(message); } } 

这就是我在程序正文中所做的:

 Win32CredMan cm = new Win32CredMan(); cm.WriteCred("TheServer-18", @"TheServer-18\Administrator", "P4SSw0rD!"); 

我假设我没有获得访问权限,因为凭证没有正确添加。

更新:

我已经介绍的过程是向Windows Credential Manager添加Generic Credential。 但是,如果不使用WriteCred方法中指定的用户名。 我不明白为什么。

问题得到解决,上面的代码现在完全正常运行。 问题与GetNativeCredential有关,它没有使用在WriteCred方法中分配给cred的值,而是使用已设置的一些静态值。

此外,我将信息输入WriteCred方法的方式不正确。 上面的代码已经修复,以便它完全正常运行。