2009-11-11 12 views
12

Hay una pregunta similar dirigida al Java VM pero no he encontrado una pregunta para .net (cierre y marque como duplicado si me falta algo)Cómo bloquear el Common Language Runtime (CLR) de .NET en .net pura

Entonces, ¿es posible sin interoperabilidad desagradable no gestionada? Y con un bloqueo me refiero a un verdadero "xxx.exe ha dejado de funcionar", no a StackOverflow ni a OutOfMemoryException.

Creo que no es posible, excepto cuando se golpea un error en la máquina virtual.

+2

El punto de CLR .NET es abstraer lejos de la computadora, manteniendo los desbordamientos de pila y otros insectos en el interior de la CLR y no bloquear su ordenador física (incluso con un sistema operativo con errores) – Earlz

+1

Si tal cosa es posible, ¿no cae en la categoría "error en la máquina virtual", por definición? –

+0

Sí ... a menos que esté hablando de eliminar archivos importantes y cosas así desde el tiempo de ejecución de CLR – Earlz

Respuesta

15

Bueno ... ¿cómo definirías "pure .NET"? Jugué con Clr2/delegado/GCHandle/matriz cuando leí el post "¿Cómo bloqueo de JVM", y se acercó con algo como esto:

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

Sólo se sabe que funciona en 32 bits Windows XP con Clr2 en x86; y también se sabe que no funciona con Vista y Windows 7 y similares, donde DEP + ASLR está activado por defecto.

Lo divertido del código anterior es que no usaba explícitamente código no seguro (aunque GCHandle.Alloc (..., GCHandleType.Pinned) exige privilegios de seguridad), pero logra falsificar una matriz en una delegar instancia y llama al código máquina x86 dentro de la matriz. El código en sí es puro C#, si no cuenta el código x86 incrustado como un "idioma extranjero" ;-) Básicamente hace uso de la implementación interna de los delegados de CLR2 en métodos estáticos, que algunos miembros privados del Delegado son en realidad punteros internos Rellené el código x86 en una matriz, que se asigna en el montón administrado. Entonces, para que esto funcione, DEP no debe estar habilitado, o tendremos que buscar otra forma de obtener privilegios de ejecución en esa página de memoria.

código El 86 es la siguiente: (en la sintaxis de 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 

Esto no es un comportamiento especificado por el CLI y no funcionará en otras implementaciones de CLI como Mono. Hay otras formas de hacer que la lógica similar se ejecute en Mono, aunque ya lo intenté en Ubuntu 9.04 con Mono 2.4 y funcionó.

escribí un post sobre ello aquí: http://rednaxelafx.javaeye.com/blog/461787

Está en chino, pero hay un montón de código que hay que debe explicar lo que hice. Utilizando el mismo truco, al final de la publicación del blog, mostré un par de ejemplos de cómo podría modificar el código anterior para que las cosas salgan mal, como obtener una SEHException.

+0

Todavía no estoy seguro de si esto es "puro .net": la definición se vuelve borrosa. Sin embargo, definitivamente es una muy buena idea +1! –

-1

Sé que puede bloquear toda su PC con .NET. Pero eso implica un ciclo infinito y una prioridad de proceso en tiempo real ...

+0

prioridad de proceso - buena idea. ¿Pero podemos cambiar la prioridad del proceso desde el interior del proceso? ¿O podemos activar otro proceso, con mayor prioridad que la nuestra? bueno ... veamos ... –

+0

Acabo de probarlo: un proceso de trabajo es un bucle sin fin y la creación de instancias de objetos mientras fue iniciado por otro proceso utilizando ProcessPriorityClass.Tiempo real. El rendimiento de la máquina se degrada, claro, pero no se bloquea. –

+0

Puede configurarlo usando Process.GetCurrentProcess(). ProcessPriority o algo así. Pero he tenido resultados mixtos. Mi propia máquina se congeló por completo, por ejemplo. No sé si importa, pero siempre me conecto como administrador. – Vivelin

2

Oren Eini descubrió un error en el framework .net que causaba una 'ExecutionEngineException', básicamente un bloqueo del tiempo de ejecución.

Usted puede leer sobre ello aquí (Microsoft Connect):

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

Y a pesar del estado 'cerrado' del error - no está solucionado.

+0

El informe de error se cerró porque encontró una solución alternativa ... por lo que MS cerró el informe y nunca solucionó el problema porque nadie más tenía el mismo problema. –

+0

... y el problema en sí permanece a oscuras sin ver la solución que él proporcionó. Sin embargo, esto también se clasificaría como "error en el CLR" –

2

Lo he hecho solo hoy. Estaba probando una configuración de un proyecto .net más grande. Faltaba un ensamblaje que contenía algunas interfaces y el exe simplemente deja de funcionar. El tiempo de ejecución no atrapó ninguna excepción.

Puede estar seguro de que hay un incluso más errores en el tiempo de ejecución - sólo cuentan los millones de líneas de código ...

1

que he visto programas Java chocar la JVM mediante la carga de una clase inexistente y ignorando ClassNotFoundError, luego continúe ejecutándose como si nada hubiera sucedido. Quizás podría hacer algo similar cuando cargue dinámicamente una clase .NET.

+0

. Dado que no podemos cargar clases en .NET, solo montajes, la situación es un poco diferente. Cuando fallamos al cargar un ensamblado y nos tragamos la excepción, lo único que podemos intentar es encontrar una clase y/o método por reflexión. Pero lo peor es otra excepción, ya sea algo relacionado con la propia reflexión (por ejemplo, TypeLoadException) o una NullReferenceException cuando se espera que alguna variable no sea nula después de cargar un ensamblaje. Para resumir: no veo ninguna posibilidad de esto en .net. Y si tienes razón, la JVM segura probablemente tenga errores al respecto. –

+0

Fue una JVM de Sun, pero hace algunos años, probablemente alrededor de la versión 2.x. –

-1

Existe algún código C# que aunque técnicamente correcto no se ejecutará como un programa .net válido. Tiene algo que hacer con la interfaz sobrecargando un método vacío, pero realmente no puedo recordarlo.

0

Puede compilar este código con/clr: pure y también tiene la opción de fuerza pura del enlazador.

Sin embargo, falla con lo que parece una falla de tiempo de ejecución;

(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=????????

A pesar de que se compila con/clr: puros o/CLR: caja fuerte, y la imagen representa a sí mismo como tal, que sólo funcionará con plena confianza debido al verificador la captura de este error (error del compilador).

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

Se trata de la salida de PEverify, que analiza todo el archivo PE, este error no se detecta hasta que el tiempo de ejecución llama a este método, ya que el verificador trabaja con el JIT'er y es perezoso se registran para la verificación .

[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

Si pudiera eludir el verificador aquí, esto sería un error enorme en el CLR y darle la ejecución de código a partir de un proceso de unprivilaged.

Aquí está el 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 

El error está en offset, IL_19.

Si se está ejecutando en CAS o en cualquier otro modo seguro, este código generará la famosa excepción "el código puede desestabilizar el tiempo de ejecución".

2

Sin la necesidad de utilizar un código inseguro o delegados (también si debo admitir que es una manera muy agradable de bloquear su CLR), puede usar funciones simples de Marshal para forzar la falla de .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); 
      } 
     } 
    } 
} 

Además de esto, usando siempre GCHandle, causará una violación de acceso a memoria como error.

using System; 
using System.Runtime.InteropServices; 

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

Me gusta el último, corto y dulce. Lo usé para mis pruebas de choque. – SilverSideDown

Cuestiones relacionadas