tags:

views:

477

answers:

5

There is a similar question targeting the Java VM but I haven't found a question for .net (please close and mark as duplicate if I was missing something).

So - is it possible without nasty unmanaged interop? And with crashing I mean a real "xxx.exe has stopped working" not a StackOverflow- or OutOfMemoryException.

I think it is not possible, except when hitting a bug in the VM itself.

A: 

I know you can crash your entire PC with .NET. But that involves an endless loop and a RealTime process priority...

horsedrowner
process priority - nice idea. But can we change the process priority from inside of the process? Or can we trigger another process, with higher priority than ours? well.... lets see...
Marc Wittke
Just tried it: a working process is endless looping and instantiating objects while it was started by another process using the ProcessPriorityClass.RealTime. Machine's performance is degraded, sure, but it does not crash.
Marc Wittke
You can set it using Process.GetCurrentProcess().ProcessPriority or something like that. But I've had mixed results. My own machine froze completely for example. I don't know if it matters but I always log in as admin.
horsedrowner
...and you'll need one endless loop per CPU core.
Roger Lipscombe
+2  A: 

Oren Eini discovered a bug in the .net framework that caused an 'ExecutionEngineException' - basically a crash of the runtime.

You can read about it here (Microsoft Connect):

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

And despite the 'closed' state of the bug - it's not fixed yet.

Adam
The bug report was closed because he found a workaround... so MS closed the report and never fixed the issue because no one else had the same problem.
Jon Seigel
...and the problem itself stays in the dark without seeing the solution he provided. However, this would also be categorized as "bug in the CLR"
Marc Wittke
+2  A: 

I've done that just today. I was testing a setup of a larger .net project. There was missing an assembly containing some interfaces and the exe just stops working. No exception was caught by the runtime.

You can be sure that there a even more bugs in the runtime - just count the millions of lines of code ...

Jan
+1  A: 

I've seen Java programs crash the JVM by loading a non-existent class and ignoring ClassNotFoundError, then continue executing as if nothing happened. Perhaps you could do something similar when dynamically loading a .NET class.

Loadmaster
Since we cannot load classes in .net but just assemblies the situation is a little bit different. When we failed to load an assembly and swallowed the exception the only thing we could try is to find a class and/or method by reflection. But then the worst thing is another exception, either something related to reflection itself (e.g. TypeLoadException) or a NullReferenceException when some variable is expected to be not null after loading an assembly. To sum it up: I see no chance for this in .net. And if you're right the certain JVM is probably buggy on this.
Marc Wittke
It was a Sun JVM, but quite a few years ago, probably circa version 2.x.
Loadmaster
+5  A: 

Well...how would you define "pure .NET"? I played with CLR2/delegate/GCHandle/array when I read the "how to crash JVM" post, and came up with something like this:

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

It's only known to work on 32-bit Windows XP with CLR2 on x86; and also known not to work with Vista and Windows 7 and the like, where DEP+ASLR is on by default.

The point of fun about the code above is that it didn't explicitly use unsafe code (although GCHandle.Alloc(..., GCHandleType.Pinned) demands security privilege), yet it manages to fake an array into a delegate instance, and calls into the x86 machine code within the array. The code itself is pure C#, if you don't count the embedded x86 code as some "foreign language" ;-) Basically it makes use of internal implementation of CLR2's delegates on static methods, that a few private members of Delegate are actually internal pointers. I stuffed x86 code into an array, which is allocated on the managed heap. So in order for this to work, DEP must not be enabled, or we'll have to find some other way to get execution privilege on that memory page.

The x86 code is like this: (in pseudo-MASM syntax)

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

This is NOT a behavior specified by CLI, and won't work on other CLI implementations such as Mono. There are other ways to make the similar logic run on Mono though, already tried that on Ubuntu 9.04 w/ Mono 2.4 and worked.

I wrote a blog post about it here: http://rednaxelafx.javaeye.com/blog/461787

It's in Chinese, but there's plenty of code there which should explain what I did. Using the same trick, at the end of the blog post I showed a couple of examples how you could tweak the code above to make things go wrong, such as getting a SEHException.

RednaxelaFX
I'm still unsure whether this is "pure .net" - the definition gets blurry. However, it's definitely a very nice idea +1!
Marc Wittke