2014-09-11 3 views
2

Есть ли способ изменить адрес OpCodes.Ret перескакивает? Может ли метод в IL изменить стек вызовов, используемый C#?Где находится адрес OpCodes.Ret использует сохраненный? Можно ли это изменить?

Насколько я знаю на C++, вы можете просто получить доступ к значениям в стеке и изменить адреса возврата и так далее. В IL все, что я пытался получить доступ к стеку за пределами текущего метода, не удалось исключить «InvalidProgramException».

мой пример кода:

public static void Test2() 
    { 
     var ma = typeof(Program).GetMethod("Test2"); 
     DynamicMethod meth = new DynamicMethod("", null, null, ma.Module, true); 
     ILGenerator il = meth.GetILGenerator(); 



     il.EmitWriteLine("Start to run the IL method"); 

     var t = il.DeclareLocal(typeof(int)); 



     //take the top of the stack (from the caller method) and put it into the variable t 
     //this seems to be not possible? 
     il.Emit(OpCodes.Stloc, t); 

     //print the value from the stack 
     il.EmitWriteLine(t); 

     //load the value back from the field onto the stack to allow everything to preceed normally 
     il.Emit(OpCodes.Ldloc, t); 

     //return 
     il.Emit(OpCodes.Ret); 

     Action a = (Action)meth.CreateDelegate(typeof(Action)); 

     a(); 
    } 
+1

Кто скажет, что 'ret' перескакивает на адрес? Спецификация опционного кода ничего не говорит о «переходе на адрес». Ни то, ни другое не имеет спецификации C++. Если вы можете сделать это на C++, это поведение, определяемое реализацией. –

+0

Да, возможно, это зависит от компилятора. Возможно, такой вид доступа на C# невозможен. Я не уверен. Но внутри CLI должен хранить, куда идти после завершения метода в команде RET. Я ищу взломать не то, что нужно использовать в реальной среде. – Luz

+3

Стек - это структура данных, принадлежащая CLR; способ, которым он использует стек, является деталью реализации, и вы не можете смело делать какие-либо предположения о том, как он использует эту структуру данных. Например, предположим, что вы меняете адрес возврата, а затем происходит переход стека безопасности или происходит исключение? Для корректной работы CLR может потребоваться структура данных в стеке.Не меняйте его; это не твое изменение. –

ответ

2

Ну, OpCodes.Ret инструкция IL на самом деле не делать каких-либо прыжков. Вместо этого код IL скомпилирован в собственный машинный код с помощью CLR и , который выполняется. Какой машинный код генерируется для некоторого кода IL, зависит от вашей архитектуры (x86, ARM, ...), и это деталь реализации CLR.

Имеет смысл предположить, что на x86 инструкция IL ret скомпилирована в инструкцию x86 ret, но это может быть не так, потому что весь метод может быть встроен.

Для этого вы можете попробовать изменить стек с помощью указателей, так как здесь хранится адрес x86 ret, но это очень опасно (вы можете легко изменить неправильную память) и чрезвычайно хрупким (так как это опираясь на макет стека, который может легко измениться).

В качестве примера рассмотрим следующий код:

using System; 

static class Program 
{ 
    static void Main() 
    { 
     A(); 
    } 

    static void A() 
    { 
     Console.WriteLine("A before"); 
     B(); 
     Console.WriteLine("A after"); 
    } 

    static void B() 
    { 
     Console.WriteLine("B before"); 
     C(); 
     Console.WriteLine("B after"); 
    } 

    static unsafe void C() 
    { 
     int local; 

     int* localPointer = &local; 

     localPointer[2] = localPointer[4]; 
    } 
} 

Если я запускаю этот на моем компьютере, в режиме отладки, используя Ctrl + F5, он печатает:

A before 
B before 
A after 
A after 

Это показывает, что я успешно изменил стек вызовов с MainABC до MainAAC.

Но это перестает работать при запуске в режиме выпуска, при запуске с помощью F5 или когда я добавить локальную переменную B или C, показывая, насколько хрупким это.

Итак, это можно сделать, но вы никогда не должны это делать (кроме образовательных целей).

+0

Если честно, я не думаю, что здесь есть какой-либо образовательный эффект. Если кто-то хочет знать, как работают вызовы/вызовы, тогда управляемый код - это очень плохой носитель для использования. –

+0

отличный ответ :) Итак, IL не разрешает манипуляции на этом уровне, но после компиляции до машинного кода он ведет себя аналогично C/C++. Я думаю, что это образовательный :) Для правильного программирования это может быть плохой пример, но с точки зрения безопасности это очень интересно. – Luz

 Смежные вопросы

  • Нет связанных вопросов^_^