Powershell 中的内部 CLR 错误 (0x80131506) 和崩溃

Internal CLR errors (0x80131506) and crash in Powershell

首先我要说错误的原因本身实际上可能与 PowerShell 具体无关,它可能更深层次地存在于 .NET 中,但这正是我遇到它的地方。

PowerShell 版本:7.1.0

我定义了以下类型以解析资源请求,例如在注册表中使用的(签名与 PInvoke.net 上看到的完全一样):

Add-Type -TypeDefinition @"
   using System;
   using System.Text;
   using System.Runtime.InteropServices;
   
   public static class ShellHelper {
      [DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)]
      public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);
   }
"@

现在对于测试用例,请考虑以下内容:

$result = [System.Text.StringBuilder]::New();
$tmp = [System.IntPtr]::New(0);
[ShellHelper]::SHLoadIndirectString("@firewallapi.dll,-50323", $result, 256, $tmp) > $null;
$result.ToString()

输出 SNMP Trap 已生成,一切看起来都不错。其他一些值也可以正常工作。但是,例如,如果我用 -50326 替换数字 -50323 那么我仍然会得到 Block any other traffic to and from SNMPTRAP service 的正确值作为输出,但是在我采取的几乎所有操作(即执行命令,甚至只是按 Tab)就会抛出一系列无休止的 Fatal error. Internal CLR error. (0x80131506) 异常,直到我收到 Stack overflow. 消息并且 PowerShell 崩溃到桌面。 (参见 https://imgur.com/a/MYZwhYa。)

错误取决于正在处理的字符串,而不是到目前为止方法调用的数量:如果在新会话中首先调用最后一个命令,则会立即发生相同的错误。

除了输出字符串可能的某些属性(它的长度、某些字符的存在等)之外,我一直无法确定甚至无法合理猜测到底是什么导致了这种行为。使用某些参数(更改第三个参数,使用 out int[ref] 作为第四个参数等)似乎不会影响结果。

我主要是被错误的奇怪时间弄糊涂了。似乎某些内部进程可能会导致内存中的其他数据损坏,从而导致以后出现错误,但这只是我的猜测。我也可能只是遗漏了一些非常明显的东西。

造成这种行为的原因可能是什么?如果它是 .NET 中的一个真正的错误,我怎么可能解决它,或者甚至只是着手确定它发生的确切标准?

像您一样使用 StringBuilder 构造函数,传递 0 或不传递任何内容,您有效地为其提供了 16 个字符的容量(默认容量)。您可以通过在 New 之后添加 $result.Capacity 来验证这一点。

当您随后调用 SHLoadIndirectString 时,您将 256 作为大小传递,因此该函数假定它可以将那么多字节写入 result 缓冲区。它这样做,因为它现在有办法知道 $result 实际上只能占用 16 个字节,因此会覆盖 PowerShell 进程中的其他任意内存。

内存损坏错误通常不会在您实际损坏内存时导致崩溃,但在以后的任何时候都不会。

您需要传递实际可用的尺寸,如下所示:

$result = [System.Text.StringBuilder]::New(256);
$tmp = [System.IntPtr]::New(0);
[ShellHelper]::SHLoadIndirectString("@firewallapi.dll,-50323", $result, $result.Capacity, $tmp) > $null;
$result.ToString()