已经问过这个问题。 How to replace the pointer to the overridden (virtual) method in the pointer of my method? (Release x64 and x86) 谢谢@Machine Learning,解决了这个问题。但是出现了一个新问题。如果系统继承自该类,例如“Systems.Windows.Forms”,则更改不起作用。 例如:
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace ReplaceHandles
{
public class Target1 : UserControl
{
public void test()
{
Console.WriteLine("Target1.test()");
}
}
public class Target2
{
public void test()
{
Console.WriteLine("Target2.test()");
}
}
class Program
{
static void Main(string[] args)
{
Injection.Replace();
var target = new Target1();
target.test();
Console.Read();
}
}
}
替换指针的类
public class Injection
{
public static void Replace()
{
var methodToReplace = typeof(Target1).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
var methodToInject = typeof(Target2).GetMethod("test", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);
if (methodToReplace.IsVirtual) ReplaceVirtualInner(methodToReplace, methodToInject);
else ReplaceInner(methodToReplace, methodToInject);
}
更换虚拟方法
static void ReplaceVirtualInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
unsafe
{
var methodDesc = (UInt64*)(methodToReplace.MethodHandle.Value.ToPointer());
var index = (int)(((*methodDesc) >> 32) & 0xFF);
if (IntPtr.Size == 4)
{
if (methodToReplace.DeclaringType != null)
{
var classStart = (uint*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 10;
classStart = (uint*)*classStart;
var tar = classStart + index;
var inj = (uint*)methodToInject.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
else
{
if (methodToReplace.DeclaringType != null)
{
var classStart = (ulong*)methodToReplace.DeclaringType.TypeHandle.Value.ToPointer();
classStart += 8;
classStart = (ulong*)*classStart;
var tar = classStart + index;
var inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
}
}
并替换非虚拟方法
static void ReplaceInner(MethodInfo methodToReplace, MethodInfo methodToInject)
{
unsafe
{
if (IntPtr.Size == 4)
{
var inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
var tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
else
{
ulong* inj = (ulong*)methodToInject.MethodHandle.Value.ToPointer() + 1;
ulong* tar = (ulong*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
var injInst = (byte*)*inj;
var tarInst = (byte*)*tar;
var injSrc = (int*)(injInst + 1);
var tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
}
}
答案 0 :(得分:2)
当目标类派生自MarshalByRefObject
时,ReplaceInner
(对于普通方法)停止工作,但ReplaceVirtualInner
(对于overridden
方法)是可以的。
MarshalByRefObject是通信对象的基类 通过使用a交换消息跨应用程序域边界 代理。不从MarshalByRefObject继承的对象是 隐含地按价值编组。当远程应用程序引用a时 按值对象编组,传递对象的副本 应用领域边界。
通过将virtual
标记为要替换的方法,可以部分修复此问题。
但是,当目标类派生自Content
时,ReplaceVirtualInner
(对于overridden
方法)也会停止工作。
不幸的是Windows.Forms
来自两者,所以我看不到简单的解决方法。
您可能需要考虑一种不同的方法:tracing with PostSharp and Aspect-Oriented Programming的基本示例,CodeProject article和关于跟踪的doc。
此外,另一种选择(不知道你是否可能)是使用 WPF的UserControl
而不是表格,在这种情况下正常方法替换将正常工作(在您导入所需的程序集并创建主[STAThread]
后)
好的,如果你真的想让它免费工作,让我们继续逆转目标。
使用CFF Explorer打开已编译的.exe。
找到.Net Directory > MetaData Streams
下的表格并取消Method Tables
的组合。
您将找到具有相同名称的2个方法,并且对应于2个类(RVA
)的不同TypeDef
。
您只需使用注入方法RVA
对目标RVA
进行ovverride,并使用新名称保存反向exe。