Как свернуть среду выполнения обычного языка .NET(CLR) в чистом виде .net
Существует аналогичный вопрос, касающийся Java VM, но я не нашел вопроса для .net(пожалуйста, закройте и отметьте как дубликат, если я что-то упустил).
Итак - возможно ли без неприятного неуправляемого взаимодействия? И с сбоем я имею в виду, что настоящий "xxx.exe перестает работать", а не исключение StackOverflow или OutOfMemoryException.
Я думаю, что это невозможно, за исключением случаев, когда вы попадаете в ошибку в самой виртуальной машине.
Ответы
Ответ 1
Ну... как бы вы определили "чистый .NET"? Я играл с CLR2/delegate/GCHandle/array, когда читал сообщение о том, как сбой JVM, и придумал что-то вроде этого:
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 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( );
}
}
}
Известно, что он работает только на 32-разрядной Windows XP с CLR2 на x86; и также известно, что он не работает с Vista и Windows 7 и т.д., где по умолчанию включен DEP + ASLR.
Самое интересное о коде выше - это то, что он явно не использовал небезопасный код (хотя GCHandle.Alloc(..., GCHandleType.Pinned) требует привилегий безопасности), но ему удается подделать массив в делегат экземпляр и вызовы в машинный код x86 в массиве. Сам код является чистым С#, если вы не считаете внедренный код 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.
Ответ 2
Орен Эйни обнаружил ошибку в инфраструктуре .net, которая вызвала "ExecutionEngineException" - в основном, сбой среды выполнения.
Вы можете прочитать об этом здесь (Microsoft Connect):
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384781
И несмотря на "закрытое" состояние ошибки - оно еще не исправлено.
Ответ 3
Я сделал это только сегодня. Я тестировал установку более крупного проекта .net. Отсутствует сборка, содержащая некоторые интерфейсы, и exe просто перестает работать. Исключение не было обнаружено во время выполнения.
Вы можете быть уверены, что в среде выполнения есть еще больше ошибок - просто считайте миллионы строк кода...
Ответ 4
Без необходимости использования небезопасного кода или делегатов (также, если я должен признать, что это очень хороший способ свернуть вашу среду CLR), вы можете использовать простые функции маршала, чтобы заставить .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);
}
}
}
}
Также это, используя всегда GCHandle, вызовет нарушение доступа к памяти, такое как ошибка.
using System;
using System.Runtime.InteropServices;
namespace Crash
{
class Program
{
static void Main(string[] args)
{
GCHandle.FromIntPtr(new IntPtr(32323));
}
}
}
Ответ 5
Я видел, как Java-программы разбивают JVM, загружая несуществующий класс и игнорируя ClassNotFoundError
, а затем продолжают выполнение, как будто ничего не произошло. Возможно, вы могли бы сделать что-то подобное при динамической загрузке .NET-класса.
Ответ 6
Вы можете скомпилировать этот код с помощью /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
call 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'ером и ленив об этом.
[IL]: Ошибка: [C:\Users\файлы\Documents\Визуальное студия 2010\Projects\testCli\Bin\Release\PureSettings.dll: Settings.aUseTemplate:: HasTemplate ^ > ] [off set 0x00000017] [found ref '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 или любым другим безопасным типом, этот код генерирует исключение известного "кода может дестабилизировать время выполнения".
Ответ 7
Я знаю, что вы можете повредить весь компьютер с помощью .NET. Но это связано с бесконечным циклом и приоритетом процесса RealTime...
Ответ 8
Существует некоторый код С#, который, хотя технически корректный, не будет работать как действительная программа .net. У него есть что-то с интерфейсом, перегружающим пустой метод, но я не могу запомнить.