Por que isso funciona código sem a palavra-chave insegura?
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?
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.