Warm tip: This article is reproduced from serverfault.com, please click

.net-内部CLR错误(0x80131506)和Powershell崩溃

(.net - Internal CLR errors (0x80131506) and crash in Powershell)

发布于 2020-11-29 07:44:02

首先,我将指出错误的原因实际上与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已产生,一切看起来都很好。其他一些值也可以正常工作。但是,如果我更换号码-50323-50326例如然后我仍然得到正确的值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中的真正错误,我应该如何解决它,甚至只是确定确切的发生条件?

Questioner
Taederias
Viewed
11
Christian.K 2020-11-29 17:43:06

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

当你调用时,SHLoadIndirectString256将按大小传递,因此该函数假定它可以将那么多字节写入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()