Ответ 1
Обновленный ответ
Прежде всего, имейте в виду, что
Метод Address = Метод Виртуальный адрес + базовый адрес класса, который объявляет этого пользователя..
Если заменяемый метод является виртуальным переопределенным методом, используйте следующие.
if (methodToReplace.IsVirtual)
{
ReplaceVirtualInner(methodToReplace, methodToInject);
} else {
ReplaceInner(methodToReplace, methodToInject);
}
Протестировано с помощью и целевой платформы x86 и x64: работает!!!.
static void ReplaceVirtualInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
unsafe
{
UInt64* methodDesc = (UInt64*)(methodToReplace.MethodHandle.Value.ToPointer());
int index = (int)(((*methodDesc) >> 32) & 0xFF);
if (IntPtr.Size == 4)
{
uint* classStart = (uint*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 10;
classStart = (uint*)*classStart;
uint* tar = classStart + index;
uint* inj = (uint*)methodToInject.MethodHandle.Value.ToPointer() + 2;
//int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
*tar = *inj;
}
else
{
ulong* classStart = (ulong*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 8;
classStart = (ulong*)*classStart;
ulong* tar = classStart + index;
ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
//ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
*tar = *inj;
}
}
}
Оригинальный ответ
Вам нужно запустить (из cmd
sell) exe
скомпилированный в Release
режиме, а не в Debug
.
Я пробовал, и я подтверждаю, что он не генерирует исключения в этом случае.
C:\dev\Calc>C:\dev\Calc\bin\Release\Calc.exe
Target.targetMethod1()
Target.targetMethod2()
Not injected 2
Target.targetMethod3(Test)
Target.targetMethod4()
Version x64 Release
Version x64 Release
Version x64 Release
Version x64 Release
Injection.injectionMethod1
Injection.injectionMethod2
Injected 2
Injection.injectionMethod3 Test
как вы можете видеть, приведенное выше выполняется без исключения
C:\dev\Calc>C:\dev\Calc\bin\Debug\Calc.exe
Target.targetMethod1()
Target.targetMethod2()
Not injected 2
Target.targetMethod3(Test)
Target.targetMethod4()
Version x64 Debug
Version x64 Debug
Version x64 Debug
Version x64 Debug
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at InjectionTest.Target.targetMethod1() in C:\dev\Calc\Program.cs:line 38
at InjectionTest.Target.test() in C:\dev\Calc\Program.cs:line 31
at InjectionTest.Program.Main(String[] args) in C:\dev\Calc\Program.cs:line 21
и причина объясняется в этом комментарии
в компиляторе отладки добавляется код среднего человека и вводится ваш метод вам нужно пересчитать адрес вашего метода
После редактирования вопроса
Рассматривая пересмотренный вопрос, я подтверждаю, что существует проблема, если метод Base
объявлен как virtual
. Я пытаюсь найти обходной путь.
обходной путь 1
Моя первая идея заключалась в замене new
keyworkd вместо override
(поэтому, когда метод Base не является virtual
).
Это делает его работать, поэтому я предполагаю, что (когда у нас есть виртуальный метод) инъекция может произойти на уровне базового класса, возможно... и различное поведение должно иметь отношение к использованию callvirt
vs call