您能否在 macOS 上的 Powershell 7 中使用 PtrToStringAuto 来解密安全字符串?

Pha*_*ake 4 powershell .net-core

我没有成功让以下代码片段输出“Hello World!” 在 PS7

$string = $("Hello World!" | ConvertTo-SecureString -AsPlainText -Force)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($string))
Run Code Online (Sandbox Code Playgroud)

上面的代码是一个不指定长度解密安全字符串的例子。

相同的代码适用于 PS6 和 PS5 以完全解密安全字符串,但不适用于 PS7。我发现解决这个问题的唯一方法是使用 PtrToStringBSTR。然后它可以在此用例的所有 PS 版本中按预期工作。

我在 Github 上的 Powershell 存储库中提出了一个问题,但没有任何回应。老实说,我只是想确认其他人的行为是否相同。

https://github.com/PowerShell/PowerShell/issues/11953

我认为对于许多移植到 PS7 的代码来说,这样的事情将是一个突破性的变化。

这是我迄今为止发现的:

文档

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.ptrtostringauto?view=netframework-4.8

根据文档,指定整数时,PtrToStringAuto:

Allocates a managed String and copies the specified number of characters from a string stored in unmanaged memory into it.

指定 11 的 int 返回“Hello”,这是因为返回的所有其他字符都是 Null。在这种情况下,您必须指定一个 23 的 int 以返回完整的字符串“Hello World!” 使用这种方法。我已经将输出存储在一个变量中来演示这一点。

$String = $("Hello World!" | ConvertTo-SecureString -AsPlainText -Force)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($string), 23)

$String[0] Returns H
$String[1] Returns NULL
$String[2] Returns E
$String[3] Returns NULL
etc.... 
Run Code Online (Sandbox Code Playgroud)

如果没有指定整数,PtrToStringAuto:

Allocates a managed String and copies all characters up to the first null character from a string stored in unmanaged memory into it.

我相信这表明安全字符串被存储为 NULL 值,而在 PS6 中它不是,或者 PtrToStringAuto 函数的行为已经改变,现在遵循上述文档描述的行为。

这只是 macOS 上的问题;但是,使用 PtrToStringBSTR 代替 PtrToStringAuto 来解密安全字符串可以在 Windows 和 macOS 上按预期工作。

这似乎相关:https : //stackoverflow.com/a/11022662/4257163

我也没有看到任何地方进行了更改。

mkl*_*nt0 6

请注意,[securestring]不建议新的代码

虽然在 Windows 上安全字符串提供有限的保护- 通过将加密的字符串存储在内存中 - 通过DPAPI - 并通过缩短纯文本表示在内存中保存的窗口,但在类 Unix 平台上根本不使用加密[1]


我发现解决此问题的唯一方法是使用PtrToStringBSTR.

这不仅是一种围绕这个问题,PtrToStringBSTR是该方法应该被用来开始考虑到输入字符串是,BSTR[2]

请注意,将安全字符串与常规[string]实例相互转换会破坏使用[securestring]开始的目的:您最终将在您无法控制的进程内存中获得敏感数据的纯文本表示。

如果你真的想这样做,一个更简单的、跨平台兼容的方法是:

[System.Net.NetworkCredential]::new('dummy', $string).Password
Run Code Online (Sandbox Code Playgroud)

[1] 当您通过或-将安全字符串保存在文件中时这尤其成问题- 请参阅此答案ConvertFrom-SecureStringExport-CliXml

[2] AutoinPtrToStringAuto()表示假定非托管输入字符串使用适合平台的字符编码,而BSTR所有平台上都是“Unicode”(UTF-16) 字符串。在 Windows 上,假定非托管字符串具有 UTF-16 编码(这就是代码有效的原因),而在类 Unix 平台上,它是 UTF-8,因为 .NET Core 3.0(PowerShell [Core] 7.0 基于 .NET Core 3.1),它解释了您的症状:NUL字符。在BSTR实例的 UTF-16 代码单元中,当(错误)解释为 UTF-8 时,它们本身就被解释为字符。请注意,.NET Core 2.x(这是 PowerShell [Core] 6.x 所基于的)(不恰当地)默认为 UTF-16这个 PR 修复了,相当于一个突破性的变化。