如何在纯.net中崩溃.NET公共语言运行库(CLR)

Mar*_*tke 13 .net security crash clr

针对Java VM有一个类似的问题,但我没有找到.net的问题(如果我遗漏了某些内容,请关闭并标记为重复).

那么 - 没有讨厌的非托管互操作可能吗?崩溃我的意思是真正的"xxx.exe已经停止工作"而不是StackOverflow-或OutOfMemoryException.

我认为这是不可能的,除非遇到VM本身的错误.

小智 16

那么......你怎么定义"纯.NET"?当我阅读"如何崩溃JVM"帖子时,我玩了CLR2/delegate/GCHandle /数组,并想出了类似这样的东西:

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( );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它只知道在x86上使用带有CLR2的32位Windows XP; 并且还知道不能使用Vista和Windows 7等,默认情况下DEP + ASLR处于打开状态.

关于上面代码的有趣之处在于它没有明确使用不安全的代码(尽管GCHandle.Alloc(...,GCHandleType.Pinned)需要安全权限),但它设法将数组伪造成委托实例,并且调用数组中的x86机器代码.代码本身是纯C#,如果你不把嵌入式x86代码算作某种"外语";-)基本上它利用了CLR2代理对静态方法的内部实现,那么Delegate的一些私有成员实际上是内部的指针.我将x86代码填充到一个数组中,该数组在托管堆上分配.因此,为了使其工作,不能启用DEP,否则我们必须找到一些其他方法来获取该内存页面上的执行权限.

x86代码是这样的:(在伪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
Run Code Online (Sandbox Code Playgroud)

这不是CLI指定的行为,也不适用于其他CLI实现,如Mono.还有其他方法可以在Mono上运行类似的逻辑,已经在Ubuntu 9.04 w/Mono 2.4上尝试过了.

我在这里写了一篇关于它的博客文章:http://rednaxelafx.javaeye.com/blog/461787

它是中文的,但那里有很多代码可以解释我的所作所为.使用相同的技巧,在博客文章的最后,我展示了几个例子,你可以调整上面的代码来解决问题,例如获取SEHException.