C#使用CredWrite访问C $
发布时间:2020-12-15 21:57:15 所属栏目:百科 来源:网络整理
导读:我正在尝试使用对该服务器没有权限的域帐户访问服务器的C $.我需要以该服务器的本地登录的形式保存凭据,以使程序正常工作. 如何使用CredWrite保存这些凭据 我发现Credential Manager类:(编辑:以下是正常运行的代码.) using System;using System.Collections
我正在尝试使用对该服务器没有权限的域帐户访问服务器的C $.我需要以该服务器的本地登录的形式保存凭据,以使程序正常工作.
如何使用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",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; /// <summary> /// This method derives a NativeCredential instance from a given Credential instance. /// </summary> /// <param name="cred">The managed Credential counterpart containing data to be stored.</param> /// <returns>A NativeCredential instance that is derived from the given Credential /// instance.</returns> 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,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 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-18Administrator","P4SSw0rD!"); 我假设我没有获得访问权限,因为没有正确添加凭据. 更新: 我已经介绍的过程是向Windows Credential Manager添加Generic Credential.但是,如果不使用WriteCred方法中指定的用户名.我不明白为什么. 解决方法
问题得到解决,上面的代码现在完全正常运行.
问题与GetNativeCredential有关,它没有使用在WriteCred方法中分配给cred的值,而是使用已设置的一些静态值. 此外,我将信息输入WriteCred方法的方式不正确.上面的代码已经修复,以便它完全正常运行. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |