2009-11-11 15 views
12

C'è una domanda simile a quella del Java VM ma non ho trovato una domanda per .net (si prega di chiudere e contrassegnare come duplicato se mi mancava qualcosa).Come arrestare .NET Common Language Runtime (CLR) in puro .net

Quindi - è possibile senza un brutto intervallo non gestito? E con arresto anomalo intendo un vero "xxx.exe ha smesso di funzionare" non un StackOverflow o OutOfMemoryException.

Penso che non sia possibile, tranne quando si verifica un errore nella VM stessa.

+2

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

+1

Se una cosa del genere è possibile, non rientra nella categoria "bug nella VM stessa", per definizione? –

+0

Sì .. a meno che non si stia parlando dell'eliminazione di file importanti e simili dall'interno del runtime CLR – Earlz

risposta

15

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.

+0

Non sono ancora sicuro se si tratta di "puro .net" - la definizione diventa sfocata. Tuttavia, è sicuramente una buona idea +1! –

-1

So che si può bloccare l'intero PC con .NET. Ma ciò implica un ciclo infinito e una priorità del processo RealTime ...

+0

priorità del processo - bella idea. Ma possiamo cambiare la priorità del processo dall'interno del processo? Oppure possiamo attivare un altro processo, con priorità più alta del nostro? bene .... vediamo ... –

+0

L'ho provato: un processo di lavoro è un loop infinito e l'istanziazione di oggetti mentre era iniziato da un altro processo usando ProcessPriorityClass.Tempo reale. Le prestazioni della macchina sono degradate, certo, ma non si bloccano. –

+0

È possibile impostarlo utilizzando Process.GetCurrentProcess(). ProcessPriority o qualcosa del genere. Ma ho avuto risultati contrastanti. La mia stessa macchina si è bloccata completamente, ad esempio. Non so se è importante ma accedo sempre come amministratore. – Vivelin

2

Oren Eini ha rilevato un bug nel framework .net che ha causato un 'ExecutionEngineException' - fondamentalmente un arresto anomalo del runtime.

Si può leggere su qui (Microsoft Connect):

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384781

E nonostante lo stato 'chiuso' del bug - non è ancora risolto.

+0

Il bug report è stato chiuso perché ha trovato una soluzione ... quindi MS ha chiuso il report e non ha mai risolto il problema perché nessun altro aveva lo stesso problema. –

+0

... e il problema rimane al buio senza vedere la soluzione che ha fornito. Tuttavia, questo sarebbe anche classificato come "bug nel CLR" –

2

L'ho fatto proprio oggi. Stavo testando una configurazione di un progetto .net più grande. Mancava un assembly contenente alcune interfacce e l'exe smette di funzionare. Nessuna eccezione è stata rilevata dal runtime.

Si può essere certi che là un ancor più bug nel runtime - basta contare i milioni di righe di codice ...

1

Ho visto programmi Java in crash JVM caricando una classe inesistente e ignorando ClassNotFoundError, quindi continua l'esecuzione come se nulla fosse accaduto. Forse potresti fare qualcosa di simile quando carichi dinamicamente una classe .NET.

+0

Dato che non possiamo caricare le classi in .net ma solo gli assembly la situazione è leggermente diversa. Quando non siamo riusciti a caricare un assembly e abbiamo inghiottito l'eccezione, l'unica cosa che potremmo provare è trovare una classe e/o un metodo per riflessione. Ma poi la cosa peggiore è un'altra eccezione, o qualcosa relativo alla riflessione stessa (ad esempio TypeLoadException) o una NullReferenceException quando ci si aspetta che alcune variabili non siano nulle dopo aver caricato un assembly. Per riassumere: non vedo alcuna possibilità per questo in. Net. E se hai ragione, la JVM è probabilmente infestata da questo. –

+0

Era una JVM Sun, ma alcuni anni fa, probabilmente circa la versione 2.x. –

-1

C'è del codice C# che mentre tecnicamente corretto non verrà eseguito come un programma .net valido. Ha qualcosa da fare con l'interfaccia che sta sovraccaricando un metodo vuoto ma non riesco davvero a ricordare.

0

È possibile compilare questo codice con/clr: pure e avere anche l'opzione pura di linker force.

Tuttavia, si blocca con quello che sembra un errore di runtime;

(1388.5e4): Access violation - code c0000005 (!!! second chance !!!) eax=8d00fea5 ebx=00000000 ecx=00253e50 edx=00253e50 esi=022ad3cc edi=00253e50 eip=6ae965c5 esp=0020edbc ebp=0020edc8 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b
efl=00010246 * WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\eb4e1e70734f6efb9c7de7ec5f452c9e\mscorlib.ni.dll mscorlib_ni+0x9365c5: 6ae965c5 ff10
call dword ptr [eax]
ds:002b:8d00fea5=????????

anche se si compila con/CLR: puri o/CLR: sicuri, e l'immagine rappresenta è di per sé come tale, funziona solo in piena fiducia a causa del verificatore cattura questo bug (compilatore bug).

namespace Settings 
{ 
    public ref class RefType 
    {  
    public: 
     unsigned int I; 
     String^ S;  
     unsigned long L; 
    }; 
    public ref class aUseTemplate 
    { 
    public: 
     void CallTemplate() 
     { 
      array<RefType^>^ refarr = gcnew array<RefType^>(20); 
      for(int i=0; i < 20; i++) 
      { 
       RefType^ rt = gcnew RefType(); 
       rt->I = 0x42424242; 
       rt->L = 0x33333333; 
       refarr[i] = rt; 
      } 

      HasTemplate(refarr); 
     } 
     template<typename T> void HasTemplate(T input) 
     { 
      for each(T% x in input) 
       Console::WriteLine(x); 
     } 
    }; 
} 

Questo è dall'uscita di PEverify, che analizza l'intero file PE, questo errore non viene rilevato fino runtime chiama in questo metodo, il verificatore funziona con il JIT'er ed è pigro su di esso è verifica .

[IL]: Error: [C:\Users\files\Documents\Visual Studio 2010\Projects\testCli\bin\Release\PureSettings.dll : Settings.aUseTemplate::HasTemplate^>][off set 0x00000017][found ref 'Settings.RefType'][expected address of ref ] Unexpected type on the stack. 1 Error(s) Verifying PureSettings.dll

Se si potesse bypassare il verificatore qui, questo sarebbe un BUG enorme nel CLR e darvi l'esecuzione di codice da un processo unprivilaged.

Ecco la MSIL;

IL_000d: bge.s  IL_0021 
    IL_000f: ldloc.1 
    IL_0010: ldloc.0 
    IL_0011: ldelem.ref 
    IL_0012: castclass Settings.RefType 
    IL_0017: stloc.2 
    IL_0018: ldloc.2 
    IL_0019: ldind.ref 
    IL_001a: call  void [mscorlib]System.Console::WriteLine(object) 
    IL_001f: br.s  IL_0006 
    IL_0021: ret 

Il bug è in offset, IL_19.

Se si sta utilizzando CAS o qualsiasi altra modalità di sicurezza del tipo, questo codice genererà la famosa eccezione "codice può destabilizzare il runtime".

2

Senza la necessità di utilizzare codice non sicuro o delegati (anche se devo ammettere che è un modo molto carino per arrestare il CLR), è possibile utilizzare semplici funzioni di Maresciallo per forzare l'arresto di .NET.

using System; 
using System.Runtime.InteropServices; 

namespace Crash 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IntPtr p = Marshal.AllocHGlobal(1); 
      for (int i = 0; i < 10000000; ++i) 
      { 
       p = new IntPtr(p.ToInt64() + 1); 
       Marshal.WriteByte(p, 0xFF); 
      } 
     } 
    } 
} 

Anche questo, utilizzando sempre GCHandle, causerà una violazione di accesso alla memoria come errore.

using System; 
using System.Runtime.InteropServices; 

namespace Crash 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      GCHandle.FromIntPtr(new IntPtr(32323)); 
     } 
    } 
} 
+0

Mi piace l'ultimo, breve e dolce. L'ho usato per i miei crash test. – SilverSideDown

Problemi correlati