Pergunta

Na uma resposta para seu próprio < a href = "https://stackoverflow.com/questions/791498/how-to-steal-private-data-in-net/"> controversa questão , Mash ilustrou que você não precisa da 'palavra-chave inseguro' a ler e escrever diretamente para os bytes de qualquer instância de objeto .NET. Você pode declarar os seguintes tipos:

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

E, em seguida, você pode fazer coisas como a mudança de uma string "imutável". As seguintes impressões de código "bar" na minha máquina:

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

Você também pode desencadear um corrompendo objeto AccessViolationException referências com a mesma técnica.

Pergunta: Eu pensei que (no código C # conseguiu pura) a inseguro palavra-chave era necessário fazer coisas como esta. Por que não é necessário aqui? isso significa que pura código gerenciado "seguro" não é realmente seguro em tudo?

Foi útil?

Solução

OK, que é desagradável ... os perigos do uso de uma união. Isso pode funcionar, mas não é uma idéia muito boa - Eu acho que eu compará-lo à reflexão (onde você pode fazer a maioria das coisas). Eu estaria interessado em ver se isso funciona em um ambiente de acesso restrito - se assim for, pode representar um problema maior ...


Eu apenas testei sem o sinalizador "confiança total", e o tempo de execução a rejeita:

Não foi possível carregar o tipo 'MemoryAccess' 'de montagem ConsoleApplication4, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' porque os objetos sobreposta no deslocamento 0 e o montagem devem ser verificáveis.

E para ter esse sinalizador, você já precisa de alta confiança - assim você já pode fazer as coisas mais desagradáveis. Cordas são um caso um pouco diferente, porque eles não são objetos normais NET - mas há outros exemplos de formas de mutação-los - a abordagem "união" é interessante, embora. Para uma outra maneira hacky (com confiança suficiente):

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

Outras dicas

unsafe Whoops, eu confuso com fixed. Aqui está uma versão corrigida:

A razão que o código de exemplo não necessita de marcação com a palavra-chave unsafe é que ele não contém ponteiros (veja abaixo cotação para porque este é considerado como inseguro). Você está absolutamente correto: "seguro" pode melhor ser chamado de "run-time amigável". Para mais informações sobre este tópico que eu encaminhá-lo para Don Box e Chris Sells .NET Essencial

Para citar MSDN,

No Common Language Runtime (CLR), código inseguro é referido como código não verificado. código inseguro em C # não é necessariamente perigosa; isto é código apenas cuja segurança não pode ser verificada pelo CLR. O CLR portanto, apenas executar código inseguro se ele está em um conjunto totalmente confiável. E se você usar o código inseguro, é sua responsabilidade de assegurar que a sua O código não apresentar riscos de segurança ou erros de ponteiro.

A diferença entre fixo e inseguro se que fixa pára o CLR de mover as coisas na memória, para que as coisas fora do tempo de execução pode seguramente acessá-los, enquanto inseguro é sobre exatamente o problema oposto: enquanto o CLR pode garantir correta resolução para uma referência dotnet, ele não pode fazê-lo por um ponteiro. Você pode chamar vários Microsofties falando sobre como uma referência não é um ponteiro, e é por isso que eles fazem tanto barulho sobre uma distinção sutil.

Você ainda estão optando fora do bit 'gerenciado'. Há a suposição de que se você pode fazer isso, então você sabe o que está fazendo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top