Bene ... come definiresti "puro .NET"? Ho giocato con CLR2/delegato/GCHandle/array quando ho letto il post "come in crash JVM", e si avvicinò con qualcosa di simile:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace TestCLR2Crash {
static void Main(string[ ] args) {
// declare a delegate that refers to a static method,
// in this case it's a static method generated from the
// anonymous delegate.
Action action = delegate() { };
// "generate" code into an array of uint
var fakeDelegate = new uint[ ] {
// dummy values
0x00000000, 0x00000000,
// fake _methodPtrAux
0x00000000,
// native code/string
0x6AEC8B55, 0x2FD9B8F5, 0xD0FF7C81, 0x006A006A,
0x00E81F6A, 0x83000000, 0x50102404, 0x81CC5DBA,
0x8BD2FF7C, 0x47C35DE5, 0x74656572, 0x73676E69,
0x6F726620, 0x6567206D, 0x6172656E, 0x20646574,
0x65646F63, 0x00000A21
};
// fill in the fake _methodPtrAux,
// make it point to the code region in fakeDelegate
var handle = GCHandle.Alloc(fakeDelegate, GCHandleType.Pinned);
var addr = handle.AddrOfPinnedObject();
const int sizeOfUInt32 = sizeof(uint); // 4
const int indexOfCode = 3;
fakeDelegate[ 2 ] = Convert.ToUInt32(addr.ToInt32() + sizeOfUInt32 * indexOfCode);
var targetInfo = typeof(Action)
.GetField("_target", BindingFlags.NonPublic | BindingFlags.Instance);
targetInfo.SetValue(action, fakeDelegate);
action(); // Greetings from generated code!
Console.WriteLine("Greetings from managed code!");
handle.Free();
}
}
}
E 'noto solo a lavorare a 32 bit Windows XP con CLR2 su x86; e noto anche che non funziona con Vista e Windows 7 e simili, dove DEP + ASLR è attivo per impostazione predefinita.
Il punto sul codice sopra riportato è che non utilizzava esplicitamente codice non sicuro (sebbene GCHandle.Alloc (..., GCHandleType.Pinned) richieda il privilegio di sicurezza), tuttavia riesce a simulare un array in un delegare l'istanza e le chiamate nel codice macchina x86 all'interno dell'array. Il codice stesso è puro C#, se non si considera il codice x86 incorporato come "lingua straniera" ;-) Fondamentalmente si avvale dell'implementazione interna dei delegati di CLR2 su metodi statici, che alcuni membri privati del Delegato sono in realtà puntatori interni. Ho riempito il codice x86 in un array, che è allocato sull'heap gestito. Quindi, affinché funzioni, DEP non deve essere abilitato, o dovremo trovare un altro modo per ottenere il privilegio di esecuzione su quella pagina di memoria.
Il codice 86 è così: (nella sintassi pseudo-MASM)
55 push ebp
8BEC mov ebp,esp
6A F5 push -0B ; /DevType = STD_OUTPUT_HANDLE
B8 D92F817C mov eax,KERNEL32.GetStdHandle ; |
FFD0 call eax ; \GetStdHandle
6A 00 push 0 ; /pReserved = NULL
6A 00 push 0 ; |pWritten = NULL
6A 1F push 1F ; |CharsToWrite = 1F (31.)
E8 00000000 call <&next_instruction> ; |
830424 10 add dword ptr ss:[esp],10 ; |Buffer
50 push eax ; |hConsole
BA 5DCC817C mov edx,KERNEL32.WriteConsoleA ; |
FFD2 call edx ; \WriteConsoleA
8BE5 mov esp,ebp
5D pop ebp
C3 ret
Questo non è un comportamento specificato da CLI, e non funziona su altre implementazioni CLI come Mono. Ci sono altri modi per far funzionare la logica simile su Mono, già provato su Ubuntu 9.04 con Mono 2.4 e funzionante.
ho scritto un post su di esso qui: http://rednaxelafx.javaeye.com/blog/461787
E 'in cinese, ma c'è un sacco di codice lì che dovrebbe spiegare quello che ho fatto. Usando lo stesso trucco, alla fine del post del blog ho mostrato un paio di esempi su come potresti modificare il codice qui sopra per rendere le cose sbagliate, come ottenere un SEHException.
Il punto di tutta la CLR .NET è quello di astrarre dal computer, mantenendo stack overflow e altri insetti all'interno del CLR e non crash del computer fisico (anche con un sistema operativo buggy) – Earlz
Se una cosa del genere è possibile, non rientra nella categoria "bug nella VM stessa", per definizione? –
Sì .. a meno che non si stia parlando dell'eliminazione di file importanti e simili dall'interno del runtime CLR – Earlz