有针对Java VM的类似问题,但我没有找到.net的问题(如果我遗漏了某些内容,请关闭并标记为重复)。
那么 - 没有讨厌的非托管互操作可能吗?崩溃我的意思是真正的“xxx.exe已经停止工作”而不是StackOverflow-或OutOfMemoryException。
我认为这是不可能的,除非遇到VM本身的错误。
答案 0 :(得分:16)
嗯......你怎么定义“纯.NET”?当我阅读“如何崩溃JVM”帖子时,我使用了CLR2 / delegate / GCHandle / array,并提出了类似的结果:
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( );
}
}
}
只知道在x86上使用带有CLR2的32位Windows XP;并且还知道不能使用Vista和Windows 7等,默认情况下DEP + ASLR处于打开状态。
关于上面代码的有趣之处在于它没有明确使用不安全的代码(尽管GCHandle.Alloc(...,GCHandleType.Pinned)需要安全权限),但它设法将数组伪造成委托实例,并调用数组中的x86机器代码。代码本身是纯C#,如果你不把嵌入式x86代码算作某些“外语”;-) 基本上它使用CLR2的静态方法委托的内部实现,委托的一些私有成员实际上是内部指针。我将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
这不是CLI指定的行为,也不适用于其他CLI实现,如Mono。还有其他方法可以在Mono上运行类似的逻辑,已经在Ubuntu 9.04 w / Mono 2.4上尝试过了。
我在这里写了一篇关于它的博文:http://rednaxelafx.javaeye.com/blog/461787
它是中文的,但那里有很多代码可以解释我的所作所为。使用相同的技巧,在博客文章的最后,我展示了几个例子,你可以调整上面的代码来解决问题,例如获取SEHException。
答案 1 :(得分:3)
我今天就这样做了。我正在测试一个更大的.net项目的设置。缺少包含一些接口的程序集,exe只是停止工作。运行时没有捕获异常。
您可以确定运行时中存在更多错误 - 只计算数百万行代码......
答案 2 :(得分:2)
您可以在此处阅读(Microsoft Connect):
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384781
尽管臭虫的“关闭”状态 - 它还没有修复。
答案 3 :(得分:2)
无需使用不安全的代码或委托(如果我必须承认它是一种非常好的方法来崩溃你的CLR),你可以使用简单的Marshal函数来强制.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);
}
}
}
}
此外,使用always GCHandle会导致内存访问冲突,例如错误。
using System;
using System.Runtime.InteropServices;
namespace Crash
{
class Program
{
static void Main(string[] args)
{
GCHandle.FromIntPtr(new IntPtr(32323));
}
}
}
答案 4 :(得分:1)
我看到Java程序通过加载一个不存在的类并忽略ClassNotFoundError
来崩溃JVM,然后继续执行,好像什么都没发生一样。也许你可以在动态加载.NET类时做类似的事情。
答案 5 :(得分:0)
您可以使用/ clr:pure编译此代码,并使用链接器强制纯选项。
然而,它看起来像运行时故障一样崩溃;
(1388.5e4):访问冲突 - 代码 c0000005(!!!第二次机会!!!) 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 * 警告:无法验证校验和 C:\ WINDOWS \装配\ NativeImages_v4.0.30319_32 \ mscorlib程序\ eb4e1e70734f6efb9c7de7ec5f452c9e \ mscorlib.ni.dll mscorlib_ni + 0x9365c5:6ae965c5 ff10
叫dword ptr [eax]
DS:002B:8d00fea5 = ????????
即使您使用/ clr:pure或/ clr:safe进行编译,并且图像自身也是如此,但由于验证程序捕获此错误(编译器错误),它只能完全信任。
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);
}
};
}
这是来自peverify的输出,它解析整个PE文件,直到运行时调用此方法才检测到此错误,因为验证程序与JIT'er一起工作并且对它的验证很懒惰。
[IL]:错误: [C:\用户\ FILES \文档\ Visual 工作室 2010 \项目\ TESTCLI \ BIN \发布\ PureSettings.dll : Settings.aUseTemplate :: HasTemplate ^&gt;] [off set 0x00000017] [找到参考 'Settings.RefType'] [预期地址 of ref]堆栈上的意外类型。 1错误验证PureSettings.dll
如果您可以在此处绕过验证程序,这将是CLR中的巨大错误,并为您提供来自无法处理的进程的代码执行。
这是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_19。
如果您在CAS或任何其他类型安全模式下运行,此代码将生成着名的“代码可能会使运行时不稳定”异常。
答案 6 :(得分:0)
我认为我找到了另一种不涉及非托管代码的方法。但是,它使用PInvoke。当我添加MethodImpl(MethodImplOptions.Unmanaged)时,它起作用了。 我在.Net Core 2.1和.Net Framework 4.7.2上进行了测试。前者在VS调试期间立即崩溃,而后者在调试器发生异常时出现异常,消息是System.TypeLoadException抛出在内部某个地方。消息和错误代码与我从@Salvatore Previti答案得到的消息和错误代码相同。 我从命令行调用了已编译的应用程序,并获取错误退出代码-532462766。 代码如下:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
[MethodImpl(MethodImplOptions.Unmanaged)]
[DllImport("user32.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern void Foo();
public static void Main(string[] args)
{
try
{
Foo();
}
catch (Exception e)
{
}
Console.ReadLine();
}
}
}
答案 7 :(得分:-1)
我知道你可以用.NET崩溃你的整个PC。但这涉及无限循环和实时进程优先级......
答案 8 :(得分:-1)
有一些c#代码虽然技术上正确但不会作为有效的.net程序运行。它有一些东西,界面重载一个空方法,但我真的不记得了。