1

我将首先说错误本身的原因实际上可能与 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 intand[ref]第四个等)似乎不会影响结果。

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

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

4

1 回答 1

2

像你一样使用StringBuilder构造函数,传递 0 或什么都不传递,你有效地给它一个 16 个字符的容量(默认容量)。您可以通过$result.CapacityNew.

然后,当您调用时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()
于 2020-11-29T09:43:06.270 回答