19

彼自身の物議を醸す質問への回答で、マッシュは、.NETオブジェクトインスタンスのバイトを直接読み書きするために「unsafe」キーワードは必要ないことを示しました。次のタイプを宣言できます。

   [StructLayout(LayoutKind.Explicit)]
   struct MemoryAccess
   {

      [FieldOffset(0)]
      public object Object;

      [FieldOffset(0)]
      public TopBytes Bytes;
   }

   class TopBytes
   {
      public byte b0;
      public byte b1;
      public byte b2;
      public byte b3;
      public byte b4;
      public byte b5;
      public byte b6;
      public byte b7;
      public byte b8;
      public byte b9;
      public byte b10;
      public byte b11;
      public byte b12;
      public byte b13;
      public byte b14;
      public byte b15;
   }

そして、「不変」の文字列を変更するなどのことができます。次のコードは、私のマシンに「バー」を出力します。

 string foo = "foo";
 MemoryAccess mem = new MemoryAccess();
 mem.Object = foo;
 mem.Bytes.b8 = (byte)'b';
 mem.Bytes.b10 = (byte)'a';
 mem.Bytes.b12 = (byte)'r';
 Console.WriteLine(foo);

同じ手法でオブジェクト参照を破損することにより、 AccessViolationExceptionをトリガーすることもできます。

質問:(純粋に管理されたC#コードでは)このようなことを行うには、安全でないキーワードが必要だと思いました。なぜここで必要ないのですか?これは、純粋に管理された「安全な」コードが実際にはまったく安全ではないことを意味しますか?

4

3 に答える 3

12

OK、それは厄介です...ユニオンを使用することの危険性。それはうまくいくかもしれませんが、あまり良い考えではありません-私はそれをリフレクション(ほとんどのことができる場所)と比較すると思います。これが制限されたアクセス環境で機能するかどうかを確認したいのですが、機能する場合は、より大きな問題になる可能性があります...


「完全信頼」フラグなしでテストしたところ、ランタイムはそれを拒否しました。

オブジェクトがオフセット0でオーバーラップし、アセンブリが検証可能である必要があるため、アセンブリ'ConsoleApplication4、Version = 1.0.0.0、Culture = neutral、PublicKeyToken=null'からタイプ'MemoryAccess'を読み込めませんでした。

そして、このフラグを立てるには、すでに高い信頼が必要です。そのため、さらに厄介なことを行うことができます。文字列は通常の.NETオブジェクトではないため、少し異なるケースですが、文字列を変更する方法の例は他にもありますが、「ユニオン」アプローチは興味深いものです。別のハッキーな方法(十分な信頼を持って)の場合:

string orig = "abc   ", copy = orig;
typeof(string).GetMethod("AppendInPlace",
    BindingFlags.NonPublic | BindingFlags.Instance,
    null, new Type[] { typeof(string), typeof(int) }, null)
    .Invoke(orig, new object[] { "def", 3 });
Console.WriteLine(copy); // note we didn't touch "copy", so we have
                         // mutated the same reference
于 2009-04-27T09:04:40.900 に答える
5

おっと、私は混乱unsafeしましたfixed。修正版は次のとおりです。

unsafeサンプル コードがキーワードでタグ付けする必要がない理由は、ポインターが含まれていないためです (これが安全でないと見なされる理由については、以下の引用を参照してください)。「安全」は「ランタイムフレンドリー」と呼ぶ方がよいでしょう。このトピックの詳細については、Don Box と Chris Sells Essential .NETを参照してください。

MSDNを引用するには、

共通言語ランタイム (CLR) では、安全でないコードは検証不能なコードと呼ばれます。C# のアンセーフ コードは必ずしも危険ではありません。CLR で安全性を検証できないコードにすぎません。したがって、CLR は、完全に信頼されたアセンブリ内にある場合にのみ、安全でないコードを実行します。安全でないコードを使用する場合は、コードがセキュリティ リスクやポインター エラーを引き起こさないようにする責任があります。

fixed と unsafe の違いは、fixed は CLR がメモリ内で物事を移動するのを停止するため、ランタイム外のものがそれらに安全にアクセスできるのに対して、unsafe は正反対の問題に関するものです。 dotnet 参照、ポインターに対してはできません。参照はポインターではないということについて、さまざまな Microsoft 関係者が話していることを思い出すかもしれません。これが、彼らが微妙な違いについて大騒ぎしている理由です。

于 2009-04-27T09:40:04.027 に答える
0

あなたはまだ「管理された」ビットをオプトアウトしています。あなたがそれをすることができればあなたはあなたが何をしているのかを知っているという根本的な仮定があります。

于 2009-04-27T09:07:00.363 に答える