Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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:</p> <pre><code>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( ); } } } </code></pre> <p>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.</p> <p>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.</p> <p>The x86 code is like this: (in pseudo-MASM syntax)</p> <pre><code>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 &lt;&amp;next_instruction&gt; ; | 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 </code></pre> <p>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.</p> <p>I wrote a blog post about it here: <a href="http://rednaxelafx.javaeye.com/blog/461787" rel="noreferrer">http://rednaxelafx.javaeye.com/blog/461787</a></p> <p>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.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload