Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
280 views
in Technique[技术] by (71.8m points)

c# - Why does this code work without the unsafe keyword?

In an answer to his own controversial question, Mash has illustrated that you don't need the "unsafe" keyword to read and write directly to the bytes of any .NET object instance. You can declare the following types:

   [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;
   }

And then you can do things like change an "immutable" string. The following code prints "bar" on my machine:

 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);

You can also trigger an AccessViolationException by corrupting object references with the same technique.

Question: I thought that (in pure managed C# code) the unsafe keyword was necessary to do things like this. Why is it not necessary here? Does this mean that pure managed "safe" code is not really safe at all?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OK, that is nasty... the dangers of using a union. That may work, but isn't a very good idea - I guess I'd compare it to reflection (where you can do most things). I'd be interested to see if this works in a constrained access environment - if so, it may represent a bigger problem...


I've just tested it without the "Full Trust" flag, and the runtime rejects it:

Could not load type 'MemoryAccess' from assembly 'ConsoleApplication4, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because objects overlapped at offset 0 and the assembly must be verifiable.

And to have this flag, you already need high trust - so you can already do more nasty things. Strings are a slightly different case, because they aren't normal .NET objects - but there are other examples of ways to mutate them - the "union" approach is an interesting one, though. For another hacky way (with enough trust):

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...