如何将指针替换为从系统类继承的方法的类中的方法指针
本文关键字:指针 方法 继承 系统 替换 | 更新日期: 2023-09-27 18:03:00
已经问过这个问题了。如何替换指针覆盖(虚拟)方法在我的方法的指针?(x64和x86版本)谢谢机器学习,解决了问题。但是一个新的问题出现了。如果系统继承自类,如"system . windows . net"。form",那么更改不起作用。例子:
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
}
}
}
}
当目标类从MarshalByRefObject
派生时,则ReplaceInner
(用于普通方法)停止工作,但ReplaceVirtualInner
(用于overridden
方法)是可以的。
MarshalByRefObject是通信对象的基类通过交换消息来跨越应用程序域边界代理。不从MarshalByRefObject继承的对象是按值隐式封送。当远程应用程序引用按值对象封送,传递对象的副本应用程序域边界。
可以通过将要替换的方法标记为virtual
来部分修复。
但是当目标类从Content
派生时,ReplaceVirtualInner
(用于overridden
方法)也停止工作。
不幸的是,Windows.Forms
是从它们两个派生的,所以我看不到一个简单的解决方案。
不同的方法和选择
你可能想考虑一种不同的方法:一个用PostSharp和面向方面编程跟踪的基本例子,一篇CodeProject文章和关于跟踪的文档。
此外,另一种选择(不知道您是否可能)是使用WPF的UserControl
而不是Forms,在这种情况下,normal方法替换将工作良好(在您导入所需的程序集并制作主[STAThread]
之后)
逆向工程的最终解
好吧,如果你真的想让它工作不惜任何代价,让我们继续反转目标。
使用CFF资源管理器打开编译后的.exe。
找到。net目录> MetaData Streams
下的表并取消Method Tables
组。您将发现两个具有相同名称和不同RVA
的方法对应于两个类(TypeDef
)。您只需使用注入方法RVA
覆盖目标RVA
,并使用新名称保存反转的exe。