每个人,我都面临着LogonUser
功能的问题。
我只想知道是否可以通过此签名将LogonUser
函数导入C#:
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int LogonUser(string username, string domain, IntPtr password, int logonType, int logonProvider, ref IntPtr token);
因为我想保护我的密码不使用字符串,而是使用SecureString
类。然后使用如下函数:
var passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
var result = LogonUser(userName, domain, passwordPtr, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
我总是得到result = 0,并且消息显示用户名和密码不正确。 但是当我更改签名以使用字符串密码时,一切都运行良好。
请帮助我保护密码SecureString
对我来说非常重要。
答案 0 :(得分:2)
正如Alex K所指出的那样,在SecureStringToGlobalAllocUnicode
中使用LogonUser
就是一个例子。请注意,P / Invoke声明有:
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain, IntPtr password,
int logonType, int logonProvider, ref IntPtr token);
已指定CharSet = CharSet.Unicode
。很遗憾,由于历史原因,默认的CharSet
值为Ansi
,因此您的 P / Invoke尝试将使用该值。
这适用于username
参数,因为P / Invoke基础结构将确保它适当地转换string
。但它不适用于password
参数,因为您已经已经执行了字符串转换,并且您已将其作为Unicode完成 - 并且所有P / Invoke现在看到的是IntPtr
。
我建议更新您的P / Invoke签名以匹配样本中给出的签名。
另一种选择是切换到使用SecureStringToGlobalAllocAnsi
并单独保留P / Invoke签名。但这是一个严重的二流解决方案。严重不建议在2015年编写非Unicode认知代码。
养成始终在您编写的任何P / Invoke签名中指定CharSet.Unicode
的习惯。