Информация об изменениях

Сообщение Re[39]: 32/64/AnyCPU - что за @$^%$? от 03.11.2016 10:48

Изменено 03.11.2016 10:59 Serginio1

Здравствуйте, tranzit, Вы писали:

Так для общего развития
https://msdn.microsoft.com/ru-ru/library/system.runtimemethodhandle.getfunctionpointer(v=vs.110).aspx
Метод RuntimeMethodHandle.GetFunctionPointer () Получает указатель на метод, представленный этим экземпляром

https://habrahabr.ru/post/307088/

Перехват функций .NET/CLR

1. Способ вызова методов в CLR

В CLR каждая функция (метод) представляет собой набор IL-команд и вся информация о ней хранится в метаданных модуля. При загрузке модуля для каждого его класса система CLR создает таблицу MethodTable, содержащую информацию о методах класса. Каждый метод класса описывается структурой MethodDesc, одно из полей которой содержит адрес скомпилированного метода в памяти (при выполненной JIT-компиляции метода), а другое содержит индекс в таблице MethodTable, по которому указан адрес переходника (thunk), содержимое которого изменяется в процессе выполнения в зависимости от того, скомпилирован метод или нет.



Первоначально (до выполнения JIT-компиляции) в качестве переходника выступает один из четырех т.н. precode переходников CLR: StubPrecode, FixupPrecode, RemotingPrecode или NDirectImportPrecode. Поскольку последний переходник используется только для вызова API-функций Windows, которые можно перехватить и напрямую, то его мы рассматривать не будем.

Основной задачей каждого из precode-переходников является передача адреса структуры MethodDesc,
определяющей используемый метод, внутренней функции ThePreStub (ThePreStubAMD64 для платформы x64, на рисунке отмечена как Stub), которая выполняет следующие задачи:
1.JIT-компиляция метода, идентифицируемого структурой MethodDesc;
2.установка указателя в структуре MethodDesc на сгенерированный native-код;
3.перезапись переходника таким образом, чтобы он осуществлял безусловный переход (jmp) на сгенерированный native-код;

4.выполнение сгенерированного native-кода.

Таким образом, в результате первоначального вызова целевого метода не только сгенерируется и выполнится код метода, но и изменится содержимое переходника, что приведет к прямому вызову сгенерированного native-кода при последующих вызовах метода.

Любой метод .NET, вызываемый из среды CLR, проходит через адрес в таблице MethodTable методов класса. Однако среда CLR предоставляет возможность вызова метода из неуправляемой среды С/С++. Для этого служат следующие функции: GetFunctionPointer класса RuntimeMethodHandle и GetFunctionPointerForDelegate класса Marshal. Адреса, возвращаемые указанными функциями, также являются адресами переходников, среди которых могут быть уже упомянутые StubPrecode, FixupPrecode и RemotingPrecode. В результате первоначального вызова метода происходит его компиляция и выполнение, при последующем вызове – прямой переход на сгенерированный код. При этом важным для нас является то, что для некомпилированного метода при вызове его как через таблицу методов, так и через возвращаемые упомянутыми функциями указатели, происходит вызов внутренней функции ThePreStub.

Re[39]: 32/64/AnyCPU - что за @$^%$?
Здравствуйте, tranzit, Вы писали:

Так для общего развития
https://msdn.microsoft.com/ru-ru/library/system.runtimemethodhandle.getfunctionpointer(v=vs.110).aspx
Метод RuntimeMethodHandle.GetFunctionPointer () Получает указатель на метод, представленный этим экземпляром

https://habrahabr.ru/post/307088/

Перехват функций .NET/CLR

1. Способ вызова методов в CLR

В CLR каждая функция (метод) представляет собой набор IL-команд и вся информация о ней хранится в метаданных модуля. При загрузке модуля для каждого его класса система CLR создает таблицу MethodTable, содержащую информацию о методах класса. Каждый метод класса описывается структурой MethodDesc, одно из полей которой содержит адрес скомпилированного метода в памяти (при выполненной JIT-компиляции метода), а другое содержит индекс в таблице MethodTable, по которому указан адрес переходника (thunk), содержимое которого изменяется в процессе выполнения в зависимости от того, скомпилирован метод или нет.



Первоначально (до выполнения JIT-компиляции) в качестве переходника выступает один из четырех т.н. precode переходников CLR: StubPrecode, FixupPrecode, RemotingPrecode или NDirectImportPrecode. Поскольку последний переходник используется только для вызова API-функций Windows, которые можно перехватить и напрямую, то его мы рассматривать не будем.

Основной задачей каждого из precode-переходников является передача адреса структуры MethodDesc,
определяющей используемый метод, внутренней функции ThePreStub (ThePreStubAMD64 для платформы x64, на рисунке отмечена как Stub), которая выполняет следующие задачи:
1.JIT-компиляция метода, идентифицируемого структурой MethodDesc;
2.установка указателя в структуре MethodDesc на сгенерированный native-код;
3.перезапись переходника таким образом, чтобы он осуществлял безусловный переход (jmp) на сгенерированный native-код;

4.выполнение сгенерированного native-кода.

Таким образом, в результате первоначального вызова целевого метода не только сгенерируется и выполнится код метода, но и изменится содержимое переходника, что приведет к прямому вызову сгенерированного native-кода при последующих вызовах метода.

Любой метод .NET, вызываемый из среды CLR, проходит через адрес в таблице MethodTable методов класса. Однако среда CLR предоставляет возможность вызова метода из неуправляемой среды С/С++. Для этого служат следующие функции: GetFunctionPointer класса RuntimeMethodHandle и GetFunctionPointerForDelegate класса Marshal. Адреса, возвращаемые указанными функциями, также являются адресами переходников, среди которых могут быть уже упомянутые StubPrecode, FixupPrecode и RemotingPrecode. В результате первоначального вызова метода происходит его компиляция и выполнение, при последующем вызове – прямой переход на сгенерированный код. При этом важным для нас является то, что для некомпилированного метода при вызове его как через таблицу методов, так и через возвращаемые упомянутыми функциями указатели, происходит вызов внутренней функции ThePreStub.



https://ludeon.com/forums/index.php?topic=13813.0

 unsafe public sealed override void ResolveReferences()
        {
            Log.Warning("x86 override test 1");
            Log.Warning(TEST().ToString());

            byte* mpx_1 = (byte*)typeof(Redefine).GetMethod ("TEST", BindingFlags.Static | BindingFlags.Public).MethodHandle.GetFunctionPointer ().ToPointer();
            
            *(mpx_1 + 0) = 0xB8; //mov eax,0x0
            *(mpx_1 + 1) = 7;
            *(mpx_1 + 2) = 2;
            *(mpx_1 + 3) = 2;
            *(mpx_1 + 4) = 1;
            *(mpx_1 + 5) = 0xC3; //ret

            Log.Warning("x86 override test 2");
            Log.Warning(TEST().ToString());


            Log.Warning("have a nice day!");

            //StageA();
        }